annotate semiconginev2/contrib/settings.nim @ 1252:01e9f41d35b1

add:support for push constants
author sam <sam@basx.dev>
date Fri, 26 Jul 2024 23:04:01 +0700
parents c8e3037aca66
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1252
01e9f41d35b1 add:support for push constants
sam <sam@basx.dev>
parents: 1226
diff changeset
1 const CONFIGHOTRELOAD {.booldefine.}: bool = not defined(release)
01e9f41d35b1 add:support for push constants
sam <sam@basx.dev>
parents: 1226
diff changeset
2 const CONFIGHOTRELOADINTERVAL {.intdefine.}: int = 1000
01e9f41d35b1 add:support for push constants
sam <sam@basx.dev>
parents: 1226
diff changeset
3 const CONFIGROOT {.strdefine.}: string = "."
01e9f41d35b1 add:support for push constants
sam <sam@basx.dev>
parents: 1226
diff changeset
4 const CONFIGEXTENSION {.strdefine.}: string = "ini"
01e9f41d35b1 add:support for push constants
sam <sam@basx.dev>
parents: 1226
diff changeset
5
1226
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
6
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
7 when CONFIGHOTRELOAD:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
8 var
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
9 configUpdates: Channel[(string, string)]
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
10 configUpdates.open()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
11
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
12 # runtime configuration
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
13 # =====================
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
14 # namespace is the path from the CONFIGROOT to the according settings file without the file extension
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
15 # a settings file must always have the extension CONFIGEXTENSION
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
16 # a fully qualified settings identifier can be in the form {namespace}.{section}.{key}
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
17 # {key} and {section} may not contain dots
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
18
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
19 # a "namespace" is the path from the settings root to an *.CONFIGEXTENSION file, without the file extension
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
20 # settings is a namespace <-> settings mapping
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
21 var allsettings: Table[string, Config]
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
22
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
23 proc configRoot(): string =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
24 joinPath(absolutePath(getAppDir()), CONFIGROOT)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
25
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
26 proc getFile(namespace: string): string =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
27 joinPath(configRoot(), namespace & "." & CONFIGEXTENSION)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
28
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
29 iterator walkConfigNamespaces(): string =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
30 for file in walkDirRec(dir = configRoot(), relative = true, checkDir = true):
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
31 if file.endsWith("." & CONFIGEXTENSION):
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
32 yield file[0 ..< ^(CONFIGEXTENSION.len + 1)]
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
33
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
34 proc loadAllConfig(): Table[string, Config] =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
35 for ns in walkConfigNamespaces():
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
36 result[ns] = ns.getFile().loadConfig()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
37
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
38 proc ReloadSettings*() =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
39 allsettings = loadAllConfig()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
40
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
41 proc configStr(key, section, namespace: string): string =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
42 when CONFIGHOTRELOAD:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
43 while configUpdates.peek() > 0:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
44 let (updatedNamespace, updatedConfig) = configUpdates.recv()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
45 allsettings[updatedNamespace] = loadConfig(newStringStream(updatedConfig))
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
46 if not allsettings.hasKey(namespace):
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
47 raise newException(Exception, &"Settings {namespace}.{section}.{key} was not found")
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
48 allsettings[namespace].getSectionValue(section, key)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
49
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
50 proc Setting*[T: int|float|string](key, section, namespace: string): T =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
51 when T is int:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
52 let value = configStr(key, section, namespace)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
53 if parseInt(value, result) == 0:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
54 raise newException(Exception, &"Unable to parse int from settings {namespace}.{section}.{key}: {value}")
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
55 elif T is float:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
56 let value = configStr(key, section, namespace)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
57 if parseFloat(value, result) == 0:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
58 raise newException(Exception, &"Unable to parse float from settings {namespace}.{section}.{key}: {value}")
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
59 else:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
60 result = configStr(key, section, namespace)
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
61
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
62 proc Setting*[T: int|float|string](identifier: string): T =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
63 # identifier can be in the form:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
64 # {namespace}.{key}
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
65 # {namespace}.{section}.{key}
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
66 let parts = identifier.rsplit(".")
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
67 if parts.len == 1:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
68 raise newException(Exception, &"Setting with name {identifier} has no namespace")
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
69 if parts.len == 2: result = Setting[T](parts[1], "", parts[0])
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
70 else: result = Setting[T](parts[^1], parts[^2], joinPath(parts[0 .. ^3]))
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
71
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
72 proc HadConfigUpdate*(): bool =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
73 when CONFIGHOTRELOAD == true:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
74 result = configUpdates.peek() > 0
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
75
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
76 allsettings = loadAllConfig()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
77
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
78 when CONFIGHOTRELOAD == true:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
79 proc configFileWatchdog() {.thread.} =
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
80 var configModTimes: Table[string, times.Time]
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
81 while true:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
82 for namespace in walkConfigNamespaces():
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
83 if not (namespace in configModTimes):
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
84 configModTimes[namespace] = times.Time()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
85 let lastMod = namespace.getFile().getLastModificationTime()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
86 if lastMod > configModTimes[namespace]:
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
87 configModTimes[namespace] = lastMod
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
88 let configStr = newFileStream(namespace.getFile()).readAll()
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
89 configUpdates.send((namespace, configStr))
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
90 sleep CONFIGHOTRELOADINTERVAL
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
91 var thethread: Thread[void]
c8e3037aca66 add: contrib stuff
sam <sam@basx.dev>
parents:
diff changeset
92 createThread(thethread, configFileWatchdog)