Skip to content

Instantly share code, notes, and snippets.

@briansorahan
Created February 1, 2017 19:07
Show Gist options
  • Save briansorahan/3207e189db345fb7111bdccb83c7270a to your computer and use it in GitHub Desktop.
Save briansorahan/3207e189db345fb7111bdccb83c7270a to your computer and use it in GitHub Desktop.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
"github.com/pkg/errors"
)
const curbsideURL = "http://challenge.shopcurbside.com"
func main() {
sessionToken, err := getSession()
if err != nil {
log.Fatal(err)
}
if err := start(sessionToken); err != nil {
log.Fatal(err)
}
}
func start(sessionToken string) error {
req, err := http.NewRequest(http.MethodGet, curbsideURL+"/start", nil)
req.Header.Add("Session", sessionToken)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
response := Response{}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return errors.Wrap(err, "decoding response in start")
}
for _, id := range response.Next {
if err := getNext(sessionToken, id); err != nil {
return err
}
}
return nil
}
func getSession() (string, error) {
resp, err := http.Get(curbsideURL + "/get-session")
if err != nil {
return "", err
}
sessionBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
if err := resp.Body.Close(); err != nil {
return "", err
}
return strings.TrimSpace(string(sessionBytes)), nil
}
func getNext(sessionToken, cur string) error {
req, err := http.NewRequest(http.MethodGet, curbsideURL+"/"+cur, nil)
req.Header.Add("Session", sessionToken)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if resp.StatusCode == http.StatusBadRequest {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if strings.HasPrefix(string(body), "Invalid session id") {
newToken, err := getSession()
if err != nil {
return err
}
if err := getNext(newToken, cur); err != nil {
return err
}
}
}
if resp.StatusCode >= 300 {
return errors.Wrapf(err, "code=%d", resp.StatusCode)
}
var (
buf = &bytes.Buffer{}
r = io.TeeReader(resp.Body, buf)
response = Response{}
)
if err := json.NewDecoder(r).Decode(&response); err != nil {
// Try decoding "next" as a single string.
rs := ResponseSingle{}
if err := json.NewDecoder(buf).Decode(&rs); err != nil {
return errors.Wrap(err, "decoding response in getNext")
}
if err := getNext(sessionToken, rs.Next); err != nil {
return err
}
}
if len(response.Secret) > 0 {
fmt.Printf("%s", response.Secret)
return nil
}
for _, id := range response.Next {
if err := getNext(sessionToken, id); err != nil {
return err
}
}
return nil
}
type Response struct {
Next []string `json:"next"`
Secret string `json:"secret"`
}
type ResponseSingle struct {
Next string `json:"next"`
Secret string `json:"secret"`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment