mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-03 03:15:31 -04:00
- use logger
This commit is contained in:
parent
bb936b1fa6
commit
7168c6bfb2
@ -3,9 +3,7 @@ require "./storage"
|
|||||||
require "./util"
|
require "./util"
|
||||||
|
|
||||||
class AuthHandler < Kemal::Handler
|
class AuthHandler < Kemal::Handler
|
||||||
property storage : Storage
|
def initialize(@storage : Storage)
|
||||||
|
|
||||||
def initialize(@storage)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
@ -18,7 +16,7 @@ class AuthHandler < Kemal::Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
if request_path_startswith env, ["/admin", "/api/admin"]
|
if request_path_startswith env, ["/admin", "/api/admin"]
|
||||||
unless storage.verify_admin cookie.value
|
unless @storage.verify_admin cookie.value
|
||||||
env.response.status_code = 403
|
env.response.status_code = 403
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -4,17 +4,22 @@ class Config
|
|||||||
include YAML::Serializable
|
include YAML::Serializable
|
||||||
|
|
||||||
@[YAML::Field(key: "port")]
|
@[YAML::Field(key: "port")]
|
||||||
property port = 9000
|
property port : Int32 = 9000
|
||||||
|
|
||||||
@[YAML::Field(key: "library_path")]
|
@[YAML::Field(key: "library_path")]
|
||||||
property library_path = File.expand_path "~/mango/library", home: true
|
property library_path : String = \
|
||||||
|
File.expand_path "~/mango/library", home: true
|
||||||
|
|
||||||
@[YAML::Field(key: "db_path")]
|
@[YAML::Field(key: "db_path")]
|
||||||
property db_path = File.expand_path "~/mango/mango.db", home: true
|
property db_path : String = \
|
||||||
|
File.expand_path "~/mango/mango.db", home: true
|
||||||
|
|
||||||
@[YAML::Field(key: "scan_interval_minutes")]
|
@[YAML::Field(key: "scan_interval_minutes")]
|
||||||
property scan_interval : Int32 = 5
|
property scan_interval : Int32 = 5
|
||||||
|
|
||||||
|
@[YAML::Field(key: "log_level")]
|
||||||
|
property log_level : String = "info"
|
||||||
|
|
||||||
def self.load
|
def self.load
|
||||||
cfg_path = File.expand_path "~/.config/mango/config.yml", home: true
|
cfg_path = File.expand_path "~/.config/mango/config.yml", home: true
|
||||||
if File.exists? cfg_path
|
if File.exists? cfg_path
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
require "./config"
|
require "./config"
|
||||||
require "./library"
|
require "./library"
|
||||||
require "./storage"
|
require "./storage"
|
||||||
require "logger"
|
require "./logger"
|
||||||
|
|
||||||
class Context
|
class Context
|
||||||
property config : Config
|
property config : Config
|
||||||
property library : Library
|
property library : Library
|
||||||
property storage : Storage
|
property storage : Storage
|
||||||
|
property logger : MLogger
|
||||||
|
|
||||||
def initialize
|
def initialize(@config, @logger, @library, @storage)
|
||||||
@config = Config.load
|
|
||||||
@library = Library.new @config.library_path, @config.scan_interval
|
|
||||||
@storage = Storage.new @config.db_path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
{% for lvl in LEVELS %}
|
||||||
|
def {{lvl.id}}(msg)
|
||||||
|
@logger.{{lvl.id}} msg
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
end
|
end
|
||||||
|
@ -7,18 +7,12 @@ class Image
|
|||||||
property mime : String
|
property mime : String
|
||||||
property filename : String
|
property filename : String
|
||||||
property size : Int32
|
property size : Int32
|
||||||
|
|
||||||
def initialize(@data, @mime, @filename, @size)
|
def initialize(@data, @mime, @filename, @size)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Entry
|
class Entry
|
||||||
property zip_path : String
|
|
||||||
property book_title : String
|
|
||||||
property title : String
|
|
||||||
property size : String
|
|
||||||
property pages : Int32
|
|
||||||
property cover_url : String
|
|
||||||
|
|
||||||
JSON.mapping zip_path: String, book_title: String, title: String, \
|
JSON.mapping zip_path: String, book_title: String, title: String, \
|
||||||
size: String, pages: Int32, cover_url: String
|
size: String, pages: Int32, cover_url: String
|
||||||
|
|
||||||
@ -144,7 +138,7 @@ end
|
|||||||
class Library
|
class Library
|
||||||
JSON.mapping dir: String, titles: Array(Title), scan_interval: Int32
|
JSON.mapping dir: String, titles: Array(Title), scan_interval: Int32
|
||||||
|
|
||||||
def initialize(@dir, @scan_interval)
|
def initialize(@dir, @scan_interval, logger)
|
||||||
# explicitly initialize @titles to bypass the compiler check. it will
|
# explicitly initialize @titles to bypass the compiler check. it will
|
||||||
# be filled with actual Titles in the `scan` call below
|
# be filled with actual Titles in the `scan` call below
|
||||||
@titles = [] of Title
|
@titles = [] of Title
|
||||||
@ -152,11 +146,11 @@ class Library
|
|||||||
return scan if @scan_interval < 1
|
return scan if @scan_interval < 1
|
||||||
spawn do
|
spawn do
|
||||||
loop do
|
loop do
|
||||||
|
logger.info "Starting periodic scan"
|
||||||
start = Time.local
|
start = Time.local
|
||||||
puts "#{start} Starting periodic scan"
|
|
||||||
scan
|
scan
|
||||||
ms = (Time.local - start).total_milliseconds
|
ms = (Time.local - start).total_milliseconds
|
||||||
puts "Scanned #{@titles.size} titles in #{ms}ms"
|
logger.info "Scanned #{@titles.size} titles in #{ms}ms"
|
||||||
sleep @scan_interval * 60
|
sleep @scan_interval * 60
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
26
src/log_handler.cr
Normal file
26
src/log_handler.cr
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
require "kemal"
|
||||||
|
require "./logger"
|
||||||
|
|
||||||
|
class LogHandler < Kemal::BaseLogHandler
|
||||||
|
def initialize(@logger : MLogger)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
elapsed_time = Time.measure { call_next env }
|
||||||
|
elapsed_text = elapsed_text elapsed_time
|
||||||
|
msg = "#{env.response.status_code} #{env.request.method}" \
|
||||||
|
" #{env.request.resource} #{elapsed_text}"
|
||||||
|
@logger.debug(msg)
|
||||||
|
env
|
||||||
|
end
|
||||||
|
|
||||||
|
def write(msg)
|
||||||
|
@logger.debug(msg)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def elapsed_text(elapsed)
|
||||||
|
millis = elapsed.total_milliseconds
|
||||||
|
return "#{millis.round(2)}ms" if millis >= 1
|
||||||
|
"#{(millis * 1000).round(2)}µs"
|
||||||
|
end
|
||||||
|
end
|
55
src/logger.cr
Normal file
55
src/logger.cr
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
require "./config"
|
||||||
|
require "logger"
|
||||||
|
require "colorize"
|
||||||
|
|
||||||
|
LEVELS = ["debug", "error", "fatal", "info", "warn"]
|
||||||
|
COLORS = [:light_cyan, :light_red, :red, :light_yellow, :light_magenta]
|
||||||
|
|
||||||
|
class MLogger
|
||||||
|
def initialize(config : Config)
|
||||||
|
@logger = Logger.new STDOUT
|
||||||
|
|
||||||
|
@log_off = false
|
||||||
|
log_level = config.log_level
|
||||||
|
if log_level == "off"
|
||||||
|
@log_off = true
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
{% begin %}
|
||||||
|
case log_level
|
||||||
|
{% for lvl in LEVELS %}
|
||||||
|
when {{lvl}}
|
||||||
|
@logger.level = Logger::{{lvl.upcase.id}}
|
||||||
|
{% end %}
|
||||||
|
else
|
||||||
|
raise "Unknown log level #{log_level}"
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
@logger.formatter = Logger::Formatter.new do \
|
||||||
|
|severity, datetime, progname, message, io|
|
||||||
|
|
||||||
|
color = :default
|
||||||
|
{% begin %}
|
||||||
|
case severity.to_s().downcase
|
||||||
|
{% for lvl, i in LEVELS %}
|
||||||
|
when {{lvl}}
|
||||||
|
color = COLORS[{{i}}]
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
io << "[#{severity}]".ljust(8).colorize(color)
|
||||||
|
io << datetime.to_s("%Y/%m/%d %H:%M:%S") << " | "
|
||||||
|
io << message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
{% for lvl in LEVELS %}
|
||||||
|
def {{lvl.id}}(msg)
|
||||||
|
return if @log_off
|
||||||
|
@logger.{{lvl.id}} msg
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
end
|
12
src/mango.cr
12
src/mango.cr
@ -1,6 +1,16 @@
|
|||||||
require "./server"
|
require "./server"
|
||||||
require "./context"
|
require "./context"
|
||||||
|
require "./config"
|
||||||
|
require "./library"
|
||||||
|
require "./storage"
|
||||||
|
require "./logger"
|
||||||
|
|
||||||
|
config = Config.load
|
||||||
|
logger = MLogger.new config
|
||||||
|
library = Library.new config.library_path, config.scan_interval, logger
|
||||||
|
storage = Storage.new config.db_path, logger
|
||||||
|
|
||||||
|
context = Context.new config, logger, library, storage
|
||||||
|
|
||||||
context = Context.new
|
|
||||||
server = Server.new context
|
server = Server.new context
|
||||||
server.start
|
server.start
|
||||||
|
@ -2,12 +2,11 @@ require "kemal"
|
|||||||
require "./context"
|
require "./context"
|
||||||
require "./auth_handler"
|
require "./auth_handler"
|
||||||
require "./static_handler"
|
require "./static_handler"
|
||||||
|
require "./log_handler"
|
||||||
require "./util"
|
require "./util"
|
||||||
|
|
||||||
class Server
|
class Server
|
||||||
property context : Context
|
def initialize(@context : Context)
|
||||||
|
|
||||||
def initialize(@context)
|
|
||||||
|
|
||||||
error 403 do |env|
|
error 403 do |env|
|
||||||
message = "You are not authorized to visit #{env.request.path}"
|
message = "You are not authorized to visit #{env.request.path}"
|
||||||
@ -87,7 +86,7 @@ class Server
|
|||||||
|
|
||||||
env.redirect "/admin/user"
|
env.redirect "/admin/user"
|
||||||
rescue e
|
rescue e
|
||||||
puts e.message
|
@context.error e.message
|
||||||
redirect_url = URI.new \
|
redirect_url = URI.new \
|
||||||
path: "/admin/user/edit",\
|
path: "/admin/user/edit",\
|
||||||
query: hash_to_query({"error" => e.message})
|
query: hash_to_query({"error" => e.message})
|
||||||
@ -127,7 +126,7 @@ class Server
|
|||||||
|
|
||||||
env.redirect "/admin/user"
|
env.redirect "/admin/user"
|
||||||
rescue e
|
rescue e
|
||||||
puts e.message
|
@context.error e.message
|
||||||
redirect_url = URI.new \
|
redirect_url = URI.new \
|
||||||
path: "/admin/user/edit",\
|
path: "/admin/user/edit",\
|
||||||
query: hash_to_query({"username" => original_username, \
|
query: hash_to_query({"username" => original_username, \
|
||||||
@ -234,7 +233,7 @@ class Server
|
|||||||
|
|
||||||
send_img env, img
|
send_img env, img
|
||||||
rescue e
|
rescue e
|
||||||
STDERR.puts e
|
@context.error e.message
|
||||||
env.response.status_code = 500
|
env.response.status_code = 500
|
||||||
e.message
|
e.message
|
||||||
end
|
end
|
||||||
@ -249,7 +248,7 @@ class Server
|
|||||||
|
|
||||||
send_json env, t.to_json
|
send_json env, t.to_json
|
||||||
rescue e
|
rescue e
|
||||||
STDERR.puts e
|
@context.error e.message
|
||||||
env.response.status_code = 500
|
env.response.status_code = 500
|
||||||
e.message
|
e.message
|
||||||
end
|
end
|
||||||
@ -303,6 +302,8 @@ class Server
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Kemal.config.logging = false
|
||||||
|
add_handler LogHandler.new @context.logger
|
||||||
add_handler AuthHandler.new @context.storage
|
add_handler AuthHandler.new @context.storage
|
||||||
{% if flag?(:release) %}
|
{% if flag?(:release) %}
|
||||||
# when building for relase, embed the static files in binary
|
# when building for relase, embed the static files in binary
|
||||||
|
@ -9,11 +9,7 @@ class FS
|
|||||||
end
|
end
|
||||||
|
|
||||||
class StaticHandler < Kemal::Handler
|
class StaticHandler < Kemal::Handler
|
||||||
property dirs : Array(String)
|
@dirs = ["/css", "/js"]
|
||||||
|
|
||||||
def initialize
|
|
||||||
@dirs = ["/css", "/js"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
if request_path_startswith env, @dirs
|
if request_path_startswith env, @dirs
|
||||||
|
@ -16,10 +16,7 @@ def random_str
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Storage
|
class Storage
|
||||||
property path : String
|
def initialize(@path : String, @logger : MLogger)
|
||||||
|
|
||||||
def initialize(path)
|
|
||||||
@path = path
|
|
||||||
dir = File.dirname path
|
dir = File.dirname path
|
||||||
unless Dir.exists? dir
|
unless Dir.exists? dir
|
||||||
Dir.mkdir_p dir
|
Dir.mkdir_p dir
|
||||||
@ -39,7 +36,7 @@ class Storage
|
|||||||
hash = hash_password random_pw
|
hash = hash_password random_pw
|
||||||
db.exec "insert into users values (?, ?, ?, ?)",
|
db.exec "insert into users values (?, ?, ?, ?)",
|
||||||
"admin", hash, nil, 1
|
"admin", hash, nil, 1
|
||||||
puts "Initial user created. You can log in with " \
|
@logger.info "Initial user created. You can log in with " \
|
||||||
"#{{"username" => "admin", "password" => random_pw}}"
|
"#{{"username" => "admin", "password" => random_pw}}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user