1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package handler
import (
"errors"
"fmt"
"io"
"net/http"
"regexp"
"codeberg.org/snonux/gos/internal/config/server"
"codeberg.org/snonux/gos/internal/easyhttp"
"codeberg.org/snonux/gos/internal/server/repository"
"codeberg.org/snonux/gos/internal/types"
)
type Handler struct {
conf server.ServerConfig
getIdRe *regexp.Regexp
}
func New(conf server.ServerConfig) Handler {
return Handler{
conf: conf,
getIdRe: regexp.MustCompile(`^/[0-9]{4}/[a-z0-9]{64}\.json$`),
}
}
func (h Handler) Submit(w http.ResponseWriter, r *http.Request) error {
if r.Method != "POST" {
return fmt.Errorf("expexted POST request")
}
bytes, err := io.ReadAll(r.Body)
if err != nil {
return err
}
entry, err := types.NewEntry(bytes)
if err != nil {
return err
}
return repository.Instance(h.conf.DataDir).Merge(entry)
}
func (h Handler) List(w http.ResponseWriter, r *http.Request) error {
if r.Method != "GET" {
return fmt.Errorf("expexted GET request")
}
list, err := repository.Instance(h.conf.DataDir).ListBytes()
if err != nil {
return err
}
_, err = w.Write(list)
return err
}
func (h Handler) Get(w http.ResponseWriter, r *http.Request) error {
id := r.URL.Query().Get("id")
if !h.getIdRe.MatchString(id) {
return fmt.Errorf("invalid id %s", id)
}
entry, ok := repository.Instance(h.conf.DataDir).Get(id)
if !ok {
return fmt.Errorf("no entry with id %s found", id)
}
fmt.Fprint(w, entry.String())
return nil
}
func (h Handler) Merge(w http.ResponseWriter, r *http.Request) error {
var errs []error
for _, partner := range h.conf.Partners() {
if err := h.mergeFromPartner(partner); err != nil {
errs = append(errs, err)
}
}
if len(errs) > 0 {
return errors.Join(errs...)
}
fmt.Fprint(w, "Okiedokie")
return nil
}
func (h Handler) mergeFromPartner(partner string) error {
var (
errs []error
uri = fmt.Sprintf("%s/list", partner)
repo = repository.Instance(h.conf.DataDir)
pairs []repository.EntryPair
)
if err := easyhttp.GetData(uri, h.conf.ApiKey, &pairs); err != nil {
return err
}
for _, pair := range pairs {
if repo.HasSameEntry(pair) {
continue
}
var (
entry types.Entry
uri = fmt.Sprintf("%s/get?id=%s", partner, pair.ID)
)
if err := easyhttp.GetData(uri, h.conf.ApiKey, &entry); err != nil {
errs = append(errs, err)
continue
}
// In theory, this should never happen
if pair.ID != entry.ID {
errs = append(errs, fmt.Errorf("pair ID %s does not match entry id %s", pair.ID, entry.ID))
continue
}
errs = append(errs, repo.Merge(entry))
}
return errors.Join(errs...)
}
|