diff options
| author | Shulhan <ms@kilabit.info> | 2021-01-31 04:56:36 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2021-01-31 06:16:54 +0700 |
| commit | 6c7bfd42bc1128f5969e9e40b23d6b828601f7cb (patch) | |
| tree | 8138149fde47f135b965be0837b4f8b83421728f /dictionary.go | |
| parent | 734ce643ecbc992834a8f78b44904b82b09bc84b (diff) | |
| download | kamusku-6c7bfd42bc1128f5969e9e40b23d6b828601f7cb.tar.xz | |
all: rewrite the server
This commit move the directClient to different repository called kamusku
and changes the module name from kamusku to kamusd.
Diffstat (limited to 'dictionary.go')
| -rw-r--r-- | dictionary.go | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/dictionary.go b/dictionary.go new file mode 100644 index 0000000..2dd309f --- /dev/null +++ b/dictionary.go @@ -0,0 +1,178 @@ +// Copyright 2020, Shulhan <ms@kilabit.info>. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package kamusd + +import ( + "bytes" + "encoding/gob" + "errors" + "io/ioutil" + "log" + "os" + "sync" + + "git.sr.ht/~shulhan/kamusku" + libio "github.com/shuLhan/share/lib/io" +) + +const ( + defStorageName = "kamus.gob" +) + +// +// dictionary contains cache of words and its definitions. +// +type dictionary struct { + sync.Mutex + cache map[string]*kamusku.Word + lastSize int + storagePath string +} + +// +// newDictionary create and initialize the cache for dictionary. +// +func newDictionary(storagePath string) (dict *dictionary, err error) { + if len(storagePath) == 0 { + storagePath = defStorageName + } + + dict = &dictionary{ + cache: make(map[string]*kamusku.Word), + storagePath: storagePath, + } + + err = dict.load() + if err != nil { + return nil, err + } + + return dict, nil +} + +// +// lookup the definition of word from cache or nil if not exist. +// +func (dict *dictionary) lookup(word string) (kata *kamusku.Word) { + dict.Lock() + kata = dict.cache[word] + dict.Unlock() + return kata +} + +// +// isChanging will return true if the last cache size is not equal with +// current size. +// +func (dict *dictionary) isChanging() bool { + dict.Lock() + defer dict.Unlock() + return dict.lastSize != len(dict.cache) +} + +// +// load the cached dictionary from storage. +// +func (dict *dictionary) load() (err error) { + dict.Lock() + defer dict.Unlock() + + v, err := ioutil.ReadFile(dict.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(&dict.cache) + if err != nil { + return err + } + + // Clean up. Remove all word that contain "→" as definition. + for k, kata := range dict.cache { + for _, def := range kata.Definition { + if def.Value == "→" { + delete(dict.cache, k) + break + } + } + if len(kata.Definition) == 0 { + delete(dict.cache, k) + } + } + + dict.lastSize = len(dict.cache) + + return nil +} + +// +// set save the definition of word into cache. +// +func (dict *dictionary) set(word string, kata *kamusku.Word) { + if len(word) == 0 || kata == nil { + return + } + + dict.Lock() + dict.cache[word] = kata + dict.Unlock() +} + +// +// store the cache to file only if the storage path is set. +// +func (dict *dictionary) store() (err error) { + if len(dict.storagePath) == 0 { + return nil + } + + dict.Lock() + defer dict.Unlock() + + if len(dict.cache) == 0 { + return nil + } + + newStorage := dict.storagePath + ".new" + + f, err := os.Create(newStorage) + if err != nil { + errc := f.Close() + if errc != nil { + log.Println("dictionary: store: ", err) + } + return err + } + + enc := gob.NewEncoder(f) + err = enc.Encode(&dict.cache) + if err != nil { + errc := f.Close() + if errc != nil { + log.Println("dictionary: store: ", err) + } + return err + } + + errc := f.Close() + if errc != nil { + log.Println("dictionary: store: ", err) + } + + err = libio.Copy(dict.storagePath, newStorage) + if err != nil { + return err + } + + dict.lastSize = len(dict.cache) + + return nil +} |
