diff options
| author | Paul Buetow <paul@buetow.org> | 2024-05-16 00:27:56 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2024-05-16 00:27:56 +0300 |
| commit | 4057c17487a6713adccad61da8a3a58a0863db37 (patch) | |
| tree | a9c76042095d9a7fd1ed9a6c0bbd9e31ae2f57ae /internal/server | |
| parent | 51ebb1e131818f9b23dd25dea5be841a90476d50 (diff) | |
more on merge support
Diffstat (limited to 'internal/server')
| -rw-r--r-- | internal/server/handle/handle.go | 83 | ||||
| -rw-r--r-- | internal/server/repository/repository.go | 56 |
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) +} |
