package main import ( "biukop/sfm/loan" "database/sql" "fmt" log "github.com/sirupsen/logrus" "net/http" "net/http/httputil" "strings" "time" ) const apiV1Prefix = "/api/v1/" type apiV1HandlerMap struct { Method string Path string //regex Handler func(http.ResponseWriter, *http.Request, *loan.Session) } var apiV1Handler = []apiV1HandlerMap{ {"POST", "login", apiV1Login}, {"GET", "login", apiV1DumpRequest}, } //apiV1Main version 1 main entry for all REST API // func apiV1Main(w http.ResponseWriter, r *http.Request) { logRequestDebug(httputil.DumpRequest(r, true)) w.Header().Set("Content-Type", "application/json;charset=UTF-8") //try session login first, if not an empty session will be created session, e := apiV1InitSession(r) if e != nil { log.Warn("Fail to InitSession %+v", session) apiV1ServerError(w, r) return } session.RenewIfExpireSoon() session.SetRemote(r) //we have a session now, either guest or valid user //search through handler path := r.URL.Path[len(apiV1Prefix):] //strip API prefix for _, node := range apiV1Handler { if r.Method == node.Method && path == node.Path { node.Handler(w, r, &session) e = session.Write() //finish this session to DB if e != nil { log.Warnf("Failed to Save Session %+v \n reason \n%s\n", session, e.Error()) } return } } //Catch for all apiV1DumpRequest(w, r, &session) } func apiV1InitSession(r *http.Request) (session loan.Session, e error) { session = loan.Session{} sid := r.Header.Get("Biukop-Session") e = session.Retrieve(r) if e == nil { //we got existing session e = session.ValidateRequest(r) if e != nil { // not successfully validated log.Warn("failed session login %+v, %s", session, time.Now().Format("RFC1132")) } //else, we have logged this user in } else if e == sql.ErrNoRows { log.Warn("DB has no corresponding session ", sid) session.InitGuest(time.Now().Add(loan.DefaultSessionDuration)) e = nil //we try to init an empty one } else { log.Warn("Retrieve Session %s encountered error %s", sid, e.Error()) } session.SetRemote(r) //make sure they are using latest remote return } func apiV1ErrorCheck(e error) { if nil != e { panic(e.Error()) //TODO: detailed error check, truck all caller } } func apiV1ServerError(w http.ResponseWriter, r *http.Request) { w.WriteHeader(500) fmt.Fprintf(w, "Server Internal Error "+time.Now().Format("RFC1132")) //write log dump := logRequestDebug(httputil.DumpRequest(r, true)) dump = strings.TrimSpace(dump) log.Warn("Unhandled Protocol = %s path= %s", r.Method, r.URL.Path) }