add avatar inorder to view code on github
This commit is contained in:
		
							parent
							
								
									17da2fd2e3
								
							
						
					
					
						commit
						8e47ae2102
					
				
					 2 changed files with 171 additions and 0 deletions
				
			
		
							
								
								
									
										136
									
								
								modules/avatar/avatar.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								modules/avatar/avatar.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| package avatar | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| var gravatar = "http://www.gravatar.com/avatar" | ||||
| 
 | ||||
| // hash email to md5 string
 | ||||
| func HashEmail(email string) string { | ||||
| 	h := md5.New() | ||||
| 	h.Write([]byte(strings.ToLower(email))) | ||||
| 	return hex.EncodeToString(h.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| type Avatar struct { | ||||
| 	Hash      string | ||||
| 	cacheDir  string // image save dir
 | ||||
| 	reqParams string | ||||
| 	imagePath string | ||||
| } | ||||
| 
 | ||||
| func New(hash string, cacheDir string) *Avatar { | ||||
| 	return &Avatar{ | ||||
| 		Hash:     hash, | ||||
| 		cacheDir: cacheDir, | ||||
| 		reqParams: url.Values{ | ||||
| 			"d":    {"retro"}, | ||||
| 			"size": {"200"}, | ||||
| 			"r":    {"pg"}}.Encode(), | ||||
| 		imagePath: filepath.Join(cacheDir, hash+".jpg"), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // get image from gravatar.com
 | ||||
| func (this *Avatar) Update() { | ||||
| 	thunder.Fetch(gravatar+"/"+this.Hash+"?"+this.reqParams, | ||||
| 		this.Hash+".jpg") | ||||
| } | ||||
| 
 | ||||
| func (this *Avatar) UpdateTimeout(timeout time.Duration) { | ||||
| 	select { | ||||
| 	case <-time.After(timeout): | ||||
| 		log.Println("timeout") | ||||
| 	case <-thunder.GoFetch(gravatar+"/"+this.Hash+"?"+this.reqParams, | ||||
| 		this.Hash+".jpg"): | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var thunder = &Thunder{QueueSize: 10} | ||||
| 
 | ||||
| type Thunder struct { | ||||
| 	QueueSize int // download queue size
 | ||||
| 	q         chan *thunderTask | ||||
| 	once      sync.Once | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) init() { | ||||
| 	if t.QueueSize < 1 { | ||||
| 		t.QueueSize = 1 | ||||
| 	} | ||||
| 	t.q = make(chan *thunderTask, t.QueueSize) | ||||
| 	for i := 0; i < t.QueueSize; i++ { | ||||
| 		go func() { | ||||
| 			for { | ||||
| 				task := <-t.q | ||||
| 				task.Fetch() | ||||
| 			} | ||||
| 		}() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) Fetch(url string, saveFile string) error { | ||||
| 	t.once.Do(t.init) | ||||
| 	task := &thunderTask{ | ||||
| 		Url:      url, | ||||
| 		SaveFile: saveFile, | ||||
| 	} | ||||
| 	task.Add(1) | ||||
| 	t.q <- task | ||||
| 	task.Wait() | ||||
| 	return task.err | ||||
| } | ||||
| 
 | ||||
| func (t *Thunder) GoFetch(url, saveFile string) chan error { | ||||
| 	c := make(chan error) | ||||
| 	go func() { | ||||
| 		c <- t.Fetch(url, saveFile) | ||||
| 	}() | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // thunder download
 | ||||
| type thunderTask struct { | ||||
| 	Url      string | ||||
| 	SaveFile string | ||||
| 	sync.WaitGroup | ||||
| 	err error | ||||
| } | ||||
| 
 | ||||
| func (this *thunderTask) Fetch() { | ||||
| 	this.err = this.fetch() | ||||
| 	this.Done() | ||||
| } | ||||
| 
 | ||||
| func (this *thunderTask) fetch() error { | ||||
| 	resp, err := http.Get(this.Url) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 	if resp.StatusCode != 200 { | ||||
| 		return fmt.Errorf("status code: %d", resp.StatusCode) | ||||
| 	} | ||||
| 	fd, err := os.Create(this.SaveFile) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer fd.Close() | ||||
| 	_, err = io.Copy(fd, resp.Body) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										35
									
								
								modules/avatar/avatar_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								modules/avatar/avatar_test.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | |||
| package avatar | ||||
| 
 | ||||
| import ( | ||||
| 	"log" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
| 
 | ||||
| func TestFetch(t *testing.T) { | ||||
| 	hash := HashEmail("ssx205@gmail.com") | ||||
| 	avatar := New(hash, "./") | ||||
| 	//avatar.Update()
 | ||||
| 	avatar.UpdateTimeout(time.Millisecond * 200) | ||||
| 	time.Sleep(5 * time.Second) | ||||
| } | ||||
| 
 | ||||
| func TestFetchMany(t *testing.T) { | ||||
| 	log.Println("start") | ||||
| 	var n = 50 | ||||
| 	ch := make(chan bool, n) | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		go func(i int) { | ||||
| 			hash := HashEmail(strconv.Itoa(i) + "ssx205@gmail.com") | ||||
| 			avatar := New(hash, "./") | ||||
| 			avatar.Update() | ||||
| 			log.Println("finish", hash) | ||||
| 			ch <- true | ||||
| 		}(i) | ||||
| 	} | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		<-ch | ||||
| 	} | ||||
| 	log.Println("end") | ||||
| } | ||||
		Loading…
	
		Reference in a new issue