From ad0dd2afce6830d717b9024464e291ef721e3bd2 Mon Sep 17 00:00:00 2001 From: Andinus Date: Thu, 19 Mar 2020 15:46:28 +0530 Subject: Add local cache for fetched body --- README.org | 2 +- cmd/cetus/main.go | 186 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 128 insertions(+), 60 deletions(-) diff --git a/README.org b/README.org index fa40c9c..50b4349 100644 --- a/README.org +++ b/README.org @@ -25,7 +25,7 @@ doesn't support some desktop environments but should work fine many others. I plan to add support for unsupported DEs too provided they're not hard to implement. -Also the code is very dirty, I couldn't think of a good way to structure it. If +Also the code is not so good, I couldn't think of a good way to structure it. If you have a better idea then please let me know. * Demo diff --git a/cmd/cetus/main.go b/cmd/cetus/main.go index 7d4ebc8..fa53e9a 100644 --- a/cmd/cetus/main.go +++ b/cmd/cetus/main.go @@ -3,6 +3,7 @@ package main import ( "flag" "fmt" + "io/ioutil" "math/rand" "os" "time" @@ -140,12 +141,11 @@ func getCacheDir() string { } func execAPOD() { - // reqInfo holds all the parameters that needs to be - // sent with the request. GetJson() will pack apiKey & - // date in params map before sending it to another - // function. Adding params here will not change the - // behaviour of the function, changes have to be made - // in GetJson() too. + // reqInfo holds all the parameters that needs to be sent with + // the request. GetJson() will pack apiKey & date in params + // map before sending it to another function. Adding params + // here will not change the behaviour of the function, changes + // have to be made in GetJson() too. reqInfo := make(map[string]string) reqInfo["api"] = string(*apodAPI) reqInfo["apiKey"] = string(*apodKey) @@ -155,8 +155,28 @@ func execAPOD() { reqInfo["date"] = apod.RandDate() } - body, err := apod.GetJson(reqInfo) - chkErr(err) + cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "apod") + os.MkdirAll(cacheDir, os.ModePerm) + + // Check if the file is available locally, if it is then don't + // download it again and get it from disk + var body string + file := fmt.Sprintf("%s/%s", cacheDir, reqInfo["date"]) + if _, err := os.Stat(file); err == nil { + data, err := ioutil.ReadFile(file) + chkErr(err) + body = string(data) + } else if os.IsNotExist(err) { + body, err = apod.GetJson(reqInfo) + chkErr(err) + + // Write body to the cache so that it can be read + // later + err = ioutil.WriteFile(file, []byte(body), 0644) + chkErr(err) + } else { + chkErr(err) + } if *apodDump { fmt.Printf(body) @@ -164,34 +184,32 @@ func execAPOD() { } res := apod.Res{} - err = apod.UnmarshalJson(&res, body) + err := apod.UnmarshalJson(&res, body) chkErr(err) - // res.Msg will be returned when there is error on - // user input or the api server. + // res.Msg will be returned when there is error on user input + // or the api server. if len(res.Msg) != 0 { fmt.Printf("Message: %s", res.Msg) os.Exit(1) } - // If path-only is passed then it will only print the - // path, even if quiet is passed. If the user wants - // the program to be quiet then path-only shouldn't be - // passed. If path-only is not passed & quiet is also - // not passed then print the response. + // If path-only is passed then it will only print the path, + // even if quiet is passed. If the user wants the program to + // be quiet then path-only shouldn't be passed. If path-only + // is not passed & quiet is also not passed then print the + // response. // - // Path is only printed when the media type is an - // image because res.HDURL is empty on non image media - // type. + // Path is only printed when the media type is an image + // because res.HDURL is empty on non image media type. if *apodPathOnly { fmt.Println(res.HDURL) } else if !*apodQuiet { apod.Print(res) } - // Proceed only if the command was set because if it - // was fetch then it's already finished & should exit - // now. + // Proceed only if the command was set because if it was fetch + // then it's already finished & should exit now. if os.Args[1] == "fetch" { os.Exit(0) } @@ -203,30 +221,29 @@ func execAPOD() { if res.MediaType != "image" { os.Exit(0) } - cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "apod") - os.MkdirAll(cacheDir, os.ModePerm) - file := fmt.Sprintf("%s/%s", cacheDir, reqInfo["date"]) + imgCacheDir := fmt.Sprintf("%s/%s", cacheDir, "background") + os.MkdirAll(imgCacheDir, os.ModePerm) + imgFile := fmt.Sprintf("%s/%s", imgCacheDir, reqInfo["date"]) // Check if the file is available locally, if it is // then don't download it again and set it from disk - if _, err := os.Stat(file); os.IsNotExist(err) { - err = background.Download(file, res.HDURL) + if _, err := os.Stat(imgFile); os.IsNotExist(err) { + err = background.Download(imgFile, res.HDURL) chkErr(err) } else { chkErr(err) } - err = background.Set(file) + err = background.Set(imgFile) chkErr(err) } func execBPOD() { - // reqInfo holds all the parameters that needs to be - // sent with the request. GetJson() will pack apiKey & - // date in params map before sending it to another - // function. Adding params here will not change the - // behaviour of the function, changes have to be made - // in GetJson() too. + // reqInfo holds all the parameters that needs to be sent with + // the request. GetJson() will pack apiKey & date in params + // map before sending it to another function. Adding params + // here will not change the behaviour of the function, changes + // have to be made in GetJson() too. reqInfo := make(map[string]string) reqInfo["api"] = string(*bpodAPI) @@ -234,14 +251,54 @@ func execBPOD() { reqInfo["random"] = "true" } - body, err := bpod.GetJson(reqInfo) - chkErr(err) + cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "bpod") + os.MkdirAll(cacheDir, os.ModePerm) - if *bpodDump { - fmt.Printf(body) - os.Exit(0) + // Check if the file is available locally, if it is then don't + // download it again and get it from disk. + // + // We don't know the bpod date because that will be there in + // response & we can't read the response without requesting + // it. So this will assume the bpod date to be today's date if + // *bpodRand is not set true. If *bpodRand is set true then we + // can't assume the date. Also this way too it can cause error + // if our assumed date doesn't matches date at the server. + var body string + var file string + var err error + + if !*bpodRand { + // If not *bpodRand and the file exists then read from + // disk, if the file doesn't exist then get it and + // save it to disk. + file = fmt.Sprintf("%s/%s", cacheDir, time.Now().UTC().Format("2006-01-02")) + if _, err := os.Stat(file); err == nil { + data, err := ioutil.ReadFile(file) + chkErr(err) + body = string(data) + } else if os.IsNotExist(err) { + body, err = bpod.GetJson(reqInfo) + chkErr(err) + + // Write body to the cache so that it can be + // read later + err = ioutil.WriteFile(file, []byte(body), 0644) + chkErr(err) + } else { + chkErr(err) + } + } else { + // If *bpodRand then get the file and save it to disk + // after unmarshal because we don't know the file name + // yet + body, err = bpod.GetJson(reqInfo) + chkErr(err) } + // Unmarshal before dump because otherwise if we come across + // the date for the first time then it would just dump and + // exit without saving it to cache. This way we first save it + // to cache if *bpodRand is true. res, err := bpod.UnmarshalJson(body) chkErr(err) @@ -251,24 +308,35 @@ func execBPOD() { chkErr(err) res.StartDate = dt.Format("2006-01-02") - // If path-only is passed then it will only print the - // path, even if quiet is passed. If the user wants - // the program to be quiet then path-only shouldn't be - // passed. If path-only is not passed & quiet is also - // not passed then print the response. + file = fmt.Sprintf("%s/%s", cacheDir, res.StartDate) + if *bpodRand { + // Write body to the cache so that it can be read + // later + err = ioutil.WriteFile(file, []byte(body), 0644) + chkErr(err) + } + + if *bpodDump { + fmt.Printf(body) + os.Exit(0) + } + + // If path-only is passed then it will only print the path, + // even if quiet is passed. If the user wants the program to + // be quiet then path-only shouldn't be passed. If path-only + // is not passed & quiet is also not passed then print the + // response. // - // Path is only printed when the media type is an - // image because res.HDURL is empty on non image media - // type. + // Path is only printed when the media type is an image + // because res.HDURL is empty on non image media type. if *bpodPathOnly { fmt.Println(res.Url) } else if !*bpodQuiet { bpod.Print(res) } - // Proceed only if the command was set because if it - // was fetch then it's already finished & should exit - // now. + // Proceed only if the command was set because if it was fetch + // then it's already finished & should exit now. if os.Args[1] == "fetch" { os.Exit(0) } @@ -277,20 +345,20 @@ func execBPOD() { // First it downloads the image to the cache directory and // then tries to set it with feh. If the download fails then // it exits with a non-zero exit code. - cacheDir := fmt.Sprintf("%s/%s", getCacheDir(), "bpod") - os.MkdirAll(cacheDir, os.ModePerm) - file := fmt.Sprintf("%s/%s", cacheDir, res.StartDate) - - // Check if the file is available locally, if it is - // then don't download it again and set it from disk - if _, err := os.Stat(file); os.IsNotExist(err) { - err = background.Download(file, res.Url) + imgCacheDir := fmt.Sprintf("%s/%s", cacheDir, "background") + os.MkdirAll(imgCacheDir, os.ModePerm) + imgFile := fmt.Sprintf("%s/%s", imgCacheDir, res.StartDate) + + // Check if the file is available locally, if it is then don't + // download it again and set it from disk + if _, err := os.Stat(imgFile); os.IsNotExist(err) { + err = background.Download(imgFile, res.Url) chkErr(err) } else { chkErr(err) } - err = background.Set(file) + err = background.Set(imgFile) chkErr(err) } -- cgit 1.4.1-2-gfad0