Skip to content

Understanding UserData #5

@RedFlames

Description

@RedFlames

ok alright so

UserData:

  • entirely abstract

methods related to "files"

methods related to raw "data" files

methods about user info?

  • string GetUID(string key);
  • string GetKey(string uid);
  • string Create(string uid, bool forceNewKey);
  • void RevokeKey(string key);
  • int GetRegisteredCount();
  • int GetAllCount();
  • string[] GetRegistered();
  • string[] GetAll();
  • T[] LoadRegistered<T>() where T : new();
  • T[] LoadAll<T>() where T : new();

FileSystemUserData:

Basics

  • all files are under Server.Settings.UserDataRoot, e.g. ./UserData/
    • string UserRoot => ... = ./UserData/User
    • string GlobalPath => ...= ./UserData/Global.yaml
  • Global.yaml only contains a Yaml-serialized FileSystemUserData.Global
    • which is a class with a Dictionary<string, string> UIDs
    • maps users' "key" => "UID"

Basic path/file related stuff

Examples for UID 12345:

  • string GetUserDir(string uid) => ./UserData/User/12345
  • static string GetDataFileName(Type type) => Celeste.Mod.CelesteNet.Server.BanInfo.yaml
  • string GetUserDataFilePath(string uid, Type type)
    • => ./UserData/User/12345/Celeste.Mod.CelesteNet.Server.BanInfo.yaml (?)
  • string GetUserDataFilePath(string uid, string name) => ./UserData/User/12345/name.yaml
  • string GetUserFilePath(string uid, string name) => ./UserData/User/12345/data/name

implementations of user info related stuff:

  • string GetUID(string key)
    • => tries to get UID for key from Global.yaml's UIDs dict, otherwise empty string
  • string GetKey(string uid)
    • => Load<PrivateUserInfo>(uid).Key;
  • string Create(string uid, bool forceNewKey)
    • load Global
    • check GetKey(uid) and if no forceNew, just return this key (loading global was pointless then)
    • generate new GUID as keyFull with no dashes, take first 16 chars as key
    • repeat while generated key already exists in Global.UIDs
    • Save(uid, new PrivateUserInfo { Key = key, KeyFull = keyFull });
    • save Global back to yaml
  • void RevokeKey(string key)
    • load Global
    • if key is in UIDs, remove it, save Global again, Delete<PrivateUserInfo>(uid);
  • int GetRegisteredCount()
    • => LoadRaw<Global>(GlobalPath).UIDs.Count;
  • int GetAllCount()
    • => Directory.GetDirectories(UserRoot).Length;
  • string[] GetRegistered()
    • => LoadRaw<Global>(GlobalPath).UIDs.Values.ToArray();
  • string[] GetAll()
    • => Directory.GetDirectories(UserRoot).Select(name => Path.GetFileName(name)).ToArray();
  • T[] LoadRegistered<T>()
    • => LoadRaw<Global>(GlobalPath).UIDs.Values.Select(uid => Load<T>(uid)).ToArray();
  • T[] LoadAll<T>()
    • => Directory.GetDirectories(UserRoot).Select(dir => LoadRaw<T>(Path.Combine(dir, GetDataFileName(typeof(T))))).ToArray();
  • void Insert(string uid, string key, string keyFull, bool registered)
    • only used by CopyTo in each UserData implementation /shrug

Raw (aren't overrides)

  • T LoadRaw<T>(string path)
    • => TryLoadRaw(path, out T value) ? value : value;
  • bool TryLoadRaw<T>(string path, out T value)
    • out new T() and return false if path no exist
    • otherwise open file and deserialize to T with YamlHelper
    • out that or new() if was null, return true
  • void SaveRaw<T>(string path, T data)
    • create path if it don't exist
    • serialize T into path+".tmp"
    • afterwards delete actual path and move tmp to path
  • void DeleteRaw(string path)
    • delete file at path if exists
  • void DeleteRawAll(string path)
    • delete directory at path if exists

UserDataFile (i.e. yamls...) methods:

  • bool TryLoad<T>(string uid, out T value)
  • void Save<T>(string uid, T value)
    • => SaveRaw(GetUserDataFilePath(uid, typeof(T)), value);
  • void Delete<T>(string uid)
  • void InsertData(string uid, string name, Type? type, Stream stream)
    • only used by CopyTo in each UserData implementation /shrug
    • uses private void InsertFileRaw

UserFile (i.e. raw under "data"...) methods:

  • bool HasFile(string uid, string name)
    • the implementation suggests this should be a "UserDataFile" thing but I'm 95% sure the implementation of this is simply wrong broken and should be using GetUserFilePath instead of GetUserDataFilePath
  • Stream? ReadFile(string uid, string name)
  • Stream WriteFile(string uid, string name)
  • void DeleteFile(string uid, string name)
  • void InsertFile(string uid, string name, Stream stream)
    • only used by CopyTo in each UserData implementation /shrug
    • uses private void InsertFileRaw

other:

  • private void CheckCleanup(string uid)
    • used to remove empty dirs after deleting files
  • void Wipe(string uid)
    • literally just DeleteRawAll(GetUserDir(uid));
  • void CopyTo(UserData other)
    • /shrug
  • private void InsertFileRaw(string path, Stream stream)
    • only used by InsertData and InsertFile which are used by CopyTo(UserData)

Observations:

  • Just about any UID can have a user directory for itself
  • Only registered users set up with a key by Create() will be in Global.UIDs and have a PrivateUserInfo

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions