summaryrefslogtreecommitdiff
path: root/internal/server
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2024-05-16 00:27:56 +0300
committerPaul Buetow <paul@buetow.org>2024-05-16 00:27:56 +0300
commit4057c17487a6713adccad61da8a3a58a0863db37 (patch)
treea9c76042095d9a7fd1ed9a6c0bbd9e31ae2f57ae /internal/server
parent51ebb1e131818f9b23dd25dea5be841a90476d50 (diff)
more on merge support
Diffstat (limited to 'internal/server')
-rw-r--r--internal/server/handle/handle.go83
-rw-r--r--internal/server/repository/repository.go56
2 files changed, 118 insertions, 21 deletions
diff --git a/internal/server/handle/handle.go b/internal/server/handle/handle.go
index 011e31c..0a0a1bb 100644
--- a/internal/server/handle/handle.go
+++ b/internal/server/handle/handle.go
@@ -1,12 +1,13 @@
package handle
import (
+ "errors"
"fmt"
"io"
- "log"
"net/http"
"os"
"regexp"
+ "strings"
"time"
"codeberg.org/snonux/gos/internal"
@@ -51,7 +52,7 @@ func List(w http.ResponseWriter, r *http.Request, dataDir string) error {
return fmt.Errorf("expexted GET request")
}
- list, err := repository.New(dataDir).List()
+ list, err := repository.Instance(dataDir).List()
if err != nil {
return err
}
@@ -61,12 +62,12 @@ func List(w http.ResponseWriter, r *http.Request, dataDir string) error {
}
func Get(w http.ResponseWriter, r *http.Request, dataDir string) error {
- path := r.URL.Query().Get("path")
- if !getIDRe.MatchString(path) {
- return fmt.Errorf("invalid path %s", path)
+ id := r.URL.Query().Get("id")
+ if !getIDRe.MatchString(id) {
+ return fmt.Errorf("invalid id %s", id)
}
- data, err := os.ReadFile(fmt.Sprintf("%s/%s", dataDir, path))
+ data, err := os.ReadFile(fmt.Sprintf("%s/%s", dataDir, id))
if err != err {
return err
}
@@ -76,11 +77,75 @@ func Get(w http.ResponseWriter, r *http.Request, dataDir string) error {
}
func Merge(w http.ResponseWriter, r *http.Request, conf server.ServerConfig) error {
+ var errs []error
+
for _, partner := range conf.Partners() {
- uri := fmt.Sprintf("%s/list", partner)
- data, err := easyhttp.Get(uri, conf.ApiKey)
- log.Println(string(data), err)
+ if err := mergeFromPartner(conf, partner); err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ err := combineErrors(errs)
+ if err != nil {
+ fmt.Fprint(w, err.Error())
+ return err
}
+ fmt.Fprint(w, "Okiedokie")
return nil
}
+
+func mergeFromPartner(conf server.ServerConfig, partner string) error {
+ var (
+ errs []error
+ uri = fmt.Sprintf("%s/list", partner)
+ repo = repository.Instance(conf.DataDir)
+ pairs []repository.EntryPair
+ )
+
+ if err := easyhttp.GetData(uri, conf.ApiKey, &pairs); err != nil {
+ return err
+ }
+
+ for _, pair := range pairs {
+ if repo.HasEntry(pair) {
+ continue
+ }
+
+ var (
+ entry types.Entry
+ uri = fmt.Sprintf("%s/get?id=%s", partner, pair.ID)
+ )
+
+ if err := easyhttp.GetData(uri, 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
+ }
+
+ repo.Merge(entry)
+ }
+
+ return combineErrors(errs)
+}
+
+func combineErrors(errs []error) error {
+ if len(errs) == 0 {
+ return nil
+ }
+
+ var sb strings.Builder
+ for i, err := range errs {
+ if i > 0 {
+ sb.WriteString("; ")
+ }
+ sb.WriteString(err.Error())
+ }
+
+ return errors.New(sb.String())
+}
diff --git a/internal/server/repository/repository.go b/internal/server/repository/repository.go
index 7eb7122..4146526 100644
--- a/internal/server/repository/repository.go
+++ b/internal/server/repository/repository.go
@@ -11,23 +11,35 @@ import (
"codeberg.org/snonux/gos/internal/types"
)
+var (
+ instance Repository
+ once sync.Once
+)
+
+// Contains an Entry ID and its checksumm, for the list and merge operations.
+type EntryPair struct {
+ ID, Checksum string
+}
+
type Repository struct {
dataDir string
entries map[string]types.Entry
mu *sync.Mutex
}
-func New(dataDir string) Repository {
- return Repository{
- dataDir: dataDir,
- entries: make(map[string]types.Entry),
- mu: &sync.Mutex{},
- }
+func Instance(dataDir string) Repository {
+ once.Do(func() {
+ instance.dataDir = dataDir
+ instance.entries = make(map[string]types.Entry)
+ instance.mu = &sync.Mutex{}
+ })
+ return instance
}
func (r Repository) store(entry types.Entry) {
r.mu.Lock()
defer r.mu.Unlock()
+
r.entries[entry.ID] = entry
}
@@ -60,17 +72,37 @@ func (r Repository) List() ([]byte, error) {
return []byte{}, err
}
- type pair struct {
- ID, Checksum string
- }
-
- var pairs []pair
+ var pairs []EntryPair
r.mu.Lock()
defer r.mu.Unlock()
for _, entry := range r.entries {
- pairs = append(pairs, pair{entry.ID, entry.Checksum()})
+ pairs = append(pairs, EntryPair{entry.ID, entry.Checksum()})
}
return json.Marshal(pairs)
}
+
+func (r Repository) HasEntry(pair EntryPair) bool {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ ent, ok := r.entries[pair.ID]
+ if !ok || ent.Checksum() != pair.Checksum {
+ return false
+ }
+ return true
+}
+
+func (r Repository) Merge(new types.Entry) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ old, ok := r.entries[new.ID]
+ if !ok {
+ r.entries[new.ID] = new
+ return
+ }
+
+ r.entries[new.ID] = old.Update(new)
+}