gifs/api
gifs/api/usage.go
Upload is no longer async, memstorage is parallel-safe. Upload no longer needs to be run async (it can be run inside a goroutine), so it now returns stuff instead of taking a channel as an argument. This will make it easier to implement, as all the async stuff is an abstraction above, and therefore doesn't need to be worried about for each reimplementation. The memstorage type is no longer exported and can now be safely used by multiple goroutines, thanks to the sync package.
| paddy@0 | 1 package api |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "sync" |
| paddy@0 | 5 ) |
| paddy@0 | 6 |
| paddy@0 | 7 func NewUsageTracker() *UsageTracker { |
| paddy@0 | 8 return &UsageTracker{ |
| paddy@0 | 9 usages: make(map[string]*Usage), |
| paddy@0 | 10 } |
| paddy@0 | 11 } |
| paddy@0 | 12 |
| paddy@0 | 13 type UsageTracker struct { |
| paddy@0 | 14 usages map[string]*Usage |
| paddy@0 | 15 sync.Mutex |
| paddy@0 | 16 } |
| paddy@0 | 17 |
| paddy@0 | 18 func (u *UsageTracker) TrackUploads(id string) (bytes, requests chan int64) { |
| paddy@0 | 19 u.Lock() |
| paddy@0 | 20 defer u.Unlock() |
| paddy@0 | 21 if _, ok := u.usages[id]; !ok { |
| paddy@0 | 22 u.usages[id] = &Usage{ |
| paddy@0 | 23 UploadBytesChan: make(chan int64), |
| paddy@0 | 24 DownloadBytesChan: make(chan int64), |
| paddy@0 | 25 UploadRequestsChan: make(chan int64), |
| paddy@0 | 26 DownloadRequestsChan: make(chan int64), |
| paddy@0 | 27 } |
| paddy@0 | 28 go u.usages[id].collect() |
| paddy@0 | 29 } |
| paddy@0 | 30 return u.usages[id].UploadBytesChan, u.usages[id].UploadRequestsChan |
| paddy@0 | 31 } |
| paddy@0 | 32 |
| paddy@0 | 33 func (u *UsageTracker) TrackDownloads(id string) (bytes, requests chan int64) { |
| paddy@0 | 34 u.Lock() |
| paddy@0 | 35 defer u.Unlock() |
| paddy@0 | 36 if _, ok := u.usages[id]; !ok { |
| paddy@0 | 37 u.usages[id] = &Usage{ |
| paddy@0 | 38 UploadBytesChan: make(chan int64), |
| paddy@0 | 39 DownloadBytesChan: make(chan int64), |
| paddy@0 | 40 UploadRequestsChan: make(chan int64), |
| paddy@0 | 41 DownloadRequestsChan: make(chan int64), |
| paddy@0 | 42 } |
| paddy@0 | 43 go u.usages[id].collect() |
| paddy@0 | 44 } |
| paddy@0 | 45 return u.usages[id].DownloadBytesChan, u.usages[id].DownloadRequestsChan |
| paddy@0 | 46 } |
| paddy@0 | 47 |
| paddy@0 | 48 type Usage struct { |
| paddy@0 | 49 UploadedBytes int64 |
| paddy@0 | 50 UploadBytesChan chan int64 |
| paddy@0 | 51 DownloadedBytes int64 |
| paddy@0 | 52 DownloadBytesChan chan int64 |
| paddy@0 | 53 UploadRequests int64 |
| paddy@0 | 54 UploadRequestsChan chan int64 |
| paddy@0 | 55 DownloadRequests int64 |
| paddy@0 | 56 DownloadRequestsChan chan int64 |
| paddy@0 | 57 } |
| paddy@0 | 58 |
| paddy@0 | 59 func (u *Usage) collect() { |
| paddy@0 | 60 for { |
| paddy@0 | 61 select { |
| paddy@0 | 62 case b, ok := <-u.UploadBytesChan: |
| paddy@0 | 63 if !ok { |
| paddy@0 | 64 u.UploadBytesChan = nil |
| paddy@0 | 65 } |
| paddy@0 | 66 u.UploadedBytes += b |
| paddy@0 | 67 case r, ok := <-u.UploadRequestsChan: |
| paddy@0 | 68 if !ok { |
| paddy@0 | 69 u.UploadRequestsChan = nil |
| paddy@0 | 70 } |
| paddy@0 | 71 u.UploadRequests += r |
| paddy@0 | 72 case b, ok := <-u.DownloadBytesChan: |
| paddy@0 | 73 if !ok { |
| paddy@0 | 74 u.DownloadBytesChan = nil |
| paddy@0 | 75 } |
| paddy@0 | 76 u.DownloadedBytes += b |
| paddy@0 | 77 case r, ok := <-u.DownloadRequestsChan: |
| paddy@0 | 78 if !ok { |
| paddy@0 | 79 u.DownloadRequestsChan = nil |
| paddy@0 | 80 } |
| paddy@0 | 81 u.DownloadRequests += r |
| paddy@0 | 82 } |
| paddy@0 | 83 if u.UploadBytesChan == nil && u.UploadRequestsChan == nil && u.DownloadBytesChan == nil && u.DownloadRequestsChan == nil { |
| paddy@0 | 84 break |
| paddy@0 | 85 } |
| paddy@0 | 86 } |
| paddy@0 | 87 } |