選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

114 行
3.1KB

  1. package main
  2. import (
  3. "biukop/sfm/loan"
  4. "database/sql"
  5. "encoding/json"
  6. "fmt"
  7. log "github.com/sirupsen/logrus"
  8. "net/http"
  9. "net/http/httputil"
  10. "strings"
  11. "time"
  12. )
  13. const apiV1Prefix = "/api/v1/"
  14. type apiV1HandlerMap struct {
  15. Method string
  16. Path string //regex
  17. Handler func(http.ResponseWriter, *http.Request, *loan.Session)
  18. }
  19. var apiV1Handler = []apiV1HandlerMap{
  20. {"POST", "login", apiV1Login},
  21. {"GET", "login", apiV1DumpRequest},
  22. }
  23. //apiV1Main version 1 main entry for all REST API
  24. //
  25. func apiV1Main(w http.ResponseWriter, r *http.Request) {
  26. logRequestDebug(httputil.DumpRequest(r, true))
  27. w.Header().Set("Content-Type", "application/json;charset=UTF-8")
  28. //try session login first, if not an empty session will be created
  29. session, e := apiV1InitSession(r)
  30. if e != nil {
  31. log.Warnf("Fail to InitSession %+v", session)
  32. apiV1Client403Error(w, r)
  33. return
  34. }
  35. session.RenewIfExpireSoon()
  36. //we have a session now, either guest or valid user
  37. //search through handler
  38. path := r.URL.Path[len(apiV1Prefix):] //strip API prefix
  39. for _, node := range apiV1Handler {
  40. if r.Method == node.Method && path == node.Path {
  41. node.Handler(w, r, &session)
  42. e = session.Write() //finish this session to DB
  43. if e != nil {
  44. log.Warnf("Failed to Save Session %+v \n reason \n%s\n", session, e.Error())
  45. }
  46. return
  47. }
  48. }
  49. //Catch for all
  50. apiV1DumpRequest(w, r, &session)
  51. }
  52. func apiV1InitSession(r *http.Request) (session loan.Session, e error) {
  53. session = loan.Session{}
  54. sid := r.Header.Get("Biukop-Session")
  55. e = session.Retrieve(r)
  56. if e == nil { //we got existing session
  57. e = session.ValidateRequest(r)
  58. if e != nil { // not successfully validated
  59. log.Warnf("failed session login %+v, %s", session, time.Now().Format(time.RFC1123))
  60. session.InitGuest(time.Now().Add(loan.DefaultSessionDuration))
  61. e = nil
  62. } //else, we have logged this user in
  63. } else if e == sql.ErrNoRows {
  64. log.Warn("DB has no corresponding session ", sid)
  65. session.InitGuest(time.Now().Add(loan.DefaultSessionDuration))
  66. e = nil //we try to init an empty one
  67. } else {
  68. log.Warnf("Retrieve Session %s encountered error %s", sid, e.Error())
  69. }
  70. session.SetRemote(r) //make sure they are using latest remote
  71. return
  72. }
  73. func apiV1ErrorCheck(e error) {
  74. if nil != e {
  75. panic(e.Error()) //TODO: detailed error check, truck all caller
  76. }
  77. }
  78. func apiV1Server500Error(w http.ResponseWriter, r *http.Request) {
  79. w.WriteHeader(500)
  80. fmt.Fprintf(w, "Server Internal Error "+time.Now().Format(time.RFC1123))
  81. //write log
  82. dump := logRequestDebug(httputil.DumpRequest(r, true))
  83. dump = strings.TrimSpace(dump)
  84. log.Warnf("Unhandled Protocol = %s path= %s", r.Method, r.URL.Path)
  85. }
  86. func apiV1Client403Error(w http.ResponseWriter, r *http.Request) {
  87. w.WriteHeader(403)
  88. type struct403 struct {
  89. Error int
  90. ErrorMsg string
  91. }
  92. e403 := struct403{Error: 403, ErrorMsg: "Not Authorized " + time.Now().Format(time.RFC1123)}
  93. msg403, _ := json.Marshal(e403)
  94. fmt.Fprintln(w, string(msg403))
  95. //write log
  96. dump := logRequestDebug(httputil.DumpRequest(r, true))
  97. dump = strings.TrimSpace(dump)
  98. log.Warnf("Not authorized http(%s) path= %s, %s", r.Method, r.URL.Path, dump)
  99. }