handler_vars.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-FileCopyrightText: Adam Evyčędo
  2. //
  3. // SPDX-License-Identifier: AGPL-3.0-or-later
  4. package server
  5. import (
  6. "fmt"
  7. "apiote.xyz/p/szczanieckiej/config"
  8. "apiote.xyz/p/szczanieckiej/traffic"
  9. "net/http"
  10. "net/url"
  11. "strings"
  12. "git.sr.ht/~sircmpwn/go-bare"
  13. "golang.org/x/text/language"
  14. )
  15. type AbstractHandlerVars interface {
  16. getWriter() http.ResponseWriter
  17. getRequest() *http.Request
  18. getTraffic() *traffic.Traffic
  19. getConfig() config.Config
  20. getAccept() map[uint]struct{}
  21. getFeedName() string
  22. getPath() []string
  23. setPath([]string)
  24. getVersionCode() traffic.Validity
  25. setVersionCode(traffic.Validity)
  26. getContext() traffic.Context
  27. setContext(traffic.Context)
  28. getAcceptLanguage() string
  29. setAcceptLanguage(string)
  30. getPreferredLanguages() []language.Tag
  31. setPreferredLanguages([]language.Tag)
  32. getResponse() any
  33. setResponse(any)
  34. getResponseBytes() []byte
  35. setResponseBytes([]byte)
  36. }
  37. type HandlerVars struct {
  38. w http.ResponseWriter
  39. r *http.Request
  40. t *traffic.Traffic
  41. c config.Config
  42. a map[uint]struct{}
  43. f string
  44. path []string
  45. versionCode traffic.Validity
  46. context traffic.Context
  47. acceptLanguage string
  48. preferredLanguages []language.Tag
  49. response any
  50. responseBytes []byte
  51. }
  52. func (v HandlerVars) getWriter() http.ResponseWriter {
  53. return v.w
  54. }
  55. func (v HandlerVars) getRequest() *http.Request {
  56. return v.r
  57. }
  58. func (v HandlerVars) getTraffic() *traffic.Traffic {
  59. return v.t
  60. }
  61. func (v HandlerVars) getConfig() config.Config {
  62. return v.c
  63. }
  64. func (v HandlerVars) getAccept() map[uint]struct{} {
  65. return v.a
  66. }
  67. func (v HandlerVars) getFeedName() string {
  68. return v.f
  69. }
  70. func (v HandlerVars) getPath() []string {
  71. return v.path
  72. }
  73. func (v *HandlerVars) setPath(p []string) {
  74. v.path = p
  75. }
  76. func (v HandlerVars) getVersionCode() traffic.Validity {
  77. return v.versionCode
  78. }
  79. func (v *HandlerVars) setVersionCode(c traffic.Validity) {
  80. v.versionCode = c
  81. }
  82. func (v HandlerVars) getContext() traffic.Context {
  83. return v.context
  84. }
  85. func (v *HandlerVars) setContext(c traffic.Context) {
  86. v.context = c
  87. }
  88. func (v HandlerVars) getAcceptLanguage() string {
  89. return v.acceptLanguage
  90. }
  91. func (v *HandlerVars) setAcceptLanguage(l string) {
  92. v.acceptLanguage = l
  93. }
  94. func (v HandlerVars) getPreferredLanguages() []language.Tag {
  95. return v.preferredLanguages
  96. }
  97. func (v *HandlerVars) setPreferredLanguages(t []language.Tag) {
  98. v.preferredLanguages = t
  99. }
  100. func (v HandlerVars) getResponse() any {
  101. return v.response
  102. }
  103. func (v *HandlerVars) setResponse(r any) {
  104. v.response = r
  105. }
  106. func (v HandlerVars) getResponseBytes() []byte {
  107. return v.responseBytes
  108. }
  109. func (v *HandlerVars) setResponseBytes(b []byte) {
  110. v.responseBytes = b
  111. }
  112. func splitPath(v AbstractHandlerVars) (AbstractHandlerVars, error) {
  113. escapedPath := strings.Split(v.getRequest().URL.EscapedPath()[1:], "/")
  114. path := make([]string, len(escapedPath))
  115. var err error
  116. for i, segment := range escapedPath {
  117. path[i], err = url.PathUnescape(segment)
  118. if err != nil {
  119. return v, fmt.Errorf("while unescaping path segment ‘%s’: %w", segment, err)
  120. }
  121. }
  122. v.setPath(path)
  123. return v, nil
  124. }
  125. func prepareForm(v AbstractHandlerVars) {
  126. v.getRequest().ParseForm()
  127. }
  128. func getVersionCode(v AbstractHandlerVars) (AbstractHandlerVars, error) {
  129. dateString := v.getRequest().Form.Get("date")
  130. versionCode, _, err := parseDate(dateString, v.getFeedName(), v.getTraffic())
  131. v.setVersionCode(versionCode)
  132. return v, err
  133. }
  134. func createContext(v AbstractHandlerVars) AbstractHandlerVars {
  135. v.setContext(
  136. traffic.Context{
  137. DataHome: v.getConfig().FeedsPath,
  138. FeedID: v.getFeedName(),
  139. Version: v.getVersionCode(),
  140. },
  141. )
  142. return v
  143. }
  144. func getAcceptLanguage(v AbstractHandlerVars) AbstractHandlerVars {
  145. v.setAcceptLanguage(v.getRequest().Header.Get("Accept-Language"))
  146. if v.getAcceptLanguage() == "" {
  147. v.setAcceptLanguage("und")
  148. }
  149. return v
  150. }
  151. func parseAcceptLanguage(v AbstractHandlerVars) (AbstractHandlerVars, error) {
  152. preferredLanguages, _, err := language.ParseAcceptLanguage(v.getAcceptLanguage())
  153. if err != nil {
  154. return v, ServerError{
  155. code: http.StatusBadRequest,
  156. field: "Accept-Language",
  157. value: v.getAcceptLanguage(),
  158. err: err,
  159. }
  160. }
  161. v.setPreferredLanguages(preferredLanguages)
  162. return v, nil
  163. }
  164. func marshalResponse(v AbstractHandlerVars) (AbstractHandlerVars, error) {
  165. r := v.getResponse()
  166. bytes, err := bare.Marshal(&r)
  167. v.setResponseBytes(bytes)
  168. return v, err
  169. }
  170. func writeResponse(v AbstractHandlerVars) error {
  171. _, err := v.getWriter().Write(v.getResponseBytes())
  172. return err
  173. }