package switchcounter import ( "context" "encoding/json" "fmt" "io/ioutil" "net/http" "path" "strconv" "time" "github.com/celrenheit/sandflake" r "gopkg.in/rethinkdb/rethinkdb-go.v6" "within.website/ln" ) func (s *Switches) ByID(ctx context.Context, id string) (*Switch, error) { var result Switch res, err := r.Table("switches"). Get(id). Run(s.session) if err != nil { return nil, err } err = res.One(&result) if err != nil { return nil, err } return &result, nil } func (s *Switches) Get(ctx context.Context, limit, page int) ([]Switch, error) { var result []Switch res, err := r.Table("switches"). OrderBy(r.Desc("started_at")). Skip(page * limit). Limit(limit). Run(s.session) if err != nil { return nil, err } err = res.All(&result) if err != nil { return nil, err } return result, nil } func (s *Switches) Switch(ctx context.Context, who string) (Switch, Switch, error) { var lastSw Switch var currentSw Switch ln.Log(ctx, ln.Info("getting last switch")) res, err := r.Table("switches"). OrderBy(r.Desc("started_at")). Limit(1). Run(s.session) if err != nil { return lastSw, currentSw, err } err = res.One(&lastSw) if err != nil { return lastSw, currentSw, err } f := ln.F{ "from": lastSw.Who, "to": who, } ln.Log(ctx, f, ln.Info("got last switch")) now := time.Now().UTC() lastSw.EndedAt = &now lastSw.Duration = now.Sub(lastSw.StartedAt).Round(time.Second) err = r.Table("switches"). Update(lastSw). Exec(s.session) if err != nil { return lastSw, currentSw, err } currentSw = Switch{ ID: sandflake.Next().String(), Who: who, StartedAt: now, } err = r.Table("switches"). Insert(currentSw). Exec(s.session) if err != nil { return lastSw, currentSw, err } go func(who string) { err = replicateToPluralKit(who) if err != nil { ln.Error(ctx, err, ln.Action("while switching"), ln.F{"to": who, "at": "pluralkit"}) } err = replicateToSwitchCounter(who) if err != nil { ln.Error(ctx, err, ln.Action("while switching"), ln.F{"to": who, "at": "switcounter"}) } }(who) ln.Log(ctx, f, ln.Info("switched")) return lastSw, currentSw, nil } func (s *Switches) GetID(rw http.ResponseWriter, req *http.Request) { id := path.Base(req.URL.Path) sw, err := s.ByID(req.Context(), id) if err != nil { ln.Error(req.Context(), err) http.Error(rw, "can't get data", http.StatusInternalServerError) return } json.NewEncoder(rw).Encode(sw) } func (s *Switches) Current(rw http.ResponseWriter, req *http.Request) { var result Switch res, err := r.Table("switches"). OrderBy(r.Desc("started_at")). Limit(1). Run(s.session) if err != nil { ln.Error(req.Context(), err) http.Error(rw, "can't get data", http.StatusInternalServerError) return } err = res.One(&result) if err != nil { panic(err) } switch req.Header.Get("Accept") { case "text/plain": rw.WriteHeader(http.StatusOK) fmt.Fprint(rw, result.Who) return default: json.NewEncoder(rw).Encode(result) } } func (s *Switches) GetSwitches(rw http.ResponseWriter, req *http.Request) { var ( limit = 40 page = 0 ) q := req.URL.Query() if val := q.Get("limit"); val != "" { i, err := strconv.Atoi(val) if err != nil { http.Error(rw, "limit is bad: "+err.Error(), http.StatusBadRequest) return } limit = i } if val := q.Get("page"); val != "" { i, err := strconv.Atoi(val) if err != nil { http.Error(rw, "page is bad: "+err.Error(), http.StatusBadRequest) return } page = i } switches, err := s.Get(req.Context(), limit, page) if err != nil { ln.Error(req.Context(), err) http.Error(rw, "can't get data", http.StatusInternalServerError) return } json.NewEncoder(rw).Encode(switches) } func (s *Switches) RegisterSwitch(rw http.ResponseWriter, req *http.Request) { who, err := ioutil.ReadAll(req.Body) defer req.Body.Close() if err != nil { http.Error(rw, err.Error(), http.StatusBadRequest) return } last, current, err := s.Switch(req.Context(), string(who)) if err != nil { ln.Error(req.Context(), err) http.Error(rw, err.Error(), http.StatusInternalServerError) return } json.NewEncoder(rw).Encode(struct { Last Switch `json:"last"` Current Switch `json:"current"` }{ Last: last, Current: current, }) }