aboutsummaryrefslogtreecommitdiff
path: root/kamus_cache.go
diff options
context:
space:
mode:
authorShulhan <m.shulhan@gmail.com>2020-03-31 01:11:26 +0700
committerShulhan <m.shulhan@gmail.com>2020-04-01 06:28:03 +0700
commit8a141995aabdee289d2b096bd77a10b52b08a1bf (patch)
tree98af569d4c3e2620809ce591c2733184cd77db8f /kamus_cache.go
parent84fdfdb6ae4175a125fc67a6aed377476d31ee0e (diff)
downloadkamusku-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.go165
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
+}