package bahn import ( "fmt" "golang.org/x/net/html/charset" "io" "io/ioutil" "net/http" "strings" "time" "net/url" ) type ApiClient struct { IrisBaseUrl string CoachSequenceBaseUrl string HafasBaseUrl string HttpClient *http.Client Caches []CacheBackend } func (c *ApiClient) Station(evaId int64) ([]Station, error) { key := fmt.Sprintf("realtime_recent %d", evaId) var result []Station for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadStation(evaId); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadStation(evaId int64) ([]Station, error) { var err error uri := fmt.Sprintf("%s/timetable/station/%d", c.IrisBaseUrl, evaId) var stations []Station var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return stations, err } if stations, err = StationsFromReader(response.Body); err != nil { return stations, err } if err = response.Body.Close(); err != nil { return stations, err } return stations, err } func (c *ApiClient) Timetable(evaId int64, date time.Time) (Timetable, error) { key := fmt.Sprintf("timetable %d %s", evaId, date) var result Timetable for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadTimetable(evaId, date); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadTimetable(evaId int64, date time.Time) (Timetable, error) { var err error BahnFormat := "060102/15" uri := fmt.Sprintf("%s/timetable/plan/%d/%s", c.IrisBaseUrl, evaId, date.Format(BahnFormat)) var timetable Timetable var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return timetable, err } if timetable, err = TimetableFromReader(response.Body); err != nil { return timetable, err } if err = response.Body.Close(); err != nil { return timetable, err } return timetable, err } func (c *ApiClient) RealtimeAll(evaId int64, date time.Time) (Timetable, error) { key := fmt.Sprintf("realtime_all %d %s", evaId, date) var result Timetable for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadRealtimeAll(evaId, date); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadRealtimeAll(evaId int64, date time.Time) (Timetable, error) { var err error uri := fmt.Sprintf("%s/timetable/fchg/%d", c.IrisBaseUrl, evaId) var timetable Timetable var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return timetable, err } if timetable, err = TimetableFromReader(response.Body); err != nil { return timetable, err } if err = response.Body.Close(); err != nil { return timetable, err } return timetable, err } func (c *ApiClient) RealtimeRecent(evaId int64, date time.Time) (Timetable, error) { key := fmt.Sprintf("realtime_recent %d %s", evaId, date) var result Timetable for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadRealtimeRecent(evaId, date); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadRealtimeRecent(evaId int64, date time.Time) (Timetable, error) { var err error uri := fmt.Sprintf("%s/timetable/rchg/%d", c.IrisBaseUrl, evaId) var timetable Timetable var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return timetable, err } if timetable, err = TimetableFromReader(response.Body); err != nil { return timetable, err } if err = response.Body.Close(); err != nil { return timetable, err } return timetable, err } func (c *ApiClient) WingDefinition(parent string, wing string) (WingDefinition, error) { key := fmt.Sprintf("wing_definition %s %s", parent, wing) var result WingDefinition for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadWingDefinition(parent, wing); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadWingDefinition(parent string, wing string) (WingDefinition, error) { var err error uri := fmt.Sprintf("%s/timetable/wingdef/%s/%s", c.IrisBaseUrl, parent, wing) var wingDefinition WingDefinition var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return wingDefinition, err } if wingDefinition, err = WingDefinitionFromReader(response.Body); err != nil { return wingDefinition, err } if err = response.Body.Close(); err != nil { return wingDefinition, err } return wingDefinition, err } func (c *ApiClient) CoachSequence(line string, date time.Time) (CoachSequence, error) { key := fmt.Sprintf("coach_sequence %s %s", line, date.String()) var result CoachSequence for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadCoachSequence(line, date); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadCoachSequence(line string, date time.Time) (CoachSequence, error) { var err error uri := fmt.Sprintf("%s/%s/%s", c.CoachSequenceBaseUrl, line, date.Format(TimeLayoutShort)) var coachSequence CoachSequence var response *http.Response if response, err = c.HttpClient.Get(uri); err != nil { return coachSequence, err } if coachSequence, err = CoachSequenceFromReader(response.Body); err != nil { return coachSequence, err } if err = response.Body.Close(); err != nil { return coachSequence, err } return coachSequence, err } func (c *ApiClient) Suggestions(line string, date time.Time) ([]Suggestion, error) { key := fmt.Sprintf("suggestions %s %s", line, date.String()) var result []Suggestion for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadSuggestions(line, date); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadSuggestions(line string, date time.Time) ([]Suggestion, error) { var err error uri := fmt.Sprintf("%s/trainsearch.exe/dn", c.HafasBaseUrl) var suggestions []Suggestion DateFormat := "02.01.2006" body := url.Values{ "maxResults": []string{"50"}, "trainname": []string{line}, "date": []string{date.Format(DateFormat)}, "L": []string{"vs_json.vs_hap"}, } var response *http.Response if response, err = c.HttpClient.PostForm(uri, body); err != nil { return suggestions, err } var utf8reader io.Reader if utf8reader, err = charset.NewReaderLabel("ISO 8859-1", response.Body); err != nil { return suggestions, nil } var content []byte if content, err = ioutil.ReadAll(utf8reader); err != nil { return suggestions, err } strippedContent := string(content) strippedContent = strings.TrimPrefix(strippedContent, "TSLs.sls = ") strippedContent = strings.TrimSuffix(strippedContent, ";") if suggestions, err = SuggestionsFromBytes([]byte(strippedContent)); err != nil { return suggestions, err } if err = response.Body.Close(); err != nil { return suggestions, err } return suggestions, err } func (c *ApiClient) HafasMessages(trainlink string) ([]HafasMessage, error) { key := fmt.Sprintf("hafas_messages %s", trainlink) var result []HafasMessage for _, cache := range c.Caches { if err := cache.Get(key, result); err == nil { return result, nil } } var err error if result, err = c.loadHafasMessages(trainlink); err == nil { for _, cache := range c.Caches { _ = cache.Set(key, result) } } return result, err } func (c *ApiClient) loadHafasMessages(trainlink string) ([]HafasMessage, error) { var err error uri := fmt.Sprintf("%s/traininfo.exe/dn/%s?rt=1&ajax=1", c.HafasBaseUrl, trainlink) var messages []HafasMessage request, err := http.NewRequest("GET", uri, nil) var response *http.Response if response, err = c.HttpClient.Do(request); err != nil { return messages, err } if messages, err = HafasMessagesFromReader(response.Body); err != nil { return messages, err } if err = response.Body.Close(); err != nil { return messages, err } return messages, err }