crystal-gauntlet/src/crystal-gauntlet.cr

225 lines
5.3 KiB
Crystal

require "http/server"
require "http/server/handler"
require "uri"
require "sqlite3"
require "migrate"
require "dotenv"
require "toml"
require "colorize"
require "option_parser"
require "migrate"
require "./server"
require "./enums"
require "./lib/hash"
require "./lib/format"
require "./lib/xor"
require "./lib/accounts"
require "./lib/gjp"
require "./lib/clean"
require "./lib/songs"
require "./lib/ids"
require "./lib/level"
require "./lib/dailies"
require "./lib/templates"
require "./lib/reupload"
require "./lib/creator_points"
require "./lib/versions"
require "./lib/ips"
require "./lib/ranks"
require "./lib/notifications"
require "./patch-exe.cr"
if File.exists?(".env")
Dotenv.load
end
include CrystalGauntlet::PatchExe
module CrystalGauntlet
VERSION = "0.1.0"
CONFIG = File.exists?("./config.toml") ? TOML.parse(File.read("./config.toml")) : TOML.parse("") # todo: log warning?
LOG = ::Log.for("crystal-gauntlet")
def config_get(key : String)
this = CONFIG
key.split(".").each do |val|
next_val = this.as(Hash)[val]?
if next_val == nil
return nil
else
this = next_val
end
end
return this
end
def config_get(key : String, default)
config_get(key).as?(typeof(default)) || default
end
DATABASE = DB.open(ENV["DATABASE_URL"]? || "sqlite3://./crystal-gauntlet.db")
# todo: unhardcore
DATA_FOLDER = Path.new("data")
@@endpoints = Hash(String, (HTTP::Server::Context -> String)).new
@@template_endpoints = Hash(
NamedTuple(name: String, path: String, methods: Enumerable(String)),
Proc(HTTP::Server::Context, Hash(String, String?), Nil)
).new
@@up_at = nil
def self.uptime
if !@@up_at
return Time::Span::ZERO
else
return Time.utc - @@up_at.not_nil!
end
end
def self.uptime_s
span = uptime
Format.fmt_timespan_long(span)
end
def self.endpoints
@@endpoints
end
def self.template_endpoints
@@template_endpoints
end
def self.is_funny
config_get("general.easter_eggs", false)
end
def severity_color(severity : Log::Severity) : Colorize::Object
case severity
when .trace?
Colorize.with.dark_gray
when .debug?
Colorize.with.dark_gray
when .info?
Colorize.with.cyan
when .notice?
Colorize.with.cyan
when .warn?
Colorize.with.yellow
when .error?
Colorize.with.red
when .fatal?
Colorize.with.light_red
else
Colorize.with.white
end
end
struct CrystalGauntletFormat < Log::StaticFormatter
def run
Colorize.with.light_gray.dim.surround(@io) do
timestamp
end
string " "
severity_color(@entry.severity).surround(@io) do
@entry.severity.label.rjust(@io, 6)
end
string " "
Colorize.with.white.surround(@io) do
source
end
string " "
message
end
end
def self.run()
Log.setup_from_env(backend: Log::IOBackend.new(formatter: CrystalGauntletFormat))
migrate = false
calc_creator_points = false
patch_exe = false
patch_exe_location = nil
patch_exe_package = nil
parser = OptionParser.new do |parser|
parser.banner = "Usage: crystal-gauntlet [command] [arguments]"
parser.on("migrate", "Migrate the database") do
migrate = true
parser.banner = "Usage: crystal-gauntlet migrate [arguments]"
end
parser.on("calc_creator_points", "Calculate creator points and update them") do
calc_creator_points = true
parser.banner = "Usage: crystal-gauntlet calc_creator_points [arguments]"
end
parser.on("patch_exe", "Patch Geometry Dash executables with your server URL (supports #{SUPPORTED_PATCH_PLATFORMS.join(", ")})") do
patch_exe = true
parser.banner = "Usage: crystal-gauntlet patch_exe <file>"
parser.on("-p NAME", "--package=NAME", "Specify the new package name") { |name| patch_exe_package = name }
parser.unknown_args do |opt|
patch_exe_location = opt[0]?
end
end
parser.on("-h", "--help", "Show this help") do
puts parser
exit
end
end
parser.parse
if patch_exe
if !patch_exe_location
puts parser
exit 1
end
check_server_length(true)
LOG.info { "Patching #{patch_exe_location}" }
patch_exe_file(patch_exe_location.not_nil!, patch_exe_package)
exit
end
migrator = Migrate::Migrator.new(
DATABASE
)
if migrate
LOG.info { "Migrating #{ENV["DATABASE_URL"].colorize(:white)}..." }
migrator.to_latest
exit
end
if calc_creator_points
LOG.info { "updating creator points" }
DATABASE.query_all("select id, username, creator_points from users", as: {Int32, String, Int32}).each() do |id, username, old_count|
new_count = CreatorPoints.update_creator_points id
if old_count > 0 || new_count > 0
LOG.info { "#{username}: #{old_count} -> #{new_count}" }
end
end
exit
end
if !migrator.latest?
LOG.fatal { "Database hasn\'t been migrated!! Please run #{"crystal-gauntlet migrate".colorize(:white)}" }
exit 1
end
["songs", "levels", "saves"].each() { |v|
Dir.mkdir_p(DATA_FOLDER / v)
}
Server.run()
end
end
require "./endpoints/**"
require "./template_endpoints/**"
CrystalGauntlet.run()