// Copyright 2016 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 }