package main import ( "database/sql/driver" "encoding/json" "encoding/xml" "fmt" "net/http" "strings" ) type Api interface { AuthGetToken(*http.Request) ApiResponse AuthGetSession(*http.Request) ApiResponse AuthGetMobileSession(*http.Request) ApiResponse TrackScrobble(*http.Request) (ApiResponse, error) } type ApiResponse interface { } type SuspendScrobbles Scrobbles func (s Scrobbles) MarshalJSON() ([]byte, error) { return json.Marshal(&struct { Tag SuspendScrobbles `json:"scrobbles"` }{Tag: SuspendScrobbles(s)}) } func (s *Session) MarshalJSON() ([]byte, error) { return json.Marshal(s) } type Name struct { XMLName xml.Name } type Token struct { XMLName xml.Name `xml:"token" json:"-"` Val string `xml:",innerxml" json:"token"` } type LFMResponse struct { XMLName xml.Name `xml:"lfm" json:"-"` Status string `xml:"status,attr" json:"-"` Response ApiResponse } type Attrs struct { Accepted int `xml:"accepted,attr" json:"accepted"` Ignored int `xml:"ignored,attr" json:"ignored"` } type Scrobbles struct { XMLName xml.Name `xml:"scrobbles" json:"-"` Scrobbles []Scrobble `xml:"scrobble" json:"scrobble"` Attrs `json:"@attr"` } type Correctable struct { Name string `xml:",chardata" json:"#text"` Corrected int `xml:"corrected,attr" json:"corrected"` } func (field Correctable) Value() (driver.Value, error) { return field.Name, nil } func NewCorrectable(name string) Correctable { return Correctable{ Name: name, } } func (field Correctable) String() string { return field.Name } func (n Name) getName() string { return n.XMLName.Local } func (store *SqlStore) AuthGetToken(r *http.Request) ApiResponse { token := Token{Val: randomToken(16)} return token } func (store *SqlStore) AuthGetMobileSession(r *http.Request) ApiResponse { return struct{}{} } func (store *SqlStore) AuthGetSession(r *http.Request) ApiResponse { var response struct { Session *Session `json:"session"` } session := &Session{ User: "thibauthorel", Client: r.FormValue("api_key"), Protocol: "2.0", Key: randomToken(16), } store.PutSession(session) response.Session = session return response } func (store *SqlStore) TrackScrobble(r *http.Request) (ApiResponse, error) { if session, err := store.GetSession(r.FormValue("sk")); err != nil { fmt.Printf("%v\n", err) return struct{}{}, err } else { scrobbles, ignored := parseScrobbles(r.Form, session) store.PutScrobbles(scrobbles) return Scrobbles{Scrobbles: scrobbles, Attrs: Attrs{len(scrobbles), ignored}}, nil } } func (app *App) ApiHandler(w http.ResponseWriter, r *http.Request) { method := r.FormValue("method") var response ApiResponse switch strings.ToLower(method) { case "auth.gettoken": response = app.AuthGetToken(r) case "auth.getsession": response = app.AuthGetSession(r) case "auth.getmobilesession": response = app.AuthGetSession(r) case "track.scrobble": if r, err := app.DataStore.TrackScrobble(r); err != nil { fmt.Printf("%v\n", err) } else { response = r } } var text []byte switch r.FormValue("format") { case "json": text, _ = json.Marshal(response) default: xmlresponse := LFMResponse{Status: "ok", Response: response} text, _ = xml.Marshal(xmlresponse) fmt.Fprint(w, xml.Header) } fmt.Printf("%s\n", text) w.Write(text) }