router.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package server
  2. import (
  3. api_structs "notabug.org/apiote/bimba_server/api/structs"
  4. "notabug.org/apiote/bimba_server/config"
  5. "notabug.org/apiote/bimba_server/traffic"
  6. "notabug.org/apiote/bimba_server/traffic/feeds"
  7. traffic_structs "notabug.org/apiote/bimba_server/traffic/structs"
  8. "log"
  9. "net/http"
  10. "os"
  11. "strings"
  12. "time"
  13. "git.sr.ht/~sircmpwn/go-bare"
  14. )
  15. func handleRoot(w http.ResponseWriter, r *http.Request) {
  16. // todo send enabled feeds
  17. }
  18. func handleFeed(w http.ResponseWriter, r *http.Request, feedName string) {
  19. // todo send feed
  20. }
  21. func handleStops(w http.ResponseWriter, r *http.Request, feedName string) {
  22. // todo ?q=query
  23. // todo query in nameIndex
  24. }
  25. func handleDepartures(w http.ResponseWriter, r *http.Request, feedName string, cfg config.Config, versions []feeds.Version, codeIndex traffic_structs.FeedCodeIndex, calendar traffic_structs.FeedCalendar) {
  26. r.ParseForm()
  27. code := traffic_structs.ID(r.Form.Get("code"))
  28. if code == "" {
  29. sendError(w, r, "code", "EMPTY", 400)
  30. return
  31. }
  32. date := r.Form.Get("date")
  33. // todo line := r.Form.Get("line")
  34. // todo limit := r.Form.Get("limit")
  35. limit := 12
  36. versionCode := traffic_structs.Validity("")
  37. departuresType := "full"
  38. if date == "" {
  39. feedNow := time.Now().In(cfg.EnabledFeeds[feedName].GetLocation())
  40. date = feedNow.Format("20060102")
  41. departuresType = "hybrid"
  42. }
  43. feedTime, err := time.ParseInLocation("20060102", date, cfg.EnabledFeeds[feedName].GetLocation())
  44. if err != nil {
  45. sendError(w, r, "date", date, 400)
  46. }
  47. for _, v := range versions {
  48. if !v.ValidFrom.After(feedTime) && !feedTime.After(v.ValidTill) {
  49. versionCode = traffic_structs.Validity(v.String())
  50. }
  51. }
  52. if versionCode == "" {
  53. sendError(w, r, "date", date, 404)
  54. return
  55. }
  56. ix := codeIndex[versionCode]
  57. cal := calendar[versionCode]
  58. stopCodePresent := ix[code]
  59. if !stopCodePresent.Present {
  60. sendError(w, r, "code", string(code), 404)
  61. return
  62. }
  63. departures := traffic.GetDepartures(code, cfg.FeedsPath, feedName, versionCode, ix, cal, date, departuresType)
  64. limitHere := limit
  65. if len(departures) < limit {
  66. limitHere = len(departures)
  67. }
  68. departures = departures[:limitHere]
  69. response := api_structs.SuccessDepartures {
  70. Success: true,
  71. Departures: departures,
  72. }
  73. bytes, err := bare.Marshal(&response)
  74. if err != nil {
  75. send500(w, r, "while marshaling departures")
  76. return
  77. }
  78. w.Write(bytes)
  79. }
  80. func sendError(w http.ResponseWriter, r *http.Request, id, value string, code int) {
  81. message := ""
  82. switch code {
  83. case 400:
  84. message = value + " not valid as " + id
  85. case 404:
  86. message = value + " not found as " + id
  87. }
  88. response := api_structs.ErrorResponse{
  89. Success: false,
  90. Field: id,
  91. Message: message,
  92. }
  93. b, err := bare.Marshal(&response)
  94. if err != nil {
  95. w.WriteHeader(500)
  96. return
  97. }
  98. w.WriteHeader(code)
  99. w.Write(b)
  100. }
  101. func send500(w http.ResponseWriter, r *http.Request, message string) {
  102. response := api_structs.ErrorResponse{
  103. Success: false,
  104. Message: message,
  105. }
  106. w.WriteHeader(500)
  107. b, err := bare.Marshal(&response)
  108. if err != nil {
  109. return
  110. }
  111. w.Write(b)
  112. }
  113. func Route(cfg config.Config, codeIndexes *traffic_structs.GlobalCodeIndex, calendar *traffic_structs.GlobalCalendar, versions *feeds.GlobalVersions) *http.Server {
  114. srv := &http.Server{Addr: ":51354"}
  115. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  116. if r.URL.Path[1:] == "" {
  117. handleRoot(w, r)
  118. } else {
  119. path := strings.Split(r.URL.Path[1:], "/")
  120. feedName := path[0]
  121. v := *versions
  122. if v[feedName] == nil {
  123. sendError(w, r, "feed", feedName, 404)
  124. return
  125. }
  126. if len(path) == 1 {
  127. handleFeed(w, r, feedName)
  128. } else {
  129. ix := *codeIndexes
  130. c := *calendar
  131. resource := path[1]
  132. switch resource {
  133. case "stops":
  134. handleStops(w, r, feedName)
  135. case "departures":
  136. handleDepartures(w, r, feedName, cfg, v[feedName], ix[feedName], c[feedName])
  137. default:
  138. sendError(w, r, "resource", resource, 404)
  139. }
  140. }
  141. }
  142. })
  143. go func() {
  144. if err := srv.ListenAndServe(); err != http.ErrServerClosed {
  145. log.Printf("ListenAndServe(): %v", err)
  146. os.Exit(1)
  147. }
  148. }()
  149. return srv
  150. }