-
Notifications
You must be signed in to change notification settings - Fork 4
/
cdn.go
73 lines (64 loc) · 2.48 KB
/
cdn.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// go-coronanet - Coronavirus social distancing network
// Copyright (c) 2020 Péter Szilágyi. All rights reserved.
package coronanet
import (
"encoding/binary"
"errors"
"golang.org/x/crypto/sha3"
)
var (
dbCDNImagePrefix = []byte("cdn-image-")
dbCDNImageRefSuffix = []byte("-refs")
// ErrImageNotFound is returned if an image is attempted to be read from the
// CDN but it is not found.
ErrImageNotFound = errors.New("image not found")
)
// uploadCDNImage inserts a binary image blob by hash into the CND and increments
// its reference count.
func (b *Backend) uploadCDNImage(data []byte) ([32]byte, error) {
// Calculate the image hash to use as a database key
hash := sha3.Sum256(data)
// Retrieve the number of live references to this hash
var refs uint64
if blob, err := b.database.Get(append(append(dbCDNImagePrefix, hash[:]...), dbCDNImageRefSuffix...), nil); err == nil {
refs, _ = binary.Uvarint(blob) // TODO(karalabe): Maybe check for errors?
}
// If there are no live references, upload the image; either way, bump the refs
if refs == 0 {
if err := b.database.Put(append(dbCDNImagePrefix, hash[:]...), data, nil); err != nil {
return [32]byte{}, err
}
}
blob := make([]byte, binary.MaxVarintLen64)
blob = blob[:binary.PutUvarint(blob, refs+1)]
return hash, b.database.Put(append(append(dbCDNImagePrefix, hash[:]...), dbCDNImageRefSuffix...), blob, nil)
}
// deleteCDNImage dereferences an image from the CDN and deletes it if the ref
// count reaches zero.
func (b *Backend) deleteCDNImage(hash [32]byte) error {
// Retrieve the number of live references to this hash, skip if zero
var refs uint64
if blob, err := b.database.Get(append(append(dbCDNImagePrefix, hash[:]...), dbCDNImageRefSuffix...), nil); err == nil {
refs, _ = binary.Uvarint(blob) // TODO(karalabe): Maybe check for errors?
}
if refs == 0 {
return nil
}
// If there is only one reference, delete the image; either way, drop the refs
if refs == 1 {
if err := b.database.Delete(append(dbCDNImagePrefix, hash[:]...), nil); err != nil {
return err
}
}
blob := make([]byte, binary.MaxVarintLen64)
blob = blob[:binary.PutUvarint(blob, refs-1)]
return b.database.Put(append(append(dbCDNImagePrefix, hash[:]...), dbCDNImageRefSuffix...), blob, nil)
}
// CDNImage retrieves an image from the CDN.
func (b *Backend) CDNImage(hash [32]byte) ([]byte, error) {
blob, err := b.database.Get(append(dbCDNImagePrefix, hash[:]...), nil)
if err != nil {
return nil, ErrImageNotFound
}
return blob, nil
}