Add storage module
This commit is contained in:
parent
af37b9ef9d
commit
61eaa41fd9
4 changed files with 203 additions and 0 deletions
|
@ -21,6 +21,7 @@ Use these to access CORE's modules.
|
||||||
- `logui` (not important for developers, displays the log graphically)
|
- `logui` (not important for developers, displays the log graphically)
|
||||||
- [`sms`](/reference/sms)
|
- [`sms`](/reference/sms)
|
||||||
- [`edl`](/reference/edl)
|
- [`edl`](/reference/edl)
|
||||||
|
- [`storage`](/reference/storage)
|
||||||
|
|
||||||
## Variables
|
## Variables
|
||||||
### *String* <u>basepath</u>
|
### *String* <u>basepath</u>
|
||||||
|
|
35
docs/docs/reference/storage.md
Normal file
35
docs/docs/reference/storage.md
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
sidebar_position: 9
|
||||||
|
---
|
||||||
|
|
||||||
|
# `Storage`
|
||||||
|
Allows you to write configuration files with ease, without any headaches.
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
### *bool* <u>is_open</u>
|
||||||
|
:::danger[Do not modify]
|
||||||
|
NEVER change the value of this variable. You will break stuff with this!
|
||||||
|
:::
|
||||||
|
Indicates if a storage file is currently open.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### *bool* <u>open_storage</u>(*String* <u>location</u>, *bool* <u>create_new</u> = *true*, *bool* <u>sanity_check</U> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*)
|
||||||
|
Loads a storage file from `location` and creates a new one first if missing (`create_new`). Also performs basic sanity checking (`sanity_check`) and may throw an error on failure (`fail_on_sanity_check`).
|
||||||
|
### *bool* <u>close_storage</u>()
|
||||||
|
Closes the active storage file.
|
||||||
|
### *bool* <u>save_storage</u>()
|
||||||
|
Saves the active storage file to disk.
|
||||||
|
### *bool* <u>nuke_storage</u>(*bool* <u>autosave</u> = *true*)
|
||||||
|
Removes all keys from the active storage file. The nuclear option basically.
|
||||||
|
### *Variant* <u>get_key</u>(*String* <u>key</u>, *Variant* <u>default</u> = *null*)
|
||||||
|
Returns a storage key. Can also return a default value if unset.
|
||||||
|
### *bool* <u>set_key</u>(*String* <u>key</u>, *Variant* <u>value</u>, *bool* <u>overwrite</u> = *true*, *bool* <u>autosave</u> = *true*)
|
||||||
|
Updates a storage key with the specified value.
|
||||||
|
### *bool* <u>del_key</u>(*String* <u>key</u>, *bool* <u>autosave</u> = *true*)
|
||||||
|
Deletes a storage key.
|
||||||
|
### *Dictionary* <u>get_dict</u>()
|
||||||
|
Returns the `storage` dictionary, useful for more advanced operations. Changes are not reflected onto the `storage` dictionary though. To save changes through this module, pass your modified dictionary to [`save_dict`](#bool-save_dictdictionary-dict-bool-sanity_check--true-bool-fail_on_sanity_check--false-bool-autosave--true).
|
||||||
|
### *bool* <u>save_dict</u>(*Dictionary* <u>dict</u>, *bool* <u>sanity_check</u> = *true*, *bool* <u>fail_on_sanity_check</u> = *false*, *bool* <u>autosave</u> = *true*)
|
||||||
|
Saves a arbitrary dictionary as a `storage` dictionary with sanity checking (`sanity_check` and `fail_on_sanity_check`).
|
||||||
|
### *Array[String]* <u>perform_sanity_check</u>(*Dictionary* <u>storage_check</u>)
|
||||||
|
Performs sanity checks on a dictionary aka. checks the type of all keys and their values.
|
|
@ -41,6 +41,8 @@ var sms: CoreBaseModule
|
||||||
var logui: CoreBaseModule
|
var logui: CoreBaseModule
|
||||||
## Use this to access CORE's builtin HTTP request maker.
|
## Use this to access CORE's builtin HTTP request maker.
|
||||||
var edl: CoreBaseModule
|
var edl: CoreBaseModule
|
||||||
|
## Use this to access configuration and settings files easily.
|
||||||
|
var storage: CoreBaseModule
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
## Contains CORE's load path
|
## Contains CORE's load path
|
||||||
|
@ -82,30 +84,35 @@ func initialize_modules() -> void:
|
||||||
sms = CoreBaseModule.new()
|
sms = CoreBaseModule.new()
|
||||||
logui = CoreBaseModule.new()
|
logui = CoreBaseModule.new()
|
||||||
edl = CoreBaseModule.new()
|
edl = CoreBaseModule.new()
|
||||||
|
storage = CoreBaseModule.new()
|
||||||
# Set names
|
# Set names
|
||||||
logger.name = "Logger"
|
logger.name = "Logger"
|
||||||
misc.name = "Misc"
|
misc.name = "Misc"
|
||||||
sms.name = "SceneManagementSystem"
|
sms.name = "SceneManagementSystem"
|
||||||
logui.name = "LogUI"
|
logui.name = "LogUI"
|
||||||
edl.name = "EasyDownLoader"
|
edl.name = "EasyDownLoader"
|
||||||
|
storage.name = "Storage"
|
||||||
# Set scripts
|
# Set scripts
|
||||||
logger.set_script(ResourceLoader.load(basepath + "src/logger.gd"))
|
logger.set_script(ResourceLoader.load(basepath + "src/logger.gd"))
|
||||||
misc.set_script(ResourceLoader.load(basepath + "src/misc.gd"))
|
misc.set_script(ResourceLoader.load(basepath + "src/misc.gd"))
|
||||||
sms.set_script(ResourceLoader.load(basepath + "src/sms.gd"))
|
sms.set_script(ResourceLoader.load(basepath + "src/sms.gd"))
|
||||||
logui.set_script(ResourceLoader.load(basepath + "src/logui.gd"))
|
logui.set_script(ResourceLoader.load(basepath + "src/logui.gd"))
|
||||||
edl.set_script(ResourceLoader.load(basepath + "src/edl.gd"))
|
edl.set_script(ResourceLoader.load(basepath + "src/edl.gd"))
|
||||||
|
storage.set_script(ResourceLoader.load(basepath + "src/storage.gd"))
|
||||||
# Set reference to self
|
# Set reference to self
|
||||||
logger.core = self
|
logger.core = self
|
||||||
misc.core = self
|
misc.core = self
|
||||||
sms.core = self
|
sms.core = self
|
||||||
logui.core = self
|
logui.core = self
|
||||||
edl.core = self
|
edl.core = self
|
||||||
|
storage.core = self
|
||||||
# Call _initialize() (workaround as modules cannot access "core" during _init())
|
# Call _initialize() (workaround as modules cannot access "core" during _init())
|
||||||
logger._initialize()
|
logger._initialize()
|
||||||
misc._initialize()
|
misc._initialize()
|
||||||
sms._initialize()
|
sms._initialize()
|
||||||
logui._initialize()
|
logui._initialize()
|
||||||
edl._initialize()
|
edl._initialize()
|
||||||
|
storage._initialize()
|
||||||
|
|
||||||
# Inject modules into the SceneTree
|
# Inject modules into the SceneTree
|
||||||
## Injects CORE's builtin modules into the SceneTree.[br]
|
## Injects CORE's builtin modules into the SceneTree.[br]
|
||||||
|
@ -117,6 +124,7 @@ func inject_modules() -> void:
|
||||||
add_child(sms)
|
add_child(sms)
|
||||||
add_child(logui)
|
add_child(logui)
|
||||||
add_child(edl)
|
add_child(edl)
|
||||||
|
add_child(storage)
|
||||||
|
|
||||||
# Registers a custom module
|
# Registers a custom module
|
||||||
## Registers a new custom module.
|
## Registers a new custom module.
|
||||||
|
|
159
src/storage.gd
Normal file
159
src/storage.gd
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
# CORE FRAMEWORK SOURCE FILE
|
||||||
|
# Copyright (c) 2024 The StarOpenSource Project & Contributors
|
||||||
|
# Licensed under the GNU Affero General Public License v3
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
extends CoreBaseModule
|
||||||
|
|
||||||
|
var is_open: bool = false
|
||||||
|
var storage: Dictionary = {}
|
||||||
|
var storage_location: String = ""
|
||||||
|
|
||||||
|
func open_storage(location: String, create_new: bool = true, sanity_check: bool = true, fail_on_sanity_check: bool = false) -> bool:
|
||||||
|
if is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to open storage: A storage file is already open")
|
||||||
|
return false
|
||||||
|
logger.verbf("storage.gd", "Opening storage file at \"" + location + "\"")
|
||||||
|
var file: FileAccess
|
||||||
|
if !FileAccess.file_exists(location):
|
||||||
|
if create_new:
|
||||||
|
file = FileAccess.open(location, FileAccess.WRITE)
|
||||||
|
if file == null:
|
||||||
|
await logger.crashf("storage.gd", "Could not open storage file at \"" + location + "\": Failed with code " + str(FileAccess.get_open_error()))
|
||||||
|
return false
|
||||||
|
file.store_string("{}")
|
||||||
|
file.close()
|
||||||
|
else:
|
||||||
|
logger.errorf("storage.gd", "Failed to open storage: create_new is set to false")
|
||||||
|
return false
|
||||||
|
file = FileAccess.open(location, FileAccess.READ)
|
||||||
|
var storage_temp: Variant = file.get_as_text()
|
||||||
|
file.close()
|
||||||
|
storage_temp = JSON.parse_string(storage_temp)
|
||||||
|
if typeof(storage_temp) != TYPE_DICTIONARY:
|
||||||
|
logger.errorf("storage.gd", "Failed to open storage: Parsed storage file is of type " + str(typeof(storage_temp)))
|
||||||
|
return false
|
||||||
|
if sanity_check:
|
||||||
|
var check_result: Array[String] = perform_sanity_check(storage_temp)
|
||||||
|
if check_result.size() != 0:
|
||||||
|
if fail_on_sanity_check:
|
||||||
|
logger.errorf("storage.gd", "Sanity check failed (stopping):")
|
||||||
|
for error in check_result:
|
||||||
|
logger.errorf("storage.gd", "-> " + error)
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
logger.warnf("storage.gd", "Sanity check failed (continuing anyway):")
|
||||||
|
for error in check_result:
|
||||||
|
logger.warnf("storage.gd", "-> " + error)
|
||||||
|
storage = storage_temp
|
||||||
|
storage_location = location
|
||||||
|
is_open = true
|
||||||
|
return true
|
||||||
|
|
||||||
|
func close_storage() -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to close storage: No storage file is open")
|
||||||
|
return false
|
||||||
|
logger.verbf("storage.gd", "Closing storage file")
|
||||||
|
storage = {}
|
||||||
|
is_open = false
|
||||||
|
return true
|
||||||
|
|
||||||
|
func save_storage() -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to save storage: No storage file is open")
|
||||||
|
return false
|
||||||
|
var file: FileAccess = FileAccess.open(storage_location, FileAccess.WRITE)
|
||||||
|
if file == null:
|
||||||
|
await logger.crashf("storage.gd", "Could not open storage file at \"" + storage_location + "\": Failed with code " + str(FileAccess.get_open_error()))
|
||||||
|
return false
|
||||||
|
logger.diagf("storage.gd", "Writing storage file to disk")
|
||||||
|
file.store_string(JSON.stringify(storage))
|
||||||
|
file.close()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func nuke_storage(autosave: bool = true) -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to nuke storage: No storage file is open")
|
||||||
|
return false
|
||||||
|
logger.warnf("storage.gd", "Nuking storage")
|
||||||
|
storage = {}
|
||||||
|
if autosave: save_storage()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func get_key(key: String, default: Variant) -> Variant:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to get key: No storage file is open")
|
||||||
|
return NAN
|
||||||
|
logger.diagf("storage.gd", "Returning storage key \"" + key + "\" (default='" + default + "')")
|
||||||
|
return storage.get(key, default)
|
||||||
|
|
||||||
|
func set_key(key: String, value: Variant, overwrite: bool = true, autosave: bool = true) -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to set key: No storage file is open")
|
||||||
|
return false
|
||||||
|
logger.diagf("storage.gd", "Updating storage key \"" + key + "\" with value '" + str(value) + "' (overwrite='" + str(overwrite) + "' autosave='" + str(autosave) + "'")
|
||||||
|
storage.merge({key: value}, overwrite)
|
||||||
|
if autosave: save_storage()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func del_key(key: String, autosave: bool = true) -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errof("storage.gd", "Failed to delete key: No storage file is open")
|
||||||
|
return false
|
||||||
|
logger.diagf("storage.gd", "Deleting storage key \"" + key + "\" (autosave='" + str(autosave) + "')")
|
||||||
|
storage.erase(key)
|
||||||
|
if autosave: save_storage()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func get_dict() -> Dictionary:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to get dictionary: No storage file is open")
|
||||||
|
return {}
|
||||||
|
logger.verbf("storage.gd", "Returning storage dictionary")
|
||||||
|
return storage
|
||||||
|
|
||||||
|
func save_dict(dict: Dictionary, sanity_check: bool = true, fail_on_sanity_check: bool = false, autosave: bool = true) -> bool:
|
||||||
|
if !is_open:
|
||||||
|
logger.errorf("storage.gd", "Failed to save dictionary: No storage file is open")
|
||||||
|
return false
|
||||||
|
logger.verbf("storage.gd", "Saving custom dictionary as storage")
|
||||||
|
if sanity_check:
|
||||||
|
var check_result: Array[String] = perform_sanity_check(dict)
|
||||||
|
if check_result.size() != 0:
|
||||||
|
if fail_on_sanity_check:
|
||||||
|
logger.errorf("storage.gd", "Sanity check failed (stopping):")
|
||||||
|
for error in check_result:
|
||||||
|
logger.errorf("storage.gd", "-> " + error)
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
logger.warnf("storage.gd", "Sanity check failed (continuing anyway):")
|
||||||
|
for error in check_result:
|
||||||
|
logger.warnf("storage.gd", "-> " + error)
|
||||||
|
storage = dict
|
||||||
|
if autosave: save_storage()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func perform_sanity_check(storage_check: Dictionary) -> Array[String]:
|
||||||
|
logger.verbf("storage.gd", "Performing a sanity check on some storage dictionary")
|
||||||
|
var errors: Array[String] = []
|
||||||
|
for key in storage_check:
|
||||||
|
if typeof(key) != TYPE_STRING:
|
||||||
|
errors.append("Key \"" + str(key) + "\" is not of type String (type '" + type_string(typeof(key)) + "')")
|
||||||
|
continue
|
||||||
|
if typeof(storage_check[key]) != TYPE_NIL and typeof(storage_check[key]) != TYPE_STRING and typeof(storage_check[key]) != TYPE_INT and typeof(storage_check[key]) != TYPE_FLOAT and typeof(storage_check[key]) != TYPE_BOOL and typeof(storage_check[key]) != TYPE_ARRAY and typeof(storage_check[key]) != TYPE_DICTIONARY:
|
||||||
|
errors.append("The value of \"" + key + "\" is not null, a string, an integer, a float, boolean, array or dictionary (type '" + type_string(typeof(key)) + "')")
|
||||||
|
|
||||||
|
logger.verbf("storage.gd", "Completed sanity check with " + str(errors.size()) + " errors")
|
||||||
|
return errors
|
Loading…
Reference in a new issue