diff options
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 228 |
1 files changed, 52 insertions, 176 deletions
@@ -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) } |
