1
0

etag.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package main
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/sha256"
  6. "encoding/hex"
  7. "encoding/json"
  8. "hash"
  9. "sync"
  10. )
  11. type etagPool struct {
  12. mutex sync.Mutex
  13. top *etagPoolEntry
  14. }
  15. type etagPoolEntry struct {
  16. hash hash.Hash
  17. enc *json.Encoder
  18. buf *bytes.Buffer
  19. next *etagPoolEntry
  20. }
  21. func newEtagPool(n int) *etagPool {
  22. pool := new(etagPool)
  23. for i := 0; i < n; i++ {
  24. pool.grow()
  25. }
  26. return pool
  27. }
  28. func (p *etagPool) grow() {
  29. h := sha256.New()
  30. enc := json.NewEncoder(h)
  31. enc.SetEscapeHTML(false)
  32. enc.SetIndent("", "")
  33. p.top = &etagPoolEntry{
  34. hash: h,
  35. enc: enc,
  36. buf: new(bytes.Buffer),
  37. next: p.top,
  38. }
  39. }
  40. func (p *etagPool) Get() *etagPoolEntry {
  41. p.mutex.Lock()
  42. defer p.mutex.Unlock()
  43. if p.top == nil {
  44. p.grow()
  45. }
  46. entry := p.top
  47. p.top = p.top.next
  48. return entry
  49. }
  50. func (p *etagPool) Put(e *etagPoolEntry) {
  51. p.mutex.Lock()
  52. defer p.mutex.Unlock()
  53. e.next = p.top
  54. p.top = e
  55. }
  56. var eTagCalcPool *etagPool
  57. func calcETag(ctx context.Context) ([]byte, context.CancelFunc) {
  58. c := eTagCalcPool.Get()
  59. cancel := func() { eTagCalcPool.Put(c) }
  60. c.hash.Reset()
  61. c.hash.Write(getImageData(ctx).Bytes())
  62. footprint := c.hash.Sum(nil)
  63. c.hash.Reset()
  64. c.hash.Write(footprint)
  65. c.hash.Write([]byte(version))
  66. c.enc.Encode(conf)
  67. c.enc.Encode(getProcessingOptions(ctx))
  68. c.buf.Reset()
  69. enc := hex.NewEncoder(c.buf)
  70. enc.Write(c.hash.Sum(nil))
  71. return c.buf.Bytes(), cancel
  72. }