Use better caching mechanism for mtr schedules
This commit is contained in:
		@@ -1,11 +1,14 @@
 | 
			
		||||
package bus
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    "fmt"
 | 
			
		||||
    "bytes"
 | 
			
		||||
    "encoding/json"
 | 
			
		||||
    "io"
 | 
			
		||||
    "log"
 | 
			
		||||
    "net/http"
 | 
			
		||||
    "path/filepath"
 | 
			
		||||
    "time"
 | 
			
		||||
 | 
			
		||||
    "github.com/tgckpg/golifehk/utils"
 | 
			
		||||
)
 | 
			
		||||
@@ -33,9 +36,27 @@ type BusStopBuses struct {
 | 
			
		||||
    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 ) {
 | 
			
		||||
@@ -48,7 +69,6 @@ func getSchedule( lang string, routeName string ) ( *BusSchedule, error ) {
 | 
			
		||||
    postLang := "en"
 | 
			
		||||
    if lang == "zh-Hant" {
 | 
			
		||||
        postLang = "zh"
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QUERY_FUNC := func() ( io.ReadCloser, error ) {
 | 
			
		||||
@@ -68,16 +88,62 @@ func getSchedule( lang string, routeName string ) ( *BusSchedule, error ) {
 | 
			
		||||
        return resp.Body, nil
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    buff, err := utils.CacheStream( CACHE_PATH, QUERY_FUNC, 60 )
 | 
			
		||||
    cs, err := utils.CacheStreamEx( CACHE_PATH, QUERY_FUNC )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    schedules := BusSchedule{}
 | 
			
		||||
    err = json.Unmarshal( buff.Bytes(), &schedules )
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        return nil, err
 | 
			
		||||
    oldSch := BusSchedule{
 | 
			
		||||
        Status: -1,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return &schedules, nil
 | 
			
		||||
    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 && cs.NotExpired( 60 ) {
 | 
			
		||||
            log.Printf( "Using cache: %s", CACHE_PATH )
 | 
			
		||||
            return &oldSch, nil
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if 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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user