diff options
| author | Shulhan <m.shulhan@gmail.com> | 2020-03-31 01:11:26 +0700 |
|---|---|---|
| committer | Shulhan <m.shulhan@gmail.com> | 2020-04-01 06:28:03 +0700 |
| commit | 8a141995aabdee289d2b096bd77a10b52b08a1bf (patch) | |
| tree | 98af569d4c3e2620809ce591c2733184cd77db8f /kamus_cache.go | |
| parent | 84fdfdb6ae4175a125fc67a6aed377476d31ee0e (diff) | |
| download | kamusku-8a141995aabdee289d2b096bd77a10b52b08a1bf.tar.xz | |
all: implement server and client for dictionary API
Currently the server and client can onyl handle API for looking up
definitions of the words through "/api/definisi" URL.
Diffstat (limited to 'kamus_cache.go')
| -rw-r--r-- | kamus_cache.go | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/kamus_cache.go b/kamus_cache.go new file mode 100644 index 0000000..ffcf4db --- /dev/null +++ b/kamus_cache.go @@ -0,0 +1,165 @@ +// Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package kbbi + +import ( + "bytes" + "encoding/gob" + "errors" + "io/ioutil" + "log" + "os" + "sync" + + libio "github.com/shuLhan/share/lib/io" +) + +const ( + defStorageName = "kamus.gob" +) + +// +// kamusCache contains cache of words and its definitions. +// +type kamusCache struct { + sync.Mutex + cache map[string]*Kata + lastSize int + + storagePath string +} + +// +// newKamusCache create and initialize the cache for dictionary. +// +func newKamusCache(storagePath string) (kamusc *kamusCache, err error) { + if len(storagePath) == 0 { + storagePath = defStorageName + } + + kamusc = &kamusCache{ + cache: make(map[string]*Kata), + storagePath: storagePath, + } + + err = kamusc.load() + if err != nil { + return nil, err + } + + return kamusc, nil +} + +// +// get the definition of word from cache or nil if not exist. +// +func (kamus *kamusCache) get(word string) (kata *Kata) { + kamus.Lock() + kata = kamus.cache[word] + kamus.Unlock() + return kata +} + +// +// isChanging will return true if the last cache size is not equal with +// current size. +// +func (kamus *kamusCache) isChanging() bool { + kamus.Lock() + defer kamus.Unlock() + return kamus.lastSize != len(kamus.cache) +} + +// +// load the cached dictionary from storage. +// +func (kamus *kamusCache) load() (err error) { + kamus.Lock() + defer kamus.Unlock() + + v, err := ioutil.ReadFile(kamus.storagePath) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return nil + } + return err + } + + r := bytes.NewReader(v) + + dec := gob.NewDecoder(r) + err = dec.Decode(&kamus.cache) + if err != nil { + return err + } + + kamus.lastSize = len(kamus.cache) + + return nil +} + +// +// set save the definition of word into cache. +// +func (kamus *kamusCache) set(word string, kata *Kata) { + if len(word) == 0 || kata == nil { + return + } + + kamus.Lock() + kamus.cache[word] = kata + kamus.Unlock() +} + +// +// store the cache to file only if the storage path is set. +// +func (kamus *kamusCache) store() (err error) { + if len(kamus.storagePath) == 0 { + return nil + } + + kamus.Lock() + defer kamus.Unlock() + + if len(kamus.cache) == 0 { + return nil + } + + newStorage := kamus.storagePath + ".new" + + f, err := os.Create(newStorage) + if err != nil { + errc := f.Close() + if errc != nil { + log.Println("kamusCache: store: ", err) + } + return err + } + + enc := gob.NewEncoder(f) + err = enc.Encode(&kamus.cache) + if err != nil { + errc := f.Close() + if errc != nil { + log.Println("kamusCache: store: ", err) + } + return err + } + + errc := f.Close() + if errc != nil { + log.Println("kamusCache: store: ", err) + } + + err = libio.Copy(kamus.storagePath, newStorage) + if err != nil { + return err + } + + kamus.lastSize = len(kamus.cache) + + return nil +} |
