github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/acme/certmagic/storage.go (about) 1 // Copyright 2020 Asim Aslam 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Original source: github.com/micro/go-micro/v3/api/server/acme/certmagic/storage.go 16 17 package certmagic 18 19 import ( 20 "bytes" 21 "encoding/gob" 22 "errors" 23 "fmt" 24 "path" 25 "strings" 26 "time" 27 28 "github.com/caddyserver/certmagic" 29 "github.com/tickoalcantara12/micro/v3/service/store" 30 "github.com/tickoalcantara12/micro/v3/util/sync" 31 ) 32 33 // File represents a "File" that will be stored in store.Store - the contents and last modified time 34 type File struct { 35 // last modified time 36 LastModified time.Time 37 // Contents 38 Contents []byte 39 } 40 41 // storage is an implementation of certmagic.Storage using micro's sync.Map and store.Store interfaces. 42 // As certmagic storage expects a filesystem (with stat() abilities) we have to implement 43 // the bare minimum of metadata. 44 type storage struct { 45 lock sync.Sync 46 store store.Store 47 } 48 49 func (s *storage) Lock(key string) error { 50 return s.lock.Lock(key, sync.LockTTL(10*time.Minute)) 51 } 52 53 func (s *storage) Unlock(key string) error { 54 return s.lock.Unlock(key) 55 } 56 57 func (s *storage) Store(key string, value []byte) error { 58 f := File{ 59 LastModified: time.Now(), 60 Contents: value, 61 } 62 buf := &bytes.Buffer{} 63 e := gob.NewEncoder(buf) 64 if err := e.Encode(f); err != nil { 65 return err 66 } 67 r := &store.Record{ 68 Key: key, 69 Value: buf.Bytes(), 70 } 71 return s.store.Write(r) 72 } 73 74 func (s *storage) Load(key string) ([]byte, error) { 75 if !s.Exists(key) { 76 return nil, certmagic.ErrNotExist(errors.New(key + " doesn't exist")) 77 } 78 records, err := s.store.Read(key) 79 if err != nil { 80 return nil, err 81 } 82 if len(records) != 1 { 83 return nil, fmt.Errorf("ACME Storage: multiple records matched key %s", key) 84 } 85 b := bytes.NewBuffer(records[0].Value) 86 d := gob.NewDecoder(b) 87 var f File 88 err = d.Decode(&f) 89 if err != nil { 90 return nil, err 91 } 92 return f.Contents, nil 93 } 94 95 func (s *storage) Delete(key string) error { 96 return s.store.Delete(key) 97 } 98 99 func (s *storage) Exists(key string) bool { 100 if _, err := s.store.Read(key); err != nil { 101 return false 102 } 103 return true 104 } 105 106 func (s *storage) List(prefix string, recursive bool) ([]string, error) { 107 keys, err := s.store.List() 108 if err != nil { 109 return nil, err 110 } 111 112 //nolint:prealloc 113 var results []string 114 for _, k := range keys { 115 if strings.HasPrefix(k, prefix) { 116 results = append(results, k) 117 } 118 } 119 if recursive { 120 return results, nil 121 } 122 keysMap := make(map[string]bool) 123 for _, key := range results { 124 dir := strings.Split(strings.TrimPrefix(key, prefix+"/"), "/") 125 keysMap[dir[0]] = true 126 } 127 results = make([]string, 0) 128 for k := range keysMap { 129 results = append(results, path.Join(prefix, k)) 130 } 131 return results, nil 132 } 133 134 func (s *storage) Stat(key string) (certmagic.KeyInfo, error) { 135 records, err := s.store.Read(key) 136 if err != nil { 137 return certmagic.KeyInfo{}, err 138 } 139 if len(records) != 1 { 140 return certmagic.KeyInfo{}, fmt.Errorf("ACME Storage: multiple records matched key %s", key) 141 } 142 b := bytes.NewBuffer(records[0].Value) 143 d := gob.NewDecoder(b) 144 var f File 145 err = d.Decode(&f) 146 if err != nil { 147 return certmagic.KeyInfo{}, err 148 } 149 return certmagic.KeyInfo{ 150 Key: key, 151 Modified: f.LastModified, 152 Size: int64(len(f.Contents)), 153 IsTerminal: false, 154 }, nil 155 } 156 157 // NewStorage returns a certmagic.Storage backed by a go-micro/lock and go-micro/store 158 func NewStorage(lock sync.Sync, store store.Store) certmagic.Storage { 159 return &storage{ 160 lock: lock, 161 store: store, 162 } 163 }