readrow.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Package p contains an HTTP Cloud Function.
  2. package p
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "html"
  7. "io"
  8. "log"
  9. "net/http"
  10. "strings"
  11. )
  12. // fetch a single row by the row key
  13. func ReadRow(w http.ResponseWriter, r *http.Request) {
  14. // Set CORS headers for the preflight request
  15. if r.Method == http.MethodOptions {
  16. w.Header().Set("Access-Control-Allow-Origin", "*")
  17. w.Header().Set("Access-Control-Allow-Methods", "POST")
  18. w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
  19. w.Header().Set("Access-Control-Max-Age", "3600")
  20. w.WriteHeader(http.StatusNoContent)
  21. return
  22. }
  23. // Set CORS headers for the main request.
  24. w.Header().Set("Access-Control-Allow-Origin", "*")
  25. var emitterChain, emitterAddress, sequence, rowKey string
  26. // allow GET requests with querystring params, or POST requests with json body.
  27. switch r.Method {
  28. case http.MethodGet:
  29. queryParams := r.URL.Query()
  30. emitterChain = queryParams.Get("emitterChain")
  31. emitterAddress = queryParams.Get("emitterAddress")
  32. sequence = queryParams.Get("sequence")
  33. readyCheck := queryParams.Get("readyCheck")
  34. if readyCheck != "" {
  35. // for running in devnet
  36. w.WriteHeader(http.StatusOK)
  37. fmt.Fprint(w, html.EscapeString("ready"))
  38. return
  39. }
  40. // check for empty values
  41. if emitterChain == "" || emitterAddress == "" || sequence == "" {
  42. fmt.Fprint(w, "query params ['emitterChain', 'emitterAddress', 'sequence'] cannot be empty")
  43. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  44. return
  45. }
  46. case http.MethodPost:
  47. // declare request body properties
  48. var d struct {
  49. EmitterChain string `json:"emitterChain"`
  50. EmitterAddress string `json:"emitterAddress"`
  51. Sequence string `json:"sequence"`
  52. }
  53. // deserialize request body
  54. if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
  55. switch err {
  56. case io.EOF:
  57. fmt.Fprint(w, "request body required")
  58. return
  59. default:
  60. log.Printf("json.NewDecoder: %v", err)
  61. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  62. return
  63. }
  64. }
  65. // check for empty values
  66. if d.EmitterChain == "" || d.EmitterAddress == "" || d.Sequence == "" {
  67. fmt.Fprint(w, "body values ['emitterChain', 'emitterAddress', 'sequence'] cannot be empty")
  68. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  69. return
  70. }
  71. emitterChain = d.EmitterChain
  72. emitterAddress = d.EmitterAddress
  73. sequence = d.Sequence
  74. default:
  75. http.Error(w, "405 - Method Not Allowed", http.StatusMethodNotAllowed)
  76. log.Println("Method Not Allowed")
  77. return
  78. }
  79. // pad sequence to 16 characters
  80. if len(sequence) <= 15 {
  81. sequence = fmt.Sprintf("%016s", sequence)
  82. }
  83. // convert chain name to chainID
  84. if len(emitterChain) > 1 {
  85. chainNameMap := map[string]string{
  86. "solana": "1",
  87. "ethereum": "2",
  88. "terra": "3",
  89. "bsc": "4",
  90. "polygon": "5",
  91. }
  92. lowercaseChain := strings.ToLower(emitterChain)
  93. if _, ok := chainNameMap[lowercaseChain]; ok {
  94. emitterChain = chainNameMap[lowercaseChain]
  95. }
  96. }
  97. rowKey = emitterChain + ":" + emitterAddress + ":" + sequence
  98. row, err := tbl.ReadRow(r.Context(), rowKey)
  99. if err != nil {
  100. http.Error(w, "Error reading rows", http.StatusInternalServerError)
  101. log.Printf("tbl.ReadRows(): %v", err)
  102. return
  103. }
  104. if row == nil {
  105. http.NotFound(w, r)
  106. log.Printf("did not find row for key %v", rowKey)
  107. return
  108. }
  109. details := makeDetails(row)
  110. jsonBytes, err := json.Marshal(details)
  111. if err != nil {
  112. w.WriteHeader(http.StatusInternalServerError)
  113. w.Write([]byte(err.Error()))
  114. log.Println(err.Error())
  115. return
  116. }
  117. w.WriteHeader(http.StatusOK)
  118. w.Write(jsonBytes)
  119. }