Repository navigation
Expand file tree
/
Copy pathetrade-core.go
More file actions
134 lines (112 loc) · 3.38 KB
/
Copy pathetrade-core.go
File metadata and controls
134 lines (112 loc) · 3.38 KB
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
134
package etradeapi
import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/gomodule/oauth1/oauth"
"github.com/blbgo/general"
"github.com/blbgo/record/recordlog"
)
// Etrade provides access to the etrade API
type Etrade interface {
Status() string
AccessTokenOK() bool
AuthURL() (string, error)
CheckCode(code string) error
MakeGetRequest(url string, form url.Values, result interface{}) error
MakePostRequest(url string, form url.Values, body interface{}, result interface{}) error
EtradeTimeAsGoTime(etradeTime int64) time.Time
Accounts() ([]Account, error)
Transactions(accountIDKey string, start time.Time) ([]Transaction, error)
}
type etrade struct {
recordlog.RecordLog
general.DumperFactory
http.RoundTripper
//httpClient httpinterface.Client
general.PersistentState
oauth.Client
baseServerURL string
requestCred *oauth.Credentials
etradeState
}
const stateName = "etradeAuth"
const timeFormatMMDDYYYY = "01022006"
type etradeState struct {
AccessCred *oauth.Credentials
AccessTime time.Time
}
// New provides an implementation of the Etrade interface
func New(
config Config,
recordLog recordlog.RecordLog,
dumperFactory general.DumperFactory,
roundTripper http.RoundTripper,
//httpClient httpinterface.Client,
persistentState general.PersistentState,
) Etrade {
return &etrade{
RecordLog: recordLog,
DumperFactory: dumperFactory,
//httpClient: httpClient,
RoundTripper: roundTripper,
PersistentState: persistentState,
Client: oauth.Client{
Credentials: oauth.Credentials{
Token: config.ConsumerKey(),
Secret: config.ConsumerSecret(),
},
TemporaryCredentialRequestURI: config.RequestTokenURL(),
ResourceOwnerAuthorizationURI: config.AuthorizeURL(),
TokenRequestURI: config.AccessTokenURL(),
RenewCredentialRequestURI: config.RenewTokenURL(),
},
baseServerURL: config.BaseServerURL(),
}
}
func (r *etrade) Status() string {
if r.AccessCred == nil {
err := r.PersistentState.Retrieve(stateName, &r.etradeState)
if err != nil {
return "No access token"
}
}
d := time.Since(r.AccessTime).Round(time.Minute)
h := d / time.Hour
d -= h * time.Hour
m := d / time.Minute
return fmt.Sprint("Access token acquired ", int64(h), " hours and ", int64(m), " minutes ago")
}
func (r *etrade) AccessTokenOK() bool {
if r.AccessCred == nil {
r.PersistentState.Retrieve(stateName, &r.etradeState)
}
return r.AccessCred != nil && time.Since(r.AccessTime) < (time.Minute*110)
}
func (r *etrade) AuthURL() (string, error) {
var err error
r.requestCred, err = r.Client.RequestTemporaryCredentials(nil, "oob", nil)
if err != nil {
return "", err
}
authorizationURL := r.Client.AuthorizationURL(
r.requestCred,
url.Values{"key": {r.Client.Credentials.Token}},
)
// etrade used paramiter "token" instead of the standard "oauth_token"
return strings.ReplaceAll(authorizationURL, "oauth_token", "token"), nil
}
func (r *etrade) CheckCode(code string) error {
var err error
r.AccessCred, _, err = r.Client.RequestToken(nil, r.requestCred, code)
if err != nil {
return err
}
r.AccessTime = time.Now()
return r.PersistentState.Save(stateName, &r.etradeState)
}
func (r *etrade) EtradeTimeAsGoTime(etradeTime int64) time.Time {
return time.Unix(etradeTime/1000, 0).UTC()
}