-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathstation.go
365 lines (305 loc) · 9.97 KB
/
station.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
package rail
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/pkg/errors"
)
// TrainBetweenStationsReq parameters
type TrainBetweenStationsReq struct {
// Specifies the source station code.
FromStationCode string `validate:"required"`
// Specifies the destination station code.
ToStationCode string `validate:"required"`
// Specifies the date for which result is required.
Date time.Time `validate:"required"`
}
// Request encodes TrainBetweenStationsReq parameters returning a new http.Request
func (r TrainBetweenStationsReq) Request() (*http.Request, error) {
err := validate.Struct(r)
if err != nil {
return nil, errors.Wrap(err, "invalid request")
}
urlStr := DefaultBaseURL + "/v2/between"
urlStr += fmt.Sprintf(
"/source/%s/dest/%s/date/%s",
r.FromStationCode,
r.ToStationCode,
date(r.Date),
)
return http.NewRequest(http.MethodGet, urlStr, nil)
}
// ExtendedTrain holds extended train details
type ExtendedTrain struct {
*Train
ToStation *Station `json:"to_station,omitempty"`
FromStation *Station `json:"from_station,omitempty"`
SourceDepartureTime *time.Time // `json:"src_departure_time,omitempty"`
DestinationArrivalTime *time.Time // `json:"dest_arrival_time,omitempty"`
TravelDuration *time.Duration // `json:"travel_time,omitempty"`
}
// UnmarshalJSON convert JSON data to struct
func (et *ExtendedTrain) UnmarshalJSON(data []byte) error {
type Alias ExtendedTrain
t := struct {
Alias
SourceDepartureTime string `json:"src_departure_time"`
DestinationArrivalTime string `json:"dest_arrival_time"`
TravelTime string `json:"travel_time"`
}{}
if err := json.Unmarshal(data, &t); err != nil {
return errors.Wrap(err, "UnmarshalJSON failed")
}
*et = ExtendedTrain(t.Alias)
if len(t.SourceDepartureTime) == 5 {
sdt, err := time.Parse("15:04", t.SourceDepartureTime)
if err != nil {
return errors.Wrap(err, "parse SourceDepartureTime failed")
}
et.SourceDepartureTime = &sdt
}
if len(t.DestinationArrivalTime) == 5 {
dat, err := time.Parse("15:04", t.DestinationArrivalTime)
if err != nil {
return errors.Wrap(err, "parse DestinationArrivalTime failed")
}
et.DestinationArrivalTime = &dat
}
if len(t.TravelTime) == 5 {
d := func(s string) string { return strings.Replace(s, ":", "h", -1) + "m" }
dur, err := time.ParseDuration(d(t.TravelTime))
if err != nil {
return errors.Wrap(err, "parse travelTime failed")
}
et.TravelDuration = &dur
}
return nil
}
// TrainBetweenStationsResp holds trains between stations
type TrainBetweenStationsResp struct {
Trains []ExtendedTrain `json:"trains,omitempty"`
Total *int `json:"total,omitempty"`
*Response
}
// TrainBetweenStations gets trains running between stations.
func (c Client) TrainBetweenStations(ctx context.Context,
FromStationCode string,
ToStationCode string,
Date time.Time,
) (TrainBetweenStationsResp, error) {
if c.Auth == nil {
return TrainBetweenStationsResp{}, ErrNoAuth
}
var r TrainBetweenStationsResp
err := c.Do(c.Auth(WithCtx(ctx, TrainBetweenStationsReq{
FromStationCode: FromStationCode,
ToStationCode: ToStationCode,
Date: Date,
})), &r)
return r, errors.Wrap(err, "Client.Do failed")
}
// TrainArrivalsReq parameters
type TrainArrivalsReq struct {
// Specifies the source station code.
StationCode string `validate:"required"`
// Specifies the windows hours to search.
//
// Window time in hours to search, valid values are 2 or 4.
Hours WindowHour `validate:"required"`
}
// Request encodes TrainArrivalsReq parameters returning a new http.Request
func (r TrainArrivalsReq) Request() (*http.Request, error) {
err := validate.Struct(r)
if err != nil {
return nil, errors.Wrap(err, "invalid request")
}
var hours uint8
switch r.Hours {
case WindowHour2:
hours = 2
case WindowHour4:
hours = 4
default:
return nil, errors.New("invalid WindowHour")
}
urlStr := DefaultBaseURL + "/v2/arrivals"
urlStr += fmt.Sprintf("/station/%s/hours/%d", r.StationCode, hours)
return http.NewRequest(http.MethodGet, urlStr, nil)
}
// TrainWithTimings holds train timings
type TrainWithTimings struct {
*Train
DelayArrivalTime *time.Time //`json:"delayarr,omitempty"`
DelayDepartureTime *time.Time //`json:"delaydep,omitempty"`
ScheduledArrivalTime *time.Time //`json:"scharr,omitempty"`
ScheduledDepartureTime *time.Time //`json:"schdep,omitempty"`
ActualDepartureTime *time.Time //`json:"actdep,omitempty"`
ActualArrivalTime *time.Time //`json:"actarr,omitempty"`
}
// UnmarshalJSON convert JSON data to struct
func (r *TrainWithTimings) UnmarshalJSON(data []byte) error {
t := struct {
ScheduledArrivalTime string `json:"scharr"`
ScheduledDepartureTime string `json:"schdep"`
ActualDepartureTime string `json:"actdep"`
ActualArrivalTime string `json:"actarr"`
DelayArrivalTime string `json:"delayarr"`
DelayDepartureTime string `json:"delaydep"`
*Train
}{}
if err := json.Unmarshal(data, &t); err != nil {
return errors.Wrap(err, "UnmarshalJSON failed")
}
r.Train = t.Train
if len(t.ScheduledArrivalTime) == 5 {
sa, err := time.Parse("15:04", t.ScheduledArrivalTime)
if err != nil {
return errors.Wrap(err, "parse ScheduledArrival failed")
}
r.ScheduledArrivalTime = &sa
}
if len(t.ScheduledDepartureTime) == 5 {
sd, err := time.Parse("15:04", t.ScheduledDepartureTime)
if err != nil {
return errors.Wrap(err, "parse ScheduledDeparture failed")
}
r.ScheduledDepartureTime = &sd
}
if len(t.ActualDepartureTime) == 5 {
ad, err := time.Parse("15:04", t.ActualDepartureTime)
if err != nil {
return errors.Wrap(err, "parse ActualDeparture failed")
}
r.ActualDepartureTime = &ad
}
if len(t.ActualArrivalTime) == 5 {
aa, err := time.Parse("15:04", t.ActualArrivalTime)
if err != nil {
return errors.Wrap(err, "parse ActualArrival failed")
}
r.ActualArrivalTime = &aa
}
if len(t.DelayArrivalTime) == 5 {
da, err := time.Parse("15:04", t.DelayArrivalTime)
if err != nil {
return errors.Wrap(err, "parse DelayArrival failed")
}
r.DelayArrivalTime = &da
}
if len(t.DelayDepartureTime) == 5 {
dd, err := time.Parse("15:04", t.DelayDepartureTime)
if err != nil {
return errors.Wrap(err, "parse DelayDeparture failed")
}
r.DelayDepartureTime = &dd
}
return nil
}
// TrainArrivalsResp holds train arrivals details
type TrainArrivalsResp struct {
Trains []TrainWithTimings `json:"trains,omitempty"`
Total *int `json:"total,omitempty"`
*Response
}
// TrainArrivals get list of trains arriving at a station within
// a window period along with their live status.
//
// Window time in hours to search, valid values are 2 or 4.
func (c Client) TrainArrivals(ctx context.Context,
StationCode string,
Hours WindowHour,
) (TrainArrivalsResp, error) {
if c.Auth == nil {
return TrainArrivalsResp{}, ErrNoAuth
}
var r TrainArrivalsResp
err := c.Do(c.Auth(WithCtx(ctx, TrainArrivalsReq{
StationCode: StationCode,
Hours: Hours,
})), &r)
return r, errors.Wrap(err, "Client.Do failed")
}
// StationNameToCodeReq parameters
type StationNameToCodeReq struct {
// Specifies the source station name.
StationName string `validate:"required"`
}
// Request encodes StationNameToCodeReq parameters returning a new http.Request
func (r StationNameToCodeReq) Request() (*http.Request, error) {
err := validate.Struct(r)
if err != nil {
return nil, errors.Wrap(err, "invalid request")
}
urlStr := DefaultBaseURL + "/v2/name-to-code"
urlStr += fmt.Sprintf("/station/%s", r.StationName)
return http.NewRequest(http.MethodGet, urlStr, nil)
}
// Stations holds stations
type Stations struct {
Stations []Station `json:"stations"`
*Response
}
// StationNameToCode gets station details of the given station and
// its nearby stations using partial station name.
// Station’s name is autocompleted.
func (c Client) StationNameToCode(ctx context.Context, StationName string) (Stations, error) {
if c.Auth == nil {
return Stations{}, ErrNoAuth
}
var r Stations
err := c.Do(c.Auth(WithCtx(ctx, StationNameToCodeReq{StationName})), &r)
return r, errors.Wrap(err, "Client.Do failed")
}
// StationCodeToNameReq parameters
type StationCodeToNameReq struct {
// Specifies the source station code.
StationCode string `validate:"required"`
}
// Request encodes StationCodeToNameReq parameters returning a new http.Request
func (r StationCodeToNameReq) Request() (*http.Request, error) {
err := validate.Struct(r)
if err != nil {
return nil, errors.Wrap(err, "invalid request")
}
urlStr := DefaultBaseURL + "/v2/code-to-name"
urlStr += fmt.Sprintf("/code/%s", r.StationCode)
return http.NewRequest(http.MethodGet, urlStr, nil)
}
// StationCodeToName gets station details of the given station and
// its nearby stations using partial station name.
// Station’s name is autocompleted.
func (c Client) StationCodeToName(ctx context.Context, StationCode string) (Stations, error) {
if c.Auth == nil {
return Stations{}, ErrNoAuth
}
var r Stations
err := c.Do(c.Auth(WithCtx(ctx, StationCodeToNameReq{StationCode})), &r)
return r, errors.Wrap(err, "Client.Do failed")
}
// SuggestStationReq parameters
type SuggestStationReq struct {
// Specifies the source station name.
StationName string `validate:"required"`
}
// Request encodes SuggestStationReq parameters returning a new http.Request
func (r SuggestStationReq) Request() (*http.Request, error) {
err := validate.Struct(r)
if err != nil {
return nil, errors.Wrap(err, "invalid request")
}
urlStr := DefaultBaseURL + "/v2/suggest-station"
urlStr += fmt.Sprintf("/name/%s", r.StationName)
return http.NewRequest(http.MethodGet, urlStr, nil)
}
// SuggestStation suggests full station names given a partial station name.
func (c Client) SuggestStation(ctx context.Context, StationName string) (Stations, error) {
if c.Auth == nil {
return Stations{}, ErrNoAuth
}
var r Stations
err := c.Do(c.Auth(WithCtx(ctx, SuggestStationReq{StationName})), &r)
return r, errors.Wrap(err, "Client.Do failed")
}