findvalues.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Package p contains an HTTP Cloud Function.
  2. package p
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. "cloud.google.com/go/bigtable"
  10. )
  11. // fetch rows by matching payload value
  12. func FindValues(w http.ResponseWriter, r *http.Request) {
  13. // Set CORS headers for the preflight request
  14. if r.Method == http.MethodOptions {
  15. w.Header().Set("Access-Control-Allow-Origin", "*")
  16. w.Header().Set("Access-Control-Allow-Methods", "POST")
  17. w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
  18. w.Header().Set("Access-Control-Max-Age", "3600")
  19. w.WriteHeader(http.StatusNoContent)
  20. return
  21. }
  22. // Set CORS headers for the main request.
  23. w.Header().Set("Access-Control-Allow-Origin", "*")
  24. var columnFamily, columnName, value, emitterChain, emitterAddress string
  25. // allow GET requests with querystring params, or POST requests with json body.
  26. switch r.Method {
  27. case http.MethodGet:
  28. queryParams := r.URL.Query()
  29. columnFamily = queryParams.Get("columnFamily")
  30. columnName = queryParams.Get("columnName")
  31. value = queryParams.Get("value")
  32. emitterChain = queryParams.Get("emitterChain")
  33. emitterAddress = queryParams.Get("emitterAddress")
  34. // check for empty values
  35. if columnFamily == "" || columnName == "" || value == "" {
  36. fmt.Fprint(w, "query params ['columnFamily', 'columnName', 'value'] cannot be empty")
  37. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  38. return
  39. }
  40. case http.MethodPost:
  41. // declare request body properties
  42. var d struct {
  43. ColumnFamily string `json:"columnFamily"`
  44. ColumnName string `json:"columnName"`
  45. Value string `json:"value"`
  46. EmitterChain string `json:"emitterChain"`
  47. EmitterAddress string `json:"emitterAddress"`
  48. }
  49. // deserialize request body
  50. if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
  51. switch err {
  52. case io.EOF:
  53. fmt.Fprint(w, "request body required")
  54. return
  55. default:
  56. log.Printf("json.NewDecoder: %v", err)
  57. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  58. return
  59. }
  60. }
  61. // check for empty values
  62. if d.ColumnFamily == "" || d.ColumnName == "" || d.Value == "" {
  63. fmt.Fprint(w, "body values ['columnFamily', 'columnName', 'value'] cannot be empty")
  64. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  65. return
  66. }
  67. columnFamily = d.ColumnFamily
  68. columnName = d.ColumnName
  69. value = d.Value
  70. emitterChain = d.EmitterChain
  71. emitterAddress = d.EmitterAddress
  72. default:
  73. http.Error(w, "405 - Method Not Allowed", http.StatusMethodNotAllowed)
  74. log.Println("Method Not Allowed")
  75. return
  76. }
  77. if columnFamily != "TokenTransferPayload" &&
  78. columnFamily != "AssetMetaPayload" &&
  79. columnFamily != "NFTTransferPayload" &&
  80. columnFamily != "TokenTransferDetails" {
  81. fmt.Fprint(w, "columnFamily must be one of: ['TokenTransferPayload', 'AssetMetaPayload', 'NFTTransferPayload', 'TokenTransferDetails']")
  82. http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
  83. return
  84. }
  85. prefix := ""
  86. if emitterChain != "" {
  87. prefix = emitterChain
  88. if emitterAddress != "" {
  89. prefix = emitterChain + emitterAddress
  90. }
  91. }
  92. results := []bigtable.Row{}
  93. err := tbl.ReadRows(r.Context(), bigtable.PrefixRange(prefix), func(row bigtable.Row) bool {
  94. results = append(results, row)
  95. return true
  96. }, bigtable.RowFilter(
  97. bigtable.ConditionFilter(
  98. bigtable.ChainFilters(
  99. bigtable.FamilyFilter(columnFamily),
  100. bigtable.ColumnFilter(columnName),
  101. bigtable.ValueFilter(value),
  102. ),
  103. bigtable.ChainFilters(
  104. bigtable.PassAllFilter(),
  105. bigtable.LatestNFilter(1),
  106. ),
  107. bigtable.BlockAllFilter(),
  108. )))
  109. if err != nil {
  110. http.Error(w, "Error reading rows", http.StatusInternalServerError)
  111. log.Printf("tbl.ReadRows(): %v", err)
  112. return
  113. }
  114. details := []Details{}
  115. for _, result := range results {
  116. detail := makeDetails(result)
  117. details = append(details, *detail)
  118. }
  119. jsonBytes, err := json.Marshal(details)
  120. if err != nil {
  121. w.WriteHeader(http.StatusInternalServerError)
  122. w.Write([]byte(err.Error()))
  123. log.Println(err.Error())
  124. return
  125. }
  126. w.WriteHeader(http.StatusOK)
  127. w.Write(jsonBytes)
  128. }