diff --git a/.env b/.env index 5844601..df09d75 100644 --- a/.env +++ b/.env @@ -1,2 +1 @@ -PORT=8080 PORT=3001 diff --git a/README.md b/README.md index eef5dd7..441343c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,16 @@ -# Hash maps +# Random Image API ## Usage -**http://`host`:`port`/render?seed=`any`&w=`[1..100]`&h=`[1..100]`** -> width and height are not required, default is 7x7 +host: https://readyyyk-randimgapi.onrender.com/ +**http://`host`:`port`/hashmaps?`...[url params]`** +**http://`host`:`port`/picsum?`...[url params]`** +> width and height defaults: +> - hashmaps - 7x7 +> - picsum - 64x64 -> returns `svg` image +> returns: +> - hashmaps - `svg` image +> - picsum - `jpeg` image ## Installation diff --git a/hashMaps b/hashMaps new file mode 100755 index 0000000..701d567 Binary files /dev/null and b/hashMaps differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..80bdbed --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ +
+

https://github.com/readyyyk/randImgAPI

+
+ +

+ Use some of these routes: +

+ +

Use these url params:

+ \ No newline at end of file diff --git a/main.go b/main.go index 2f26542..df0f318 100644 --- a/main.go +++ b/main.go @@ -6,19 +6,74 @@ import ( svg "github.com/ajstarks/svgo" "github.com/joho/godotenv" "io" + "math" "math/rand" "net/http" "os" "strconv" + "time" ) +func checkError(err error, httpCode int, httpRes http.ResponseWriter) bool { + if err != nil { + httpRes.WriteHeader(httpCode) + fmt.Println(" [ERROR] - " + err.Error()) + return true + } + return false +} + +func stringToInt64(s string) int64 { + seed := int64(1) + for _, c := range s { + seed *= int64(c - '0') + } + return seed +} + +func getWHUrlParams(req *http.Request, w *int, h *int, maxW int, maxH int) (err error) { + if !req.URL.Query().Has("w") && !req.URL.Query().Has("h") { + return nil + } + if req.URL.Query().Has("w") { + wUrl, err := strconv.Atoi(req.URL.Query().Get("w")) + if err != nil { + return err + } + if wUrl < 1 || wUrl > maxW { + return err + } + *w, *h = wUrl, wUrl + } + if req.URL.Query().Has("h") { + hUrl, err := strconv.Atoi(req.URL.Query().Get("h")) + if err != nil { + return err + } + if hUrl < 1 || hUrl > maxH { + return err + } + *h = hUrl + } + return nil +} + func main() { + http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) { + fileData, err := os.ReadFile("index.html") + if checkError(err, http.StatusInternalServerError, res) { + return + } + res.Header().Set("Content-Type", "text/html") + _, _ = res.Write(fileData) + }) + // seed - required // w - width (if not defined 7) in range [1..100] // h - height (if not defined 7 or same as defined width) in range [1..100] // /render?seed=any&w=number&h=number - http.HandleFunc("/render", func(res http.ResponseWriter, req *http.Request) { - fmt.Println("[hashMap]") + http.HandleFunc("/hashmap", func(res http.ResponseWriter, req *http.Request) { + fmt.Println("\n[hashMap]") if req.Method != "GET" { res.WriteHeader(http.StatusBadRequest) return @@ -26,40 +81,20 @@ func main() { res.Header().Set("Content-Type", "image/svg+xml") // setting random seed - seedStr := req.URL.Query().Get("seed") - seed := int64(1) - for _, c := range seedStr { - seed *= int64(c - '0') + seed := time.Now().UnixNano() + if req.URL.Query().Has("seed") { + seed = stringToInt64(req.URL.Query().Get("seed")) } - fmt.Println(seed) rand.Seed(seed) + fmt.Println("seed: ", seed) // getting width and height with default 7x7 and in range of [1..100] w, h := 7, 7 - if req.URL.Query().Has("w") { - wUrl, err := strconv.Atoi(req.URL.Query().Get("w")) - if err != nil { - res.WriteHeader(http.StatusBadRequest) - return - } - if wUrl < 1 || wUrl > 100 { - res.WriteHeader(http.StatusBadRequest) - return - } - w, h = wUrl, wUrl - } - if req.URL.Query().Has("w") { - hUrl, err := strconv.Atoi(req.URL.Query().Get("h")) - if err != nil { - res.WriteHeader(http.StatusBadRequest) - return - } - if hUrl < 1 || hUrl > 100 { - res.WriteHeader(http.StatusBadRequest) - return - } - h = hUrl - } + checkError( + getWHUrlParams(req, &w, &h, 100, 100), + http.StatusBadRequest, + res, + ) colors := []string{"#000", "#fff"} img := svg.New(res) @@ -72,64 +107,82 @@ func main() { } img.End() }) + http.HandleFunc("/picsum", func(res http.ResponseWriter, req *http.Request) { - fmt.Println("[picsum]") + fmt.Println("\n[picsum]") if req.Method != "GET" { res.WriteHeader(http.StatusBadRequest) return } - if !req.URL.Query().Has("seed") { - res.WriteHeader(http.StatusBadRequest) - return + + // setting random seed + seed := strconv.Itoa(int(time.Now().UnixNano())) + if req.URL.Query().Has("seed") { + seed = req.URL.Query().Get("seed") } + fmt.Println(" seed: " + seed) // fetching info from picsum/.../info and getting donwload url - fetchedData, err := http.Get("https://picsum.photos/seed/" + req.URL.Query().Get("seed") + "/info") - if err != nil { - res.WriteHeader(http.StatusInternalServerError) - panic(err) + fetchedData, err := http.Get("https://picsum.photos/seed/" + seed + "/info") + if checkError(err, http.StatusInternalServerError, res) { return } + data, err := io.ReadAll(fetchedData.Body) - if err != nil { - res.WriteHeader(http.StatusInternalServerError) - panic(err) + if checkError(err, http.StatusInternalServerError, res) { return } + type downloadUrl struct { Url string `json:"download_url"` } var url downloadUrl err = json.Unmarshal(data, &url) - if err != nil { - res.WriteHeader(http.StatusInternalServerError) - panic(err) + if checkError(err, http.StatusInternalServerError, res) { return } // processing download url - url.Url = url.Url[:len(url.Url)-9] + "64/64" + w, h := 64, 64 + checkError( + getWHUrlParams(req, &w, &h, math.MaxInt, math.MaxInt), + http.StatusBadRequest, + res, + ) - // fetching entire image + isSecondSlash := false + for i := len(url.Url) - 1; i >= -1; i-- { + if url.Url[i] != '/' { + continue + } + if !isSecondSlash { + isSecondSlash = true + continue + } + url.Url = url.Url[0 : i+1] + break + } + url.Url = url.Url + strconv.Itoa(w) + "/" + strconv.Itoa(h) + + // reading image fetchedData, err = http.Get(url.Url) - if err != nil { - res.WriteHeader(http.StatusInternalServerError) - panic(err) + if checkError(err, http.StatusInternalServerError, res) { return } + data, err = io.ReadAll(fetchedData.Body) - if err != nil { - res.WriteHeader(http.StatusInternalServerError) - panic(err) + if checkError(err, http.StatusInternalServerError, res) { return } - res.Header().Set("Content-Type", "image/jpeg") + // writing response + res.Header().Set("Content-Type", req.Header.Get("Content-Type")) _, _ = res.Write(data) - res.WriteHeader(http.StatusOK) return }) + err := godotenv.Load(".env") + fmt.Println("[SERVER] - starting on :" + os.Getenv("PORT") + " ...") err = http.ListenAndServe(":"+os.Getenv("PORT"), nil) if err != nil { panic(err)