package bus import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "path/filepath" "time" "github.com/tgckpg/golifehk/utils" ) type Location struct { latitude float32 longitude float32 } type Bus struct { ETA int `json:"arrivalTimeInSecond,string"` ETAText string `json:"arrivalTimeText"` BusId string `json:"busId"` BusLocation Location `json:"busLocation"` ETD string `json:"departureTimeInSecond"` ETDText string `json:"departureTimeText"` Delayed string `json:"isDelayed"` Scheduled string `json:"isScheduled"` LineRef string `json:"lineRef"` } type BusStopBuses struct { Buses []Bus `json:"bus"` BusStopId string `json:"busStopId"` Suspended string `json:"isSuspended"` } type ScheduleStatusTime struct { time.Time } type BusSchedule struct { RefreshTime int `json:"appRefreshTimeInSecond,string"` BusStops []BusStopBuses `json:"busStop"` StatusTime ScheduleStatusTime `json:"routeStatusTime"` RemarksTitle string `json:"routeStatusRemarkTitle"` // 0 = OK // 100 = Rate limit ( Unconfirmed. Not in spec ) Status int `json:"status,string"` } func (t *ScheduleStatusTime) UnmarshalJSON(b []byte) (err error) { date, err := time.Parse(`"2006\/01\/02 15:04"`, string(b)) if err != nil { return err } t.Time = date return } func getSchedule(lang string, routeName string) (*BusSchedule, error) { CACHE_PATH := filepath.Join( utils.WORKDIR, "mtr_bsch"+"-"+lang+"-"+routeName+".json", ) postLang := "en" if lang == "zh-Hant" { postLang = "zh" } QUERY_FUNC := func() (io.ReadCloser, error) { // Query Remote values := map[string]string{"language": postLang, "routeName": routeName} jsonValue, _ := json.Marshal(values) resp, err := http.Post( "https://rt.data.gov.hk/v1/transport/mtr/bus/getSchedule", "application/json", bytes.NewBuffer(jsonValue), ) if err != nil { return nil, err } return resp.Body, nil } cs, err := utils.CacheStreamEx(CACHE_PATH, QUERY_FUNC) if err != nil { return nil, err } oldSch := BusSchedule{ Status: -1, } if cs.Local != nil { err = json.Unmarshal(cs.Local.Bytes(), &oldSch) if err != nil { return nil, err } } newSch := BusSchedule{ Status: -1, } for i := 0; i < 3; i++ { if cs.Remote != nil { err = json.Unmarshal(cs.Remote.Bytes(), &newSch) if err != nil { return nil, err } } if newSch.Status == 0 { cs.Commit() return &newSch, nil } if oldSch.Status == 0 { if cs.NotExpired(60) || oldSch.StatusTime.Time == newSch.StatusTime.Time { log.Printf("Using cache: %s", CACHE_PATH) return &oldSch, nil } } // First time + try again i times err = cs.Reload() log.Printf("Reloading (%d): %s", i, CACHE_PATH) if err != nil { err = fmt.Errorf("Error retrieving data: %s", err) return nil, err } } if newSch.Status != 0 { err = fmt.Errorf("%s (%d)", newSch.RemarksTitle, newSch.Status) } return &newSch, err }