avatar.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package avatar
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "fmt"
  6. "io"
  7. "log"
  8. "net/http"
  9. "net/url"
  10. "os"
  11. "path/filepath"
  12. "strings"
  13. "sync"
  14. "time"
  15. )
  16. var gravatar = "http://www.gravatar.com/avatar"
  17. // hash email to md5 string
  18. func HashEmail(email string) string {
  19. h := md5.New()
  20. h.Write([]byte(strings.ToLower(email)))
  21. return hex.EncodeToString(h.Sum(nil))
  22. }
  23. type Avatar struct {
  24. Hash string
  25. cacheDir string // image save dir
  26. reqParams string
  27. imagePath string
  28. }
  29. func New(hash string, cacheDir string) *Avatar {
  30. return &Avatar{
  31. Hash: hash,
  32. cacheDir: cacheDir,
  33. reqParams: url.Values{
  34. "d": {"retro"},
  35. "size": {"200"},
  36. "r": {"pg"}}.Encode(),
  37. imagePath: filepath.Join(cacheDir, hash+".jpg"),
  38. }
  39. }
  40. // get image from gravatar.com
  41. func (this *Avatar) Update() {
  42. thunder.Fetch(gravatar+"/"+this.Hash+"?"+this.reqParams,
  43. this.Hash+".jpg")
  44. }
  45. func (this *Avatar) UpdateTimeout(timeout time.Duration) {
  46. select {
  47. case <-time.After(timeout):
  48. log.Println("timeout")
  49. case <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams,
  50. this.Hash+".jpg"):
  51. }
  52. }
  53. var thunder = &Thunder{QueueSize: 10}
  54. type Thunder struct {
  55. QueueSize int // download queue size
  56. q chan *thunderTask
  57. once sync.Once
  58. }
  59. func (t *Thunder) init() {
  60. if t.QueueSize < 1 {
  61. t.QueueSize = 1
  62. }
  63. t.q = make(chan *thunderTask, t.QueueSize)
  64. for i := 0; i < t.QueueSize; i++ {
  65. go func() {
  66. for {
  67. task := <-t.q
  68. task.Fetch()
  69. }
  70. }()
  71. }
  72. }
  73. func (t *Thunder) Fetch(url string, saveFile string) error {
  74. t.once.Do(t.init)
  75. task := &thunderTask{
  76. Url: url,
  77. SaveFile: saveFile,
  78. }
  79. task.Add(1)
  80. t.q <- task
  81. task.Wait()
  82. return task.err
  83. }
  84. func (t *Thunder) GoFetch(url, saveFile string) chan error {
  85. c := make(chan error)
  86. go func() {
  87. c <- t.Fetch(url, saveFile)
  88. }()
  89. return c
  90. }
  91. // thunder download
  92. type thunderTask struct {
  93. Url string
  94. SaveFile string
  95. sync.WaitGroup
  96. err error
  97. }
  98. func (this *thunderTask) Fetch() {
  99. this.err = this.fetch()
  100. this.Done()
  101. }
  102. func (this *thunderTask) fetch() error {
  103. resp, err := http.Get(this.Url)
  104. if err != nil {
  105. return err
  106. }
  107. defer resp.Body.Close()
  108. if resp.StatusCode != 200 {
  109. return fmt.Errorf("status code: %d", resp.StatusCode)
  110. }
  111. fd, err := os.Create(this.SaveFile)
  112. if err != nil {
  113. return err
  114. }
  115. defer fd.Close()
  116. _, err = io.Copy(fd, resp.Body)
  117. if err != nil {
  118. return err
  119. }
  120. return nil
  121. }