add switch tracking support
This commit is contained in:
parent
9f0f1dbbc5
commit
9add4289cb
|
@ -11,9 +11,11 @@ import (
|
|||
|
||||
"github.com/facebookarchive/flagenv"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
r "gopkg.in/rethinkdb/rethinkdb-go.v6"
|
||||
"within.website/ln"
|
||||
"within.website/ln/ex"
|
||||
"within.website/mi/rethink"
|
||||
"within.website/mi/switchcounter"
|
||||
"within.website/x/web/useragent"
|
||||
)
|
||||
|
||||
|
@ -36,6 +38,9 @@ var (
|
|||
|
||||
// meta
|
||||
noPush = flag.Bool("no-push", false, "if set, don't push content")
|
||||
|
||||
// switchcounter
|
||||
switchFile = flag.String("switch-file", "", "if set, import switches from CSV")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -89,6 +94,28 @@ func main() {
|
|||
mux: mux,
|
||||
}
|
||||
mi.RegisterRoutes()
|
||||
sc := switchcounter.New(session, mux)
|
||||
|
||||
if *switchFile != "" {
|
||||
fin, err := os.Open(*switchFile)
|
||||
if err != nil {
|
||||
ln.FatalErr(ctx, err)
|
||||
}
|
||||
|
||||
switches, err := sc.ImportCSV(fin)
|
||||
if err != nil {
|
||||
ln.FatalErr(ctx, err)
|
||||
}
|
||||
|
||||
if len(switches) == 0 {
|
||||
panic("what")
|
||||
}
|
||||
|
||||
err = r.Table("switches").Insert(switches).Exec(session)
|
||||
if err != nil {
|
||||
ln.FatalErr(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
go func(cf func()) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"flag"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
@ -75,6 +76,10 @@ func (pm PasetoMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
goto ok
|
||||
}
|
||||
|
||||
if strings.HasPrefix(r.URL.EscapedPath(), "/webhooks/") {
|
||||
goto ok
|
||||
}
|
||||
|
||||
err = pm.v2.Verify(tok, pm.pubKey, &newJsonToken, &newFooter)
|
||||
if err != nil {
|
||||
ln.Error(r.Context(), err)
|
||||
|
|
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
|||
christine.website v1.3.1
|
||||
github.com/McKael/madon v2.3.0+incompatible
|
||||
github.com/McKael/madon/v2 v2.0.0-20180929094633-c679abc985d6
|
||||
github.com/celrenheit/sandflake v0.0.0-20190410195419-50a943690bc2
|
||||
github.com/dghubble/go-twitter v0.0.0-20190719072343-39e5462e111f
|
||||
github.com/dghubble/oauth1 v0.6.0
|
||||
github.com/facebookarchive/flagenv v0.0.0-20160425205200-fcd59fca7456
|
||||
|
|
1
go.sum
1
go.sum
|
@ -26,6 +26,7 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
|||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/birkelund/boltdbcache v1.0.0/go.mod h1:WgJWF40tV+4K0Q7MxAPbWEIkgs4AVUB7EyKVds0EgfQ=
|
||||
github.com/bwmarrin/discordgo v0.20.1/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/celrenheit/sandflake v0.0.0-20190410195419-50a943690bc2 h1:/BpnZPo/sk1vPlt62dLya5KCn7PN9ZBDrpTGlQzgUZI=
|
||||
github.com/celrenheit/sandflake v0.0.0-20190410195419-50a943690bc2/go.mod h1:7L8gY0+4GYeBc9TvqVuDUq7tXuM6Sj7llnt7HkVwWlQ=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package switchcounter
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"io"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/celrenheit/sandflake"
|
||||
)
|
||||
|
||||
type Switch struct {
|
||||
ID string `json:"id"`
|
||||
Who string `json:"who"`
|
||||
StartedAt time.Time `json:"started_at"`
|
||||
EndedAt *time.Time `json:"ended_at"`
|
||||
Duration time.Duration `json:"duration"`
|
||||
}
|
||||
|
||||
// 2020-01-04 13:42:13 UTC
|
||||
const timeFormat = `2006-01-02 15:04:05 MST`
|
||||
|
||||
func (s *Switches) ImportCSV(r io.Reader) ([]Switch, error) {
|
||||
var result []Switch
|
||||
rd := csv.NewReader(r)
|
||||
rows, err := rd.ReadAll()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, row := range rows[1:] {
|
||||
log.Printf("%v", row)
|
||||
startedAtVal := row[1]
|
||||
endedAtVal := row[2]
|
||||
|
||||
startedAt, err := time.Parse(timeFormat, startedAtVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endedAt, err := time.Parse(timeFormat, endedAtVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lenSeconds, err := strconv.ParseInt(row[3], 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
g := sandflake.NewFixedTimeGenerator(startedAt)
|
||||
id := g.Next()
|
||||
sw := Switch{
|
||||
ID: id.String(),
|
||||
Who: row[0],
|
||||
StartedAt: startedAt,
|
||||
EndedAt: &endedAt,
|
||||
Duration: time.Duration(lenSeconds) * time.Second,
|
||||
}
|
||||
|
||||
result = append(result, sw)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package switchcounter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
r "gopkg.in/rethinkdb/rethinkdb-go.v6"
|
||||
)
|
||||
|
||||
type Switches struct {
|
||||
session *r.Session
|
||||
}
|
||||
|
||||
func New(session *r.Session, mux *http.ServeMux) *Switches {
|
||||
result := &Switches{
|
||||
session: session,
|
||||
}
|
||||
|
||||
mux.HandleFunc("/switches/", result.GetSwitches)
|
||||
mux.HandleFunc("/switches/current", result.Current)
|
||||
mux.HandleFunc("/switches/switch", result.RegisterSwitch)
|
||||
|
||||
return result
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
package switchcounter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/celrenheit/sandflake"
|
||||
r "gopkg.in/rethinkdb/rethinkdb-go.v6"
|
||||
"within.website/ln"
|
||||
)
|
||||
|
||||
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")).
|
||||
Limit(limit).
|
||||
Skip(page * 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
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return lastSw, currentSw, nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
err = res.One(&result)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch req.Header.Get("Accept") {
|
||||
case "text/plain":
|
||||
http.Error(rw, result.Who, http.StatusOK)
|
||||
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,
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue