-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathticketswap.go
125 lines (101 loc) · 2.74 KB
/
ticketswap.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package main
import (
"bytes"
_ "embed"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/http/httputil"
"strconv"
)
const apiURL string = "https://api.ticketswap.com/graphql/public"
//go:embed addTicketsToCart.gql
var addTicketsToCartQuery string
var reverseProxy = httputil.ReverseProxy{
Director: func(r *http.Request) {
r.Header["X-Forwarded-For"] = nil
r.URL.Host = "api.ticketswap.com"
r.URL.Scheme = "https"
},
}
func ticketswapHandler(w http.ResponseWriter, req *http.Request) error {
op := req.Header.Get("x-apollo-operation-name")
switch op {
case "GetListing":
return prefetch(w, req)
default:
reverseProxy.ServeHTTP(w, req)
return nil
}
}
func base64ListingID(id string) string {
// If number, then base64 encode it
if _, err := strconv.Atoi(id); err == nil {
prefixed := fmt.Sprintf("Listing:%s")
return base64.StdEncoding.EncodeToString([]byte(prefixed))
}
return id
}
func prepareBody(body []byte) ([]byte, error) {
var listingBody listingRequest
if err := json.Unmarshal(body, &listingBody); err != nil {
return []byte{}, err
}
return json.Marshal(cartRequest{
OperationName: "AddTicketsToCart",
Query: addTicketsToCartQuery,
Variables: cartVariables{
ID: base64ListingID(listingBody.Variables.ID),
Hash: listingBody.Variables.Hash,
Tickets: 1,
},
})
}
func prefetch(w http.ResponseWriter, listingReq *http.Request) error {
ctx := listingReq.Context()
listingReqBody, err := io.ReadAll(listingReq.Body)
if err != nil {
return err
}
addToCartReqBody, err := prepareBody(listingReqBody)
if err != nil {
return err
}
addToCartReader := bytes.NewReader(addToCartReqBody)
addToCartReq, err := http.NewRequestWithContext(ctx, "POST", apiURL, addToCartReader)
if err != nil {
return err
}
addToCartReq.Header = listingReq.Header.Clone()
addToCartReq.Header.Set("x-apollo-operation-type", "mutation")
addToCartReq.Header.Set("x-apollo-operation-name", "AddTicketsToCart")
addToCartRes, err := http.DefaultTransport.RoundTrip(addToCartReq)
if err != nil {
return err
}
addToCartRes.Body.Close()
slog.Info("put a thing in a cart! maybe?")
listingReq.Body = io.NopCloser(bytes.NewReader(listingReqBody))
reverseProxy.ServeHTTP(w, listingReq)
return nil
}
type cartRequest struct {
OperationName string `json:"operationName"`
Query string `json:"query"`
Variables cartVariables `json:"variables"`
}
type cartVariables struct {
Tickets int `json:"amountOfTickets"`
Hash string `json:"listingHash"`
ID string `json:"listingId"`
}
type listingRequest struct {
Variables listingVariables `json:"variables"`
}
type listingVariables struct {
Hash string `json:"listingHash"`
ID string `json:"listingId"`
}