-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathersvc.go
More file actions
148 lines (116 loc) · 3.82 KB
/
ersvc.go
File metadata and controls
148 lines (116 loc) · 3.82 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package api
import (
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strings"
"time"
)
// ----------------------------------------------
// const endpoints
// ----------------------------------------------
const DOMAIN = ".pamdas.org"
const API_V1 = "/api/v1.0"
const API_AUTH = "/oauth2/token"
const API_ACTIVITY = API_V1 + "/activity"
const API_PATROLS = API_ACTIVITY + "/patrols"
const API_SUBJECT = API_V1 + "/subject"
const API_SUBJECTS = API_V1 + "/subjects"
const API_SUBJECT_TRACKS = "/tracks"
const API_USER = API_V1 + "/user"
const API_USER_ME = API_USER + "/me"
const API_USER_PROFILES = "/profiles"
// ----------------------------------------------
// struct
// ----------------------------------------------
type Client struct {
httpClient *http.Client
sitename string
token string
mockURL string
}
// ----------------------------------------------
// functions
// ----------------------------------------------
func ERClient(sitename, token string, opts ...string) *Client {
mockURL := ""
if len(opts) > 0 {
mockURL = opts[0]
}
return &Client{
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
sitename: sitename,
token: token,
mockURL: mockURL,
}
}
func (c *Client) newRequest(method, endpoint string, isAuth bool) (*http.Request, error) {
url := getApiUrl(c.sitename, endpoint, c.mockURL)
req, err := http.NewRequest(method, url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
if isAuth {
// Auth request headers
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
} else {
// Regular API request headers
req.Header.Set("Authorization", "Bearer "+c.token)
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; er-cli)")
}
return req, nil
}
func (c *Client) doRequest(req *http.Request, v interface{}) error {
resp, err := c.httpClient.Do(req)
if err != nil {
return c.handleRequestError(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
return fmt.Errorf("failed to decode response: %w", err)
}
return nil
}
func (c *Client) handleRequestError(err error) error {
// Check for timeout errors
if os.IsTimeout(err) {
return fmt.Errorf("request timed out - try reducing the requested data and/or check your network connection")
}
// Check for context deadline exceeded (another form of timeout)
if err == context.DeadlineExceeded || strings.Contains(err.Error(), "context deadline exceeded") {
return fmt.Errorf("request timed out - try reducing the date range with --days or check your network connection")
}
// Check for network timeout specifically
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
return fmt.Errorf("network timeout - try reducing the date range with --days or check your network connection")
}
// Check for DNS resolution errors
if strings.Contains(err.Error(), "no such host") {
return fmt.Errorf("unable to connect to EarthRanger server - check your network connection and site name")
}
// Check for connection refused
if strings.Contains(err.Error(), "connection refused") {
return fmt.Errorf("connection refused - check your network connection and EarthRanger server status")
}
// Default error message for other request failures
return fmt.Errorf("failed to connect to EarthRanger server: %v", err)
}
// ----------------------------------------------
// Helper functions
// ----------------------------------------------
func getApiUrl(sitename string, endpoint string, mockURL string) string {
if mockURL != "" {
return mockURL + endpoint
}
return fmt.Sprintf("https://%s%s%s", sitename, DOMAIN, endpoint)
}