funfriend/src/configman.cr

92 lines
2.3 KiB
Crystal

require "file_utils"
require "ini"
module Funfriend::ConfigMan
extend self
APPLICATION_NAME = "funfriend"
CONFIG_NAME = "cfg.ini"
alias ConfigValue = String | Int32 | Bool | Float64
alias ConfigSection = Hash(String, ConfigValue)
alias Config = Hash(String, ConfigSection)
DEFAULT_CONFIG = {
"window" => {
"funfriend_size" => 75.as(ConfigValue)
},
"sound" => {
"volume" => 0.2.as(ConfigValue)
},
"buddies" => {
"types" => "funfriend".as(ConfigValue)
},
}.as(Config)
def get_config_path : Path
{% if flag?(:windows) %}
Path.new(ENV["APPDATA"]) / APPLICATION_NAME
{% elsif flag?(:macosx) %}
Path.home / "Library" / "Application Support" / APPLCATION_NAME
{% elsif flag?(:unix) %}
(ENV["XDG_CONFIG_HOME"]?.try { |p| Path.new(p) } || (Path.home / ".config")) / APPLICATION_NAME
{% end %}
end
@@config_initialized = false
@@config = {} of String => ConfigSection
def config
if !@@config_initialized
raise "config read before initialization"
end
@@config
end
def init
config_path = get_config_path
FileUtils.mkdir_p(config_path)
config_file = config_path / CONFIG_NAME
if !File.exists?(config_file)
@@config = DEFAULT_CONFIG.dup
File.write(config_file, INI.build(@@config))
else
parsed = INI.parse(File.read(config_file))
@@config = DEFAULT_CONFIG.dup
parsed.each do |sect_i, section|
section.each do |key, value|
# if it exists in the default config
if DEFAULT_CONFIG[sect_i]?.try &.[key]?
# try casting
casted_val = case DEFAULT_CONFIG[sect_i][key]
when String
value
when Int32
value.to_i32?
when Float64
value.to_f64?
when Bool
value === "1" || value.downcase === "true"
end
# casted_val being nil means it failed; fall back to default
if casted_val != nil
# write to config
@@config[sect_i][key] = casted_val.not_nil!
end
else
# keep as a string just incase it's ever needed
@@config[sect_i][key] = value
end
end
end
File.write(config_file, INI.build(@@config))
end
@@config_initialized = true
end
end