| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // Package p contains an HTTP Cloud Function.
- package p
- import (
- "encoding/json"
- "fmt"
- "html"
- "io"
- "log"
- "net/http"
- "strings"
- )
- // fetch a single row by the row key
- func ReadRow(w http.ResponseWriter, r *http.Request) {
- // Set CORS headers for the preflight request
- if r.Method == http.MethodOptions {
- w.Header().Set("Access-Control-Allow-Origin", "*")
- w.Header().Set("Access-Control-Allow-Methods", "POST")
- w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
- w.Header().Set("Access-Control-Max-Age", "3600")
- w.WriteHeader(http.StatusNoContent)
- return
- }
- // Set CORS headers for the main request.
- w.Header().Set("Access-Control-Allow-Origin", "*")
- var emitterChain, emitterAddress, sequence, rowKey string
- // allow GET requests with querystring params, or POST requests with json body.
- switch r.Method {
- case http.MethodGet:
- queryParams := r.URL.Query()
- emitterChain = queryParams.Get("emitterChain")
- emitterAddress = queryParams.Get("emitterAddress")
- sequence = queryParams.Get("sequence")
- readyCheck := queryParams.Get("readyCheck")
- if readyCheck != "" {
- // for running in devnet
- w.WriteHeader(http.StatusOK)
- fmt.Fprint(w, html.EscapeString("ready"))
- return
- }
- // check for empty values
- if emitterChain == "" || emitterAddress == "" || sequence == "" {
- fmt.Fprint(w, "query params ['emitterChain', 'emitterAddress', 'sequence'] cannot be empty")
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
- case http.MethodPost:
- // declare request body properties
- var d struct {
- EmitterChain string `json:"emitterChain"`
- EmitterAddress string `json:"emitterAddress"`
- Sequence string `json:"sequence"`
- }
- // deserialize request body
- if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
- switch err {
- case io.EOF:
- fmt.Fprint(w, "request body required")
- return
- default:
- log.Printf("json.NewDecoder: %v", err)
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
- }
- // check for empty values
- if d.EmitterChain == "" || d.EmitterAddress == "" || d.Sequence == "" {
- fmt.Fprint(w, "body values ['emitterChain', 'emitterAddress', 'sequence'] cannot be empty")
- http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
- return
- }
- emitterChain = d.EmitterChain
- emitterAddress = d.EmitterAddress
- sequence = d.Sequence
- default:
- http.Error(w, "405 - Method Not Allowed", http.StatusMethodNotAllowed)
- log.Println("Method Not Allowed")
- return
- }
- // pad sequence to 16 characters
- if len(sequence) <= 15 {
- sequence = fmt.Sprintf("%016s", sequence)
- }
- // convert chain name to chainID
- if len(emitterChain) > 1 {
- chainNameMap := map[string]string{
- "solana": "1",
- "ethereum": "2",
- "terra": "3",
- "bsc": "4",
- "polygon": "5",
- }
- lowercaseChain := strings.ToLower(emitterChain)
- if _, ok := chainNameMap[lowercaseChain]; ok {
- emitterChain = chainNameMap[lowercaseChain]
- }
- }
- rowKey = emitterChain + ":" + emitterAddress + ":" + sequence
- row, err := tbl.ReadRow(r.Context(), rowKey)
- if err != nil {
- http.Error(w, "Error reading rows", http.StatusInternalServerError)
- log.Printf("tbl.ReadRows(): %v", err)
- return
- }
- if row == nil {
- http.NotFound(w, r)
- log.Printf("did not find row for key %v", rowKey)
- return
- }
- details := makeDetails(row)
- jsonBytes, err := json.Marshal(details)
- if err != nil {
- w.WriteHeader(http.StatusInternalServerError)
- w.Write([]byte(err.Error()))
- log.Println(err.Error())
- return
- }
- w.WriteHeader(http.StatusOK)
- w.Write(jsonBytes)
- }
|