diff options
Diffstat (limited to 'cache.go')
-rw-r--r-- | cache.go | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/cache.go b/cache.go new file mode 100644 index 0000000..253de98 --- /dev/null +++ b/cache.go @@ -0,0 +1,159 @@ +package main + +import ( + "log" + "reflect" + "strings" + "time" + + "github.com/getwtxt/registry" + "github.com/syndtr/goleveldb/leveldb" +) + +// checks if it's time to refresh the cache or not +func checkCacheTime() bool { + return time.Since(confObj.lastCache) > confObj.cacheInterval +} + +// checks if it's time to push the cache to the database +func checkDBtime() bool { + return time.Since(confObj.lastPush) > confObj.dbInterval +} + +// launched by init as a goroutine to constantly watch +// for the update interval to pass +func cacheAndPush() { + for { + if checkCacheTime() { + refreshCache() + } + if checkDBtime() { + if err := pushDatabase(); err != nil { + log.Printf("Error pushing cache to database: %v\n", err) + } + } + } +} + +// refreshes the cache +func refreshCache() { + + for k := range twtxtCache.Reg { + err := twtxtCache.UpdateUser(k) + if err != nil { + log.Printf("%v\n", err) + continue + } + } + + for _, v := range remoteRegistries.List { + err := twtxtCache.ScrapeRemoteRegistry(v) + if err != nil { + log.Printf("Error while refreshing local copy of remote registry user data: %v\n", err) + } + } + confObj.mu.Lock() + confObj.lastCache = time.Now() + confObj.mu.Unlock() +} + +// pushes the registry's cache data to a local +// database for safe keeping +func pushDatabase() error { + db := <-dbChan + twtxtCache.Mu.RLock() + + // create a batch write job so it can + // be done at one time rather than + // per value + var dbBasket *leveldb.Batch + for k, v := range twtxtCache.Reg { + dbBasket.Put([]byte(k+".Nick"), []byte(v.Nick)) + dbBasket.Put([]byte(k+".URL"), []byte(v.URL)) + dbBasket.Put([]byte(k+".IP"), []byte(v.IP)) + dbBasket.Put([]byte(k+".Date"), []byte(v.Date)) + for i, e := range v.Status { + dbBasket.Put([]byte(k+".Status."+i.String()), []byte(e)) + } + } + + // save our list of remote registries to scrape + for k, v := range remoteRegistries.List { + dbBasket.Put([]byte("remote."+string(k)), []byte(v)) + } + + // execute the batch job + if err := db.Write(dbBasket, nil); err != nil { + return err + } + + twtxtCache.Mu.RUnlock() + dbChan <- db + + // update the last push time + confObj.mu.Lock() + confObj.lastPush = time.Now() + confObj.mu.Unlock() + + return nil +} + +// pulls registry data from the DB on startup +func pullDatabase() { + db := <-dbChan + + iter := db.NewIterator(nil, nil) + + for iter.Next() { + key := iter.Key() + val := iter.Value() + + split := strings.Split(string(key), ".") + urls := string(split[0]) + field := string(split[1]) + data := registry.NewUserData() + + twtxtCache.Mu.RLock() + if _, ok := twtxtCache.Reg[urls]; ok { + data = twtxtCache.Reg[urls] + } + twtxtCache.Mu.RUnlock() + + ref := reflect.ValueOf(data).Elem() + + if field != "Status" && urls != "remote" { + for i := 0; i < ref.NumField(); i++ { + + f := ref.Field(i) + if f.String() == field { + f.Set(reflect.ValueOf(val)) + break + } + } + } else if field == "Status" && urls != "remote" { + + thetime, err := time.Parse("RFC3339", split[2]) + if err != nil { + log.Printf("%v\n", err) + } + data.Status[thetime] = string(val) + + } else { + remoteRegistries.Mu.Lock() + remoteRegistries.List = append(remoteRegistries.List, string(val)) + remoteRegistries.Mu.Unlock() + } + + twtxtCache.Mu.Lock() + twtxtCache.Reg[urls] = data + twtxtCache.Mu.Unlock() + } + + iter.Release() + err := iter.Error() + if err != nil { + log.Printf("Error while pulling DB into registry cache: %v\n", err) + } + + dbChan <- db +} |