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  }