github.com/zooyer/miskit@v1.0.71/sdk/jcon/jcon.go (about) 1 package jcon 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "strings" 8 "sync" 9 "time" 10 ) 11 12 type cacheInfo struct { 13 Data []byte 14 Timestamp int64 15 } 16 17 var ( 18 dir string 19 mutex sync.RWMutex 20 cache = make(map[string]map[string]*cacheInfo) 21 ) 22 23 func readNamespace(dir string) (map[string]*cacheInfo, error) { 24 files, err := ioutil.ReadDir(dir) 25 if err != nil { 26 return nil, err 27 } 28 var cache = make(map[string]*cacheInfo) 29 for _, file := range files { 30 if file.IsDir() { 31 continue 32 } 33 filename := filepath.Join(dir, file.Name()) 34 ft, err := fileTime(filename) 35 if err != nil { 36 return nil, err 37 } 38 data, err := ioutil.ReadFile(filename) 39 if err != nil { 40 return nil, err 41 } 42 cache[strings.TrimSuffix(file.Name(), ".json")] = &cacheInfo{ 43 Timestamp: ft.UnixNano(), 44 Data: data, 45 } 46 } 47 return cache, nil 48 } 49 50 func filePath(namespace string) string { 51 return filepath.Join(dir, namespace) 52 } 53 54 func fileName(namespace, name string) string { 55 return filepath.Join(dir, namespace, name+".json") 56 } 57 58 func fileTime(filename string) (time.Time, error) { 59 stat, err := os.Stat(filename) 60 if err != nil { 61 return time.Time{}, err 62 } 63 64 return stat.ModTime(), nil 65 } 66 67 func getData(namespace, name string) ([]byte, error) { 68 mutex.Lock() 69 defer mutex.Unlock() 70 71 filename := fileName(namespace, name) 72 tm, err := fileTime(filename) 73 if err != nil { 74 return nil, err 75 } 76 77 var data []byte 78 if cache[namespace] != nil { 79 if info := cache[namespace][name]; info != nil { 80 data = info.Data 81 if tm.UnixNano() == info.Timestamp { 82 return data, nil 83 } 84 } 85 } 86 87 file, err := ioutil.ReadFile(filename) 88 if err != nil { 89 if data != nil { 90 return data, nil 91 } 92 return nil, err 93 } 94 95 if cache[namespace] == nil { 96 cache[namespace] = make(map[string]*cacheInfo) 97 } 98 cache[namespace][name] = &cacheInfo{ 99 Data: file, 100 Timestamp: tm.UnixNano(), 101 } 102 103 return file, nil 104 } 105 106 func touch(filename string) (err error) { 107 file, err := os.Create(filename) 108 if err != nil { 109 return 110 } 111 defer file.Close() 112 113 return 114 } 115 116 func notify(namespace, name string, fn func()) (err error) { 117 var last, curr time.Time 118 for { 119 filename := fileName(namespace, name) 120 if curr, _ = fileTime(filename); curr != last { 121 fn() 122 last = curr 123 } 124 time.Sleep(time.Second) 125 } 126 }