A Libre Multiplayer FPS Game built with Godot 4 engine and a fully open-source toolchain https://libla.st
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
Liblast/InfraServer/Storage.gd

147 lines
4.7 KiB

extends Node
# facilitates storing and fetching arbitrary binary data
# store deleted files away instead of deleting them
enum StorageBackend {TESTING, PRODUCTION}
var backend = StorageBackend.TESTING
var testing_path = "user://storage/"
var testing_dir : DirAccess
var testing_use_trash_can = true
var testing_trash_path = "user://storage_trash/"
var testing_trash_dir : DirAccess
# storage unit - single file in the Storage pool
class Unit:
var hash : String # hash that is both an MD5 checksum of the data, and a UUID for the storage unit
var data : PackedByteArray # actual data
var created_by : String # usrname_hash
var creation_time : float # unix time
var last_accessed_time : float # unix time
var last_accessed_by : String
var accesed_count : int # index
func string_from_hash(hash: PackedByteArray) -> String:
return Marshalls.raw_to_base64(hash)
func hash_from_string(hash: String) -> PackedByteArray:
return Marshalls.base64_to_raw(hash)
func hash_data(data: PackedByteArray) -> PackedByteArray:
var hasher = HashingContext.new()
hasher.start(HashingContext.HASH_SHA256)
hasher.update(data)
return hasher.finish()
func _ready():
if backend == StorageBackend.TESTING:
testing_dir = DirAccess.open("user://")
if testing_dir.dir_exists(testing_path) == false:
testing_dir.make_dir_recursive(testing_path)
testing_dir = DirAccess.open(testing_path)
testing_trash_dir = DirAccess.open("user://")
if testing_trash_dir.dir_exists(testing_trash_path) == false:
testing_trash_dir.make_dir_recursive(testing_trash_path)
testing_trash_dir = DirAccess.open(testing_trash_path)
func store(hash: PackedByteArray, data: PackedByteArray, created_by: String) -> int:
if backend == StorageBackend.TESTING:
var filename = string_from_hash(hash)
if testing_dir.file_exists(filename):
print("Attempting to store a unit that already exists")
return ERR_ALREADY_EXISTS
var unit = {
"hash" = Marshalls.raw_to_base64(hash),
"data" = Marshalls.raw_to_base64(data),
"created_by" = created_by,
"creation_time" = Time.get_unix_time_from_system(),
}
var file = FileAccess.open(testing_path.path_join(filename),FileAccess.WRITE)
file.store_string(var_to_str(unit))
file.flush()
var err = file.get_error()
if err == ERR_UNCONFIGURED:
print_debug("Saving file gives ERR_UNCONFIGURED, but the file seems to be written fine.")
err = OK # ignore this error
if err == OK:
prints("Storage unit created, filename:", filename)
else:
prints("Storage unit creation FAILED, filename:", filename,"; error:", error_string(err))
return err
else:
return ERR_METHOD_NOT_FOUND
func retrieve(hash: PackedByteArray, username_hash: String):
if backend == StorageBackend.TESTING:
var filename = string_from_hash(hash)
if not testing_dir.file_exists(filename):
return ERR_DOES_NOT_EXIST
var file = FileAccess.open(testing_path.plus_file(filename),FileAccess.READ)
var unit = str_to_var(file.get_as_text()) as Dictionary
prints("unit is of type:", typeof(unit))
var err = file.get_error()
if err != OK:
return err
if unit.has("accessed_count"):
unit["accessed_count"] += 1
else:
unit["accessed_count"] = 1
unit["last_accessed_by"] = username_hash
unit["last_accessed_time"] = Time.get_unix_time_from_system()
# update internal metadata
file = FileAccess.open(testing_path.plus_file(filename),FileAccess.WRITE)
file.store_string(var_to_str(unit))
err = file.get_error()
if err != OK:
prints("Storage unit retrieval FAILED, filename:", filename, "; error:", error_string(err))
return file.get_error()
else:
file.close()
prints("Storage unit retrieved, filename:", filename)
return Marshalls.base64_to_raw(unit["data"])
func delete(hash: PackedByteArray):
if backend == StorageBackend.TESTING:
var filename = string_from_hash(hash)
if not testing_dir.file_exists(filename):
prints("Trying to delete a non-existent file! Filename:", filename)
return ERR_DOES_NOT_EXIST
if testing_use_trash_can == false:
# delete file (no undo!)
var err = testing_dir.remove(filename)
if err == OK:
prints("Storage unit deleted, filename:", filename)
else:
prints("Storage unit deletion FAILED, filename:", filename, "; error:", error_string(err))
else:
# move file to trash
# remove old trashed file if the name is already taken
if testing_trash_dir.file_exists(filename):
testing_trash_dir.remove(filename)
var err = testing_dir.rename(testing_path.plus_file(filename), testing_trash_path.plus_file(filename))
if err == OK:
prints("Storage unit trashed, filename:", filename)
else:
prints("Storage unit trashing FAILED, filename:", filename, "; error:", error_string(err))