migrate to athena for web routing
This commit is contained in:
parent
7e2dbd2917
commit
543a959829
|
@ -1,5 +1,9 @@
|
||||||
version: 2.0
|
version: 2.0
|
||||||
shards:
|
shards:
|
||||||
|
athena-routing:
|
||||||
|
git: https://github.com/athena-framework/routing.git
|
||||||
|
version: 0.1.6
|
||||||
|
|
||||||
db:
|
db:
|
||||||
git: https://github.com/crystal-lang/crystal-db.git
|
git: https://github.com/crystal-lang/crystal-db.git
|
||||||
version: 0.11.0
|
version: 0.11.0
|
||||||
|
|
|
@ -23,6 +23,9 @@ dependencies:
|
||||||
branch: master
|
branch: master
|
||||||
http-session:
|
http-session:
|
||||||
github: straight-shoota/http-session
|
github: straight-shoota/http-session
|
||||||
|
athena-routing:
|
||||||
|
github: athena-framework/routing
|
||||||
|
version: ~> 0.1.0
|
||||||
|
|
||||||
crystal: 1.6.2
|
crystal: 1.6.2
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ require "colorize"
|
||||||
require "option_parser"
|
require "option_parser"
|
||||||
require "migrate"
|
require "migrate"
|
||||||
|
|
||||||
|
require "./server"
|
||||||
require "./enums"
|
require "./enums"
|
||||||
require "./lib/hash"
|
require "./lib/hash"
|
||||||
require "./lib/format"
|
require "./lib/format"
|
||||||
|
@ -64,7 +65,10 @@ module CrystalGauntlet
|
||||||
DATA_FOLDER = Path.new("data")
|
DATA_FOLDER = Path.new("data")
|
||||||
|
|
||||||
@@endpoints = Hash(String, (HTTP::Server::Context -> String)).new
|
@@endpoints = Hash(String, (HTTP::Server::Context -> String)).new
|
||||||
@@template_endpoints = Hash(String, (HTTP::Server::Context -> Nil)).new
|
@@template_endpoints = Hash(
|
||||||
|
NamedTuple(name: String, path: String, methods: Enumerable(String)),
|
||||||
|
Proc(HTTP::Server::Context, Hash(String, String?), Nil)
|
||||||
|
).new
|
||||||
|
|
||||||
@@up_at = nil
|
@@up_at = nil
|
||||||
|
|
||||||
|
@ -132,90 +136,6 @@ module CrystalGauntlet
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class GDHandler
|
|
||||||
include HTTP::Handler
|
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
|
||||||
# expunge trailing slashes
|
|
||||||
path = context.request.path.chomp("/")
|
|
||||||
|
|
||||||
path = path.sub(config_get("general.append_path").as(String | Nil) || "", "")
|
|
||||||
|
|
||||||
body = context.request.body
|
|
||||||
|
|
||||||
if CrystalGauntlet.endpoints.has_key?(path) && context.request.method == "POST" && body
|
|
||||||
func = CrystalGauntlet.endpoints[path]
|
|
||||||
begin
|
|
||||||
value = func.call(context)
|
|
||||||
rescue err
|
|
||||||
LOG.error { "error while handling #{path.colorize(:white)}:" }
|
|
||||||
LOG.error { err.to_s }
|
|
||||||
is_relevant = true
|
|
||||||
err.backtrace.each do |str|
|
|
||||||
# this is a hack. Oh well
|
|
||||||
if str.starts_with?("src/crystal-gauntlet.cr") || (!is_relevant)
|
|
||||||
is_relevant = false
|
|
||||||
else
|
|
||||||
LOG.error {" #{str}"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
context.response.content_type = "text/plain"
|
|
||||||
context.response.respond_with_status(500, "-1")
|
|
||||||
else
|
|
||||||
max_size = 2048
|
|
||||||
|
|
||||||
value_displayed = value
|
|
||||||
if value.size > max_size
|
|
||||||
value_displayed = value[0..max_size] + ("…".colorize(:dark_gray).to_s)
|
|
||||||
end
|
|
||||||
LOG.debug { "-> ".colorize(:green).to_s + value_displayed }
|
|
||||||
|
|
||||||
context.response.content_type = "text/plain"
|
|
||||||
# to let endpoints manually write to IO
|
|
||||||
if value != ""
|
|
||||||
context.response.print value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
call_next(context)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class TemplateHandler
|
|
||||||
include HTTP::Handler
|
|
||||||
|
|
||||||
def call(context : HTTP::Server::Context)
|
|
||||||
# expunge trailing slashes
|
|
||||||
path = context.request.path.chomp("/")
|
|
||||||
|
|
||||||
body = context.request.body
|
|
||||||
|
|
||||||
if CrystalGauntlet.template_endpoints.has_key?(path)
|
|
||||||
func = CrystalGauntlet.template_endpoints[path]
|
|
||||||
begin
|
|
||||||
func.call(context)
|
|
||||||
rescue err
|
|
||||||
LOG.error { "error while handling #{path.colorize(:white)}:" }
|
|
||||||
LOG.error { err.to_s }
|
|
||||||
is_relevant = true
|
|
||||||
err.backtrace.each do |str|
|
|
||||||
# this is a hack. Oh well
|
|
||||||
if str.starts_with?("src/crystal-gauntlet.cr") || (!is_relevant)
|
|
||||||
is_relevant = false
|
|
||||||
else
|
|
||||||
LOG.error {" #{str}"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
context.response.content_type = "text/html"
|
|
||||||
context.response.respond_with_status(500, "Internal server error occurred, sorry about that")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
call_next(context)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.run()
|
def self.run()
|
||||||
Log.setup_from_env(backend: Log::IOBackend.new(formatter: CrystalGauntletFormat))
|
Log.setup_from_env(backend: Log::IOBackend.new(formatter: CrystalGauntletFormat))
|
||||||
|
|
||||||
|
@ -294,31 +214,7 @@ module CrystalGauntlet
|
||||||
Dir.mkdir_p(DATA_FOLDER / v)
|
Dir.mkdir_p(DATA_FOLDER / v)
|
||||||
}
|
}
|
||||||
|
|
||||||
server = HTTP::Server.new([
|
Server.run()
|
||||||
HTTP::LogHandler.new,
|
|
||||||
HTTP::StaticFileHandler.new("public/", fallthrough: true, directory_listing: false),
|
|
||||||
HTTP::StaticFileHandler.new((DATA_FOLDER / "songs").to_s, fallthrough: true, directory_listing: false),
|
|
||||||
CrystalGauntlet::GDHandler.new,
|
|
||||||
CrystalGauntlet::TemplateHandler.new
|
|
||||||
])
|
|
||||||
|
|
||||||
listen_on = URI.parse(ENV["LISTEN_ON"]? || "http://localhost:8080").normalize
|
|
||||||
|
|
||||||
case listen_on.scheme
|
|
||||||
when "http"
|
|
||||||
server.bind_tcp(listen_on.hostname.not_nil!, listen_on.port.not_nil!)
|
|
||||||
when "unix"
|
|
||||||
server.bind_unix(listen_on.to_s.sub("unix://",""))
|
|
||||||
end
|
|
||||||
|
|
||||||
check_server_length(false)
|
|
||||||
|
|
||||||
Reupload.init()
|
|
||||||
Ranks.init()
|
|
||||||
|
|
||||||
@@up_at = Time.utc
|
|
||||||
LOG.notice { "Listening on #{listen_on.to_s.colorize(:white)}" }
|
|
||||||
server.listen
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
require "athena-routing"
|
||||||
|
|
||||||
|
module CrystalGauntlet::Server
|
||||||
|
class GDHandler
|
||||||
|
include HTTP::Handler
|
||||||
|
|
||||||
|
def call(context : HTTP::Server::Context)
|
||||||
|
# expunge trailing slashes
|
||||||
|
path = context.request.path.chomp("/")
|
||||||
|
|
||||||
|
path = path.sub(config_get("general.append_path").as(String | Nil) || "", "")
|
||||||
|
|
||||||
|
body = context.request.body
|
||||||
|
|
||||||
|
if CrystalGauntlet.endpoints.has_key?(path) && context.request.method == "POST" && body
|
||||||
|
func = CrystalGauntlet.endpoints[path]
|
||||||
|
begin
|
||||||
|
value = func.call(context)
|
||||||
|
rescue err
|
||||||
|
LOG.error { "error while handling #{path.colorize(:white)}:" }
|
||||||
|
LOG.error { err.to_s }
|
||||||
|
is_relevant = true
|
||||||
|
err.backtrace.each do |str|
|
||||||
|
# this is a hack. Oh well
|
||||||
|
if str.starts_with?("src/crystal-gauntlet.cr") || (!is_relevant)
|
||||||
|
is_relevant = false
|
||||||
|
else
|
||||||
|
LOG.error {" #{str}"}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context.response.content_type = "text/plain"
|
||||||
|
context.response.respond_with_status(500, "-1")
|
||||||
|
else
|
||||||
|
max_size = 2048
|
||||||
|
|
||||||
|
value_displayed = value
|
||||||
|
if value.size > max_size
|
||||||
|
value_displayed = value[0..max_size] + ("…".colorize(:dark_gray).to_s)
|
||||||
|
end
|
||||||
|
LOG.debug { "-> ".colorize(:green).to_s + value_displayed }
|
||||||
|
|
||||||
|
context.response.content_type = "text/plain"
|
||||||
|
# to let endpoints manually write to IO
|
||||||
|
if value != ""
|
||||||
|
context.response.print value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
call_next(context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.run()
|
||||||
|
template_handler = ART::RoutingHandler.new
|
||||||
|
|
||||||
|
CrystalGauntlet.template_endpoints.each do |key, handler|
|
||||||
|
template_handler.add(
|
||||||
|
key[:name],
|
||||||
|
ART::Route.new(
|
||||||
|
key[:path],
|
||||||
|
methods: key[:methods]
|
||||||
|
)
|
||||||
|
) { |ctx, params| handler.call(ctx, params) }
|
||||||
|
end
|
||||||
|
|
||||||
|
server = HTTP::Server.new([
|
||||||
|
HTTP::LogHandler.new,
|
||||||
|
HTTP::StaticFileHandler.new("public/", fallthrough: true, directory_listing: false),
|
||||||
|
HTTP::StaticFileHandler.new((DATA_FOLDER / "songs").to_s, fallthrough: true, directory_listing: false),
|
||||||
|
GDHandler.new,
|
||||||
|
template_handler.compile
|
||||||
|
])
|
||||||
|
|
||||||
|
listen_on = URI.parse(ENV["LISTEN_ON"]? || "http://localhost:8080").normalize
|
||||||
|
|
||||||
|
case listen_on.scheme
|
||||||
|
when "http"
|
||||||
|
server.bind_tcp(listen_on.hostname.not_nil!, listen_on.port.not_nil!)
|
||||||
|
when "unix"
|
||||||
|
server.bind_unix(listen_on.to_s.sub("unix://",""))
|
||||||
|
end
|
||||||
|
|
||||||
|
check_server_length(false)
|
||||||
|
|
||||||
|
Reupload.init()
|
||||||
|
Ranks.init()
|
||||||
|
|
||||||
|
@@up_at = Time.utc
|
||||||
|
LOG.notice { "Listening on #{listen_on.to_s.colorize(:white)}" }
|
||||||
|
server.listen
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,11 +1,19 @@
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/#{config_get("general.append_path").as(String | Nil) || ""}accounts/accountManagement.php"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "account_management_redirect",
|
||||||
|
path: "/#{config_get("general.append_path").as(String | Nil) || ""}accounts/accountManagement.php",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.headers.add("Location", "/accounts/")
|
context.response.headers.add("Location", "/accounts/")
|
||||||
context.response.status = HTTP::Status::MOVED_PERMANENTLY
|
context.response.status = HTTP::Status::MOVED_PERMANENTLY
|
||||||
}
|
}
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/accounts"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "account_management",
|
||||||
|
path: "/accounts",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
account_id = nil
|
account_id = nil
|
||||||
|
|
|
@ -2,7 +2,12 @@ require "uri"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/accounts/settings"] = ->(context : HTTP::Server::Context) {
|
|
||||||
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "account_settings",
|
||||||
|
path: "/accounts/settings",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
account_id = nil
|
account_id = nil
|
||||||
|
|
|
@ -3,7 +3,11 @@ require "compress/gzip"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools/create_session"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "create_session",
|
||||||
|
path: "/tools/create_session",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
disabled = !config_get("sessions.allow").as(Bool | Nil)
|
disabled = !config_get("sessions.allow").as(Bool | Nil)
|
||||||
result = nil
|
result = nil
|
||||||
body = context.request.body
|
body = context.request.body
|
||||||
|
|
|
@ -2,12 +2,21 @@ require "ecr"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "tools_redirect",
|
||||||
|
path: "/tools",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.headers.add("Location", "/")
|
context.response.headers.add("Location", "/")
|
||||||
context.response.status = HTTP::Status::TEMPORARY_REDIRECT
|
context.response.status = HTTP::Status::TEMPORARY_REDIRECT
|
||||||
}
|
}
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints[""] = ->(context : HTTP::Server::Context) {
|
|
||||||
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "index",
|
||||||
|
path: "/",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
ECR.embed("./public/template/index.ecr", context.response)
|
ECR.embed("./public/template/index.ecr", context.response)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,11 @@ include CrystalGauntlet
|
||||||
|
|
||||||
levels_per_page = 10
|
levels_per_page = 10
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools/levels"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "list_levels",
|
||||||
|
path: "/tools/levels",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
page = (context.request.query_params["page"]? || "0").to_i? || 0
|
page = (context.request.query_params["page"]? || "0").to_i? || 0
|
||||||
total_levels = DATABASE.scalar("select count(*) from levels").as(Int64)
|
total_levels = DATABASE.scalar("select count(*) from levels").as(Int64)
|
||||||
|
|
|
@ -3,7 +3,11 @@ require "http-session"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/login"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "login",
|
||||||
|
path: "/login",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
if session = CrystalGauntlet.sessions.get(context)
|
if session = CrystalGauntlet.sessions.get(context)
|
||||||
logged_in = true
|
logged_in = true
|
||||||
account_id = session.account_id
|
account_id = session.account_id
|
||||||
|
|
|
@ -3,12 +3,11 @@ require "http-session"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/accounts/logout"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
if context.request.method != "POST"
|
name: "logout",
|
||||||
context.response.respond_with_status 405
|
path: "/accounts/logout",
|
||||||
return
|
methods: ["post"]
|
||||||
end
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
|
|
||||||
CrystalGauntlet.sessions.delete(context)
|
CrystalGauntlet.sessions.delete(context)
|
||||||
|
|
||||||
context.response.headers.add("Location", "/")
|
context.response.headers.add("Location", "/")
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/accounts/notifications"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "account_notifications",
|
||||||
|
path: "/accounts/notifications",
|
||||||
|
methods: ["get"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
account_id = nil
|
account_id = nil
|
||||||
|
|
|
@ -3,7 +3,11 @@ require "xml"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools/reupload"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "reupload",
|
||||||
|
path: "/tools/reupload",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
disabled = !(config_get("reuploads.allowed").as?(Bool))
|
disabled = !(config_get("reuploads.allowed").as?(Bool))
|
||||||
|
|
|
@ -2,7 +2,11 @@ require "ecr"
|
||||||
|
|
||||||
include CrystalGauntlet
|
include CrystalGauntlet
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools/song_search"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "song_search",
|
||||||
|
path: "/tools/song_search",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
error = nil
|
error = nil
|
||||||
|
|
|
@ -17,7 +17,11 @@ def get_next_song_id() : Int32
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
CrystalGauntlet.template_endpoints["/tools/song_upload"] = ->(context : HTTP::Server::Context) {
|
CrystalGauntlet.template_endpoints[{
|
||||||
|
name: "song_upload",
|
||||||
|
path: "/tools/song_upload",
|
||||||
|
methods: ["get", "post"]
|
||||||
|
}] = ->(context : HTTP::Server::Context, params : Hash(String, String?)) {
|
||||||
context.response.content_type = "text/html"
|
context.response.content_type = "text/html"
|
||||||
|
|
||||||
disabled = !(config_get("songs.allow_custom_songs").as?(Bool))
|
disabled = !(config_get("songs.allow_custom_songs").as?(Bool))
|
||||||
|
|
Loading…
Reference in New Issue