package bus import ( "fmt" "bytes" "encoding/json" "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 }