package main import ( _ "embed" "encoding/gob" "io" "log/slog" "net/http" "net/url" "os" "strings" "sync" ) //go:embed popup.html var popup string //go:embed notfound.html var notfound string //go:embed genericerror.html var genericerror string var migratedLock = sync.RWMutex{} var migrated = map[string]struct{}{} func migrate(id string) { migratedLock.Lock() migrated[id] = struct{}{} migratedLock.Unlock() slog.Info("Saving migrations", "id", id) save() } func save() { file, err := os.Create("migrated") if err != nil { slog.Warn("Could not create Migration-File", "err", err) return } defer file.Close() enc := gob.NewEncoder(file) migratedLock.RLock() defer migratedLock.RUnlock() err = enc.Encode(migrated) if err != nil { slog.Warn("Could not encode migrations", "err", err) return } } func main() { file, err := os.Open("migrated") if err != nil { slog.Warn("Could not open migration history", "err", err) save() } else { dec := gob.NewDecoder(file) dec.Decode(&migrated) } http.HandleFunc("GET /p/{id}", func(w http.ResponseWriter, r *http.Request) { id := url.PathEscape(r.PathValue("id")) migratedLock.RLock() if _, ok := migrated[id]; ok { migratedLock.RUnlock() http.Redirect(w, r, "https://notes.stuve.fau.de/stuve-etherpad-migrated-"+id, 302) return } migratedLock.RUnlock() req, err := http.Get("http://127.0.0.1:9001/p/" + id + "/export/html") if err != nil { w.WriteHeader(502) slog.Error("Could not fetch Pad as html", "err", err, "id", id) w.Write([]byte(genericerror)) return } defer req.Body.Close() if req.StatusCode == 404 { w.WriteHeader(404) slog.Error("Could not fetch Pad: 404", "id", id) w.Write([]byte(notfound)) return } body, err := io.ReadAll(req.Body) if req.StatusCode != 200 { w.WriteHeader(req.StatusCode) slog.Error("Could not fetch Pad", "id", id, "status", req.Status, "body", string(body)) w.Write([]byte(genericerror)) return } if err != nil { w.WriteHeader(502) slog.Error("Could not read entire body", "err", err, "id", id) w.Write([]byte(genericerror)) return } w.Write([]byte(strings.Replace(string(body), "", popup, 1))) }) http.HandleFunc("POST /p/{id}", func(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") req, err := http.Get("http://127.0.0.1:9001/p/" + id + "/export/markdown") if err != nil { w.WriteHeader(502) slog.Error("Could not fetch Pad as markdown", "err", err, "id", id) w.Write([]byte(genericerror)) return } if req.StatusCode == 404 { w.WriteHeader(404) slog.Error("Could not fetch Pad: 404", "id", id) w.Write([]byte(notfound)) return } if req.StatusCode != 200 { body, err := io.ReadAll(req.Body) w.WriteHeader(req.StatusCode) slog.Error("Could not fetch Pad", "id", id, "status", req.Status, "body", string(body), "err", err) w.Write([]byte(genericerror)) return } resp, err := http.Post("https://notes.stuve.fau.de/new/stuve-etherpad-migrated-"+id, "text/markdown", req.Body) if resp.StatusCode != 200 { body, err := io.ReadAll(resp.Body) w.WriteHeader(req.StatusCode) slog.Error("Could not Post Pad", "id", id, "status", req.Status, "body", string(body), "err", err) w.Write([]byte(genericerror)) return } migrate(id) http.Redirect(w, r, "https://notes.stuve.fau.de/stuve-etherpad-migrated-"+id, 302) }) http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {w.WriteHeader(204)}) err = http.ListenAndServe("[::]:8080", nil) panic(err) }