aboutsummaryrefslogtreecommitdiffstats
path: root/main.go
diff options
context:
space:
mode:
authorThibaut Horel <thibaut.horel@gmail.com>2017-06-03 18:00:51 -0400
committerThibaut Horel <thibaut.horel@gmail.com>2017-06-03 18:00:51 -0400
commitf154ae1ec88146017abf3de9d14d119facb5fc4c (patch)
treecd857864dd52b088ccc8943b64fe9bbd59c04dc8 /main.go
parent3f3cb7c7cede379914eed51c57e58f66ffdd1856 (diff)
downloadlastfm-api-f154ae1ec88146017abf3de9d14d119facb5fc4c.tar.gz
Basic web app
Diffstat (limited to 'main.go')
-rw-r--r--main.go228
1 files changed, 52 insertions, 176 deletions
diff --git a/main.go b/main.go
index de5ba2a..4065dad 100644
--- a/main.go
+++ b/main.go
@@ -1,199 +1,75 @@
package main
import (
- "errors"
+ "database/sql"
+ "encoding/hex"
"fmt"
+ "html/template"
+ "log"
"net/http"
"net/http/httputil"
- "net/url"
- "strconv"
- "strings"
- "time"
-)
-
-func mainHandler(ds DataStore, w http.ResponseWriter, r *http.Request) {
- r.ParseForm()
- if _, ok := r.Form["hs"]; ok {
-
- protocol := r.FormValue("p")
- if protocol != "1.2.1" && protocol != "1.2" {
- fmt.Fprintln(w, "FAILED Protocol mismatch")
- return
- }
-
- timestamp := r.FormValue("t")
- ts, err := strconv.ParseInt(timestamp, 10, 0)
- if err != nil {
- fmt.Fprintln(w, "FAILED Invalid timestamp")
- return
- }
-
- delta := time.Now().Unix() - ts
- if delta > 30 || delta < -30 {
- fmt.Fprintln(w, "BADTIME")
- return
- }
-
- user := r.FormValue("u")
- auth := r.FormValue("a")
- password, err := ds.GetPassword(user)
- if (md5hex(password+timestamp) != auth) || err != nil {
- fmt.Fprintln(w, "BADAUTH")
- return
- }
-
- client := r.FormValue("c")
- s := NewSession(user, client, protocol)
- ds.PutSession(s)
- fmt.Fprintln(w, "OK")
- fmt.Fprintf(w, "%s\n", s.Key)
- fmt.Fprintln(w, "http://post.audioscrobbler.com:80/np")
- fmt.Fprintln(w, "http://post.audioscrobbler.com:80/scrobble")
- } else {
- fmt.Fprintf(w, "<html>This is an endpoint, see <a href=\"http://www.last.fm/api/submissions\">here</a></html>")
- }
-}
-
-func parseValues(values url.Values) map[int]url.Values {
- parts := make(map[int]url.Values)
- var field string
- for key, value := range values {
- splitted_key := strings.SplitN(key, "[", 2)
- if len(splitted_key) < 2 {
- continue
- }
- field = splitted_key[0]
- idx, err := strconv.Atoi(strings.TrimSuffix(splitted_key[1], "]"))
- if err != nil {
- continue
- } else {
- if _, ok := parts[idx]; !ok {
- parts[idx] = make(url.Values)
- }
- parts[idx][field] = value
- }
- }
- return parts
-}
-
-func parsePart1(values url.Values) (Scrobble, error) {
- var scrobble Scrobble
- scrobble.TrackName = NewCorrectable(values.Get("t"))
- scrobble.Artist = NewCorrectable(values.Get("a"))
- if time, err := strconv.Atoi(values.Get("i")); err != nil {
- return scrobble, errors.New("Could not parse timestamp")
- } else {
- scrobble.Time = time
- }
- scrobble.Album = NewCorrectable(values.Get("b"))
- scrobble.Mbid = values.Get("m")
- if tn, err := strconv.Atoi(values.Get("n")); err != nil {
- return scrobble, errors.New("Could not parse track number")
- } else {
- scrobble.TrackNumber = tn
- }
- if duration, err := strconv.Atoi(values.Get("l")); err != nil {
- return scrobble, errors.New("Could not parse duration")
- } else {
- scrobble.Duration = duration
- }
- chosen := values.Get("o")
- if chosen == "P" || chosen == "" {
- scrobble.Chosen = true
- }
- return scrobble, nil
-}
-func parsePart2(values url.Values) (Scrobble, error) {
- var scrobble Scrobble
- scrobble.TrackName = NewCorrectable(values.Get("track"))
- scrobble.Artist = NewCorrectable(values.Get("artist"))
- if time, err := strconv.Atoi(values.Get("timestamp")); err != nil {
- return scrobble, errors.New("Could not parse timestamp")
- } else {
- scrobble.Time = time
- }
- scrobble.Album = NewCorrectable(values.Get("album"))
- scrobble.Mbid = values.Get("mbid")
- if tn, ok := values["trackNumber"]; ok {
- if tn, err := strconv.Atoi(tn[0]); err != nil {
- return scrobble, errors.New("Could not parse track number")
- } else {
- scrobble.TrackNumber = tn
- }
- }
- if duration, err := strconv.Atoi(values.Get("duration")); err != nil {
- return scrobble, errors.New("Could not parse duration")
- } else {
- scrobble.Duration = duration
- }
- chosen := values.Get("chosenByUser")
- if chosen == "1" || chosen == "" {
- scrobble.Chosen = true
- }
- return scrobble, nil
-}
+ "github.com/gorilla/securecookie"
+)
-func parseScrobbles(values url.Values, session *Session) ([]Scrobble, int) {
- scrobbles := make([]Scrobble, 0, 1)
- parts := parseValues(values)
- var parsePart func(url.Values) (Scrobble, error)
- if session.Protocol == "2.0" {
- parsePart = parsePart2
- } else {
- parsePart = parsePart1
- }
- ignored := 0
- for i, c := 0, 0; i < 50 && c < len(parts); i++ {
- if part, ok := parts[i]; ok {
- c++
- if scrobble, err := parsePart(part); err != nil {
- fmt.Printf("%v\n", err)
- ignored++
- } else {
- scrobble.Session = session.Key
- scrobbles = append(scrobbles, scrobble)
- }
- }
- }
- return scrobbles, ignored
-}
+type handler func(DataStore, http.ResponseWriter, *http.Request)
-func scrobbleHandler(ds DataStore, w http.ResponseWriter, r *http.Request) {
- if session, err := ds.GetSession(r.FormValue("s")); err != nil {
- fmt.Fprintln(w, "BADSESSION")
- } else {
- scrobbles, _ := parseScrobbles(r.Form, session)
- fmt.Printf("%v\n", scrobbles)
- ds.PutScrobbles(scrobbles)
- fmt.Fprintln(w, "OK")
- }
+type App struct {
+ DataStore
+ DB *sql.DB
+ Config *Config
+ CookieHandler *securecookie.SecureCookie
+ Template *template.Template
}
-func nowPlayingHandler(ds DataStore, w http.ResponseWriter, r *http.Request) {
- if _, err := ds.GetSession(r.FormValue("s")); err != nil {
- fmt.Fprintln(w, "BADSESSION")
- } else {
- fmt.Fprintln(w, "OK")
+func New() *App {
+ app := new(App)
+ config := NewConfig()
+ app.Config = config
+ db, err := sql.Open("postgres", config.Database)
+ if err = db.Ping(); err != nil {
+ log.Fatal(err)
}
+ app.DB = db
+ app.DataStore = &SqlStore{db}
+ hashKey, err := hex.DecodeString(config.HashKey)
+ blockKey, err := hex.DecodeString(config.HashKey)
+ s := securecookie.New(hashKey, blockKey)
+ app.CookieHandler = s
+ templates := template.Must(template.ParseGlob("templates/*.tmpl"))
+ app.Template = templates
+ return app
}
-type handler func(DataStore, http.ResponseWriter, *http.Request)
-
-func wrap(ds DataStore, fn handler) http.HandlerFunc {
+func logg(fn http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
d, _ := httputil.DumpRequest(r, true)
fmt.Printf("--------------------------\n%s\n", d)
r.ParseForm()
- fn(ds, w, r)
+ fn(w, r)
}
}
func main() {
- store := NewSqlStore()
- http.HandleFunc("/", wrap(store, handler(mainHandler)))
- http.HandleFunc("/np", wrap(store, nowPlayingHandler))
- http.HandleFunc("/scrobble", wrap(store, scrobbleHandler))
- http.HandleFunc("/2.0/", wrap(store, ApiHandler))
- http.ListenAndServe(":3001", nil)
+ app := New()
+
+ go func() {
+ sm := http.NewServeMux()
+ sm.HandleFunc("/", logg(app.mainHandler))
+ sm.HandleFunc("/np", logg(app.nowPlayingHandler))
+ sm.HandleFunc("/scrobble", logg(app.scrobbleHandler))
+ //http.HandleFunc("/2.0/", logg(app.ApiHandler))
+ http.ListenAndServe(":3001", sm)
+ }()
+
+ app.TrackInfo("believe", "cher")
+
+ sm := http.NewServeMux()
+ fs := http.FileServer(http.Dir("static"))
+ sm.Handle("/static/", http.StripPrefix("/static/", fs))
+ sm.HandleFunc("/", app.root)
+ sm.HandleFunc("/callback", app.callback)
+ sm.HandleFunc("/login", app.login)
+ sm.HandleFunc("/settings", app.settings)
+ http.ListenAndServe(":8000", sm)
}