Mercurial > games > semicongine
view semicongine/storage.nim @ 1097:bc3efccc2bf4
tmp: move stuff to notebook
author | sam <sam@basx.dev> |
---|---|
date | Sun, 07 Apr 2024 20:12:52 +0700 |
parents | 9809bd9e2cdb |
children | 3e0116b5d2ed |
line wrap: on
line source
import std/marshal import std/tables import std/strformat import std/paths import std/os import db_connector/db_sqlite import ./core const STORAGE_NAME = Path("storage.db") const KEY_VALUE_TABLE_NAME = "shelf" type StorageType* = enum SystemStorage UserStorage # ? level storage type ? var db: Table[StorageType, DbConn] proc path(storageType: StorageType): Path = case storageType: of SystemStorage: Path(getAppDir()) / STORAGE_NAME of UserStorage: string(Path(getDataDir()) / Path(AppName())).createDir() Path(getDataDir()) / Path(AppName()) / STORAGE_NAME proc setup(storageType: StorageType) = if storageType in db: return db[storageType] = open(string(storageType.path), "", "", "") db[storageType].exec(sql(&"""CREATE TABLE IF NOT EXISTS {KEY_VALUE_TABLE_NAME} ( key TEXT NOT NULL UNIQUE, value TEXT NOT NULL )""")) proc storeInDb[T](db: DbConn, key: string, value: T) = const KEY_VALUE_TABLE_NAME = "shelf" db.exec(sql(&"""INSERT INTO {KEY_VALUE_TABLE_NAME} VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value """), key, $$value) proc loadFromDb[T](db: DbConn, key: string, default = default(T)): T = const KEY_VALUE_TABLE_NAME = "shelf" let dbResult = db.getValue(sql(&"""SELECT value FROM {KEY_VALUE_TABLE_NAME} WHERE key = ? """), key) if dbResult == "": return default return to[T](dbResult) proc purge*(storageType: StorageType) = storageType.path().string.removeFile() # mini async API # # LOADING ######################################3333 # # type LoadFuture*[T] = object thread: Thread[(DbConn, string, ptr Channel[T])] channel: ptr Channel[T] result: T proc cleanup*[T](p: var LoadFuture[T]) = if p.channel != nil: p.thread.joinThread() p.channel[].close() deallocShared(p.channel) p.channel = nil proc awaitResult*[T](p: var LoadFuture[T]): T = if p.channel == nil: return p.result result = p.channel[].recv() p.result = result p.cleanup() proc hasResult*[T](p: var LoadFuture[T]): bool = let ret = p.channel[].tryRecv() result = ret.dataAvailable if result: p.result = ret.msg p.cleanup() proc getResult*[T](p: LoadFuture[T]): T = assert p.channel == nil, "Result is not available yet" return p.result proc loadWorker[T](params: (DbConn, string, ptr Channel[T])) {.thread.} = let ret = loadFromDb[T](params[0], params[1]) params[2][].send(ret) proc load*[T](storageType: StorageType, key: string): LoadFuture[T] = storageType.setup() result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) result.channel[].open() createThread(result.thread, loadWorker[T], (db[storageType], key, result.channel)) # STORING ######################################3333 # type StoreFuture*[T] = object # thread: Thread[(DbConn, string, ptr Channel[T], ptr Channel[bool])] thread: Thread[void] channel: ptr Channel[T] doneChannel: ptr Channel[bool] proc cleanup*[T](p: var StoreFuture[T]) = if p.channel != nil: p.thread.joinThread() p.channel[].close() p.doneChannel[].close() deallocShared(p.channel) deallocShared(p.doneChannel) p.channel = nil p.doneChannel = nil proc awaitStored*[T](p: var StoreFuture[T]) = discard p.doneChannel[].recv() p.cleanup() proc isStored*[T](p: var StoreFuture[T]): bool = let ret = p.doneChannel[].tryRecv() result = ret.dataAvailable if ret.dataAvailable: p.cleanup() # proc storeWorker[T](params: (DbConn, string, ptr Channel[T], ptr Channel[bool])) {.thread.} = # storeInDb(params[0], params[1], params[2][].recv()) # params[3][].send(true) # proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T] = # storageType.setup() # result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) # result.channel[].open() # result.doneChannel = cast[ptr Channel[bool]](allocShared0(sizeof(Channel[bool]))) # result.doneChannel[].open() # createThread(result.thread, storeWorker[T], (db[storageType], key, result.channel, result.doneChannel)) # createThread(result.thread, storeWorker) # result.channel[].send(value) proc storeWorker() {.thread.} = echo "storeWorker" proc store*() = var thread: Thread[void] createThread(thread, storeWorker)