etag.go 1.3 KB

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