forked from ronoaldo/swgoh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
133 lines (120 loc) · 3.41 KB
/
client.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
126
127
128
129
130
131
132
133
package swgohgg
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"net/http/cookiejar"
"net/url"
"github.com/PuerkitoBio/goquery"
"github.com/ronoaldo/swgoh/swgohgg/api"
)
// Client implements methods to interact with the https://swgoh.gg/ website.
type Client struct {
gg *api.Client
hc *http.Client
guildName string
playerName string
shortLink string
allyCode string
authorized bool
}
// NewClient initializes a new instance of the client, tied to the specified user profile.
func NewClient(profile string) *Client {
// Build up the HTTP client for website requests
jar, err := cookiejar.New(nil)
if err != nil {
// Should never happen.
panic(err)
}
c := &Client{
hc: http.DefaultClient,
shortLink: profile,
}
c.hc.Jar = jar
// Build up the API client for API endpoint requests
c.gg = api.NewClient(context.Background())
return c
}
// Get retrieves the provided URL and returns a parsed goquery.Document.
func (c *Client) Get(url string) (*goquery.Document, error) {
// Not in cache, fetch from remote site
resp, err := c.hc.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, fmt.Errorf("swgohgg: unable to find collection for profile '%s'", url)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("swgohgg: unexpected status code %d", resp.StatusCode)
}
data, err := ioutil.ReadAll(resp.Body)
return goquery.NewDocumentFromReader(bytes.NewBuffer(data))
}
// UseHTTPClient allows one to overwrite the default HTTP Client.
// The Client.Jar is replaced before next use.
func (c *Client) UseHTTPClient(hc *http.Client) *Client {
hc.Jar = c.hc.Jar
c.hc = hc
return c
}
// Profile sets the client profile to a new value.
// *DEPRECATED*: use SetAllyCode instead.
func (c *Client) Profile(profile string) *Client {
c.shortLink = profile
return c
}
// SetAllyCode set's the Ally Code for the client.
func (c *Client) SetAllyCode(allyCode string) *Client {
c.allyCode = nonDigits.ReplaceAllString(allyCode, "")
return c
}
// AllyCode returns the player ally code
func (c *Client) AllyCode() string {
// Fetch and cache ally code
if c.allyCode == "" {
c.Arena()
}
return c.allyCode
}
// PlayerName returns the player nickname
func (c *Client) PlayerName() string {
return c.playerName
}
// GuildName returns the player guild name
func (c *Client) GuildName() string {
return c.guildName
}
// Login authorizes the bot client using the provided username and password.
func (c *Client) Login(username, password string) (err error) {
resp, err := c.hc.Get("https://swgoh.gg/accounts/login/")
if err != nil {
return err
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return fmt.Errorf("swgoh.gg: unexpected status code %d: %v", resp.StatusCode, resp.Status)
}
loginPage, err := goquery.NewDocumentFromResponse(resp)
if err != nil {
return err
}
loginForm := make(url.Values)
loginPage.Find("input").Each(func(i int, s *goquery.Selection) {
loginForm[s.AttrOr("name", "")] = []string{s.AttrOr("value", "")}
})
loginForm["username"] = []string{username}
loginForm["password"] = []string{password}
resp, err = c.hc.PostForm("https://swgoh.gg/accounts/login/", loginForm)
if err != nil {
return err
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
return fmt.Errorf("swgoh.gg: unexpected status code %d: %v", resp.StatusCode, resp.Status)
}
// Logged in!
c.authorized = true
return nil
}