summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Gerus <arachnist@i.am-a.cat>2016-06-13 19:26:48 +0200
committerRobert Gerus <arachnist@i.am-a.cat>2016-06-13 19:26:48 +0200
commitea151d1de7bacc24fca339c19d8afd2089c4b2fa (patch)
tree06056d4965ce88f670499be16c4de34c312d50e2
downloadfrog-tipper-ea151d1de7bacc24fca339c19d8afd2089c4b2fa.tar.gz
frog-tipper-ea151d1de7bacc24fca339c19d8afd2089c4b2fa.tar.bz2
frog-tipper-ea151d1de7bacc24fca339c19d8afd2089c4b2fa.tar.xz
frog-tipper-ea151d1de7bacc24fca339c19d8afd2089c4b2fa.zip
Frog tipper! First and final release!
-rw-r--r--frog-tipper.go109
1 files changed, 109 insertions, 0 deletions
diff --git a/frog-tipper.go b/frog-tipper.go
new file mode 100644
index 0000000..0f37281
--- /dev/null
+++ b/frog-tipper.go
@@ -0,0 +1,109 @@
+// Copyright 2015 Robert S. Gerus. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/http/cookiejar"
+ "sync"
+ "time"
+)
+
+type tip struct {
+ Number int `json:"number"`
+ Tip string `json:"tip"`
+}
+
+type tips struct {
+ Tips []tip `json:"tips"`
+ lock sync.RWMutex
+}
+
+func (tips *tips) fetchTips() error {
+ tips.lock.Lock()
+ defer tips.lock.Unlock()
+
+ data, err := httpGet("http://frog.tips/api/1/tips/")
+ if err != nil {
+ return err
+ }
+
+ err = json.Unmarshal(data, tips)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (tips *tips) popTip() string {
+ if len(tips.Tips) == 0 {
+ if err := tips.fetchTips(); err != nil {
+ return fmt.Sprint(err)
+ }
+ }
+
+ tips.lock.RLock()
+ defer tips.lock.RUnlock()
+
+ rmsg := tips.Tips[len(tips.Tips)-1].Tip
+ tips.Tips = tips.Tips[:len(tips.Tips)-1]
+
+ return rmsg
+}
+
+func main() {
+ var t tips
+ for {
+ fmt.Println(t.popTip())
+ }
+}
+
+func httpGet(link string) ([]byte, error) {
+ var buf []byte
+ cj, err := cookiejar.New(nil)
+ tr := &http.Transport{
+ TLSHandshakeTimeout: 20 * time.Second,
+ ResponseHeaderTimeout: 20 * time.Second,
+ }
+ client := &http.Client{
+ Transport: tr,
+ Jar: cj,
+ }
+
+ req, err := http.NewRequest("GET", link, nil)
+ if err != nil {
+ return []byte{}, err
+ }
+
+ req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.152 Safari/537.36")
+
+ resp, err := client.Do(req)
+ if err != nil {
+ return []byte{}, err
+ }
+ defer resp.Body.Close()
+
+ // 5MiB
+ if resp.ContentLength > 5*1024*1024 || resp.ContentLength < 0 {
+ buf = make([]byte, 5*1024*1024)
+ } else if resp.ContentLength == 0 {
+ return []byte{}, nil
+ } else {
+ buf = make([]byte, resp.ContentLength)
+ }
+
+ i, err := io.ReadFull(resp.Body, buf)
+ if err == io.ErrUnexpectedEOF {
+ buf = buf[:i]
+ } else if err != nil {
+ return []byte{}, err
+ }
+
+ return buf, nil
+}