From 2b9360acb48cb20bf54f15fdcc3ba292022582a5 Mon Sep 17 00:00:00 2001 From: Karchnu Date: Sun, 18 Oct 2020 02:49:45 +0200 Subject: [PATCH] Compilable. Nothing to see, yet. --- shard.yml | 11 ++-- src/main.cr | 175 ++++++++++++++++++++++++++++++++++++++++++++++---- src/parser.cr | 27 -------- 3 files changed, 168 insertions(+), 45 deletions(-) delete mode 100644 src/parser.cr diff --git a/shard.yml b/shard.yml index 6da003f..e4b04ab 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: dnsmanager -version: 0.1.0 +version: 0.2.0 authors: - karchnu @@ -9,11 +9,14 @@ description: | dependencies: ipc: - git: https://git.karchnu.fr/WeirdOS/ipc.cr + git: https://git.baguette.netlib.re/Baguette/ipc.cr dodb: - git: https://git.karchnu.fr/WeirdOS/dodb.cr + git: https://git.baguette.netlib.re/Baguette/dodb.cr authd: - git: https://git.karchnu.fr/WeirdOS/authd + git: https://git.baguette.netlib.re/Baguette/authd + baguette-crystal-base: + git: https://git.baguette.netlib.re/Baguette/baguette-crystal-base + branch: master targets: dnsmanager: diff --git a/src/main.cr b/src/main.cr index 51a1bfd..56f3292 100644 --- a/src/main.cr +++ b/src/main.cr @@ -1,29 +1,176 @@ require "http/server" -require "option_parser" +require "ipc" +require "ipc/json" require "authd" +require "baguette-crystal-base" -service_name = "dnsmanager" -verbosity = 1 -authd_key_file = nil +class Context + class_property service_name = "dnsmanager" + class_property recreate_indexes = false + class_property print_timer = false +end -require "./parser" +module DNSManager + class Exception < ::Exception + end + class AuthorizationException < ::Exception + end + class NotLoggedException < ::Exception + end + class AdminAuthorizationException < ::Exception + end +end -begin - authd = AuthD::Client.new - authd.key = File.read(Context.authd_key_file.not_nil!).chomp +require "./cli-parser" +require "./storage.cr" +require "./network.cr" + + +class DNSManager::Service < IPC::Server + getter storage_directory : String + getter storage : DNSManager::Storage + getter logged_users : Hash(Int32, AuthD::User::Public) + # getter logged_connections : Hash(Int32, IPC::Connection) + + @authd : AuthD::Client + + def initialize(service_name, @storage_directory : String, @authd : AuthD::Client) + @storage = DNSManager::Storage.new @storage_directory + + @logged_users = Hash(Int32, AuthD::User::Public).new + # @logged_connections = Hash(Int32, IPC::Connection).new + + super service_name + end + + def get_logged_user(event : IPC::Event::Events) + fd = event.connection.fd + + @logged_users[fd]? + end + + def decode_token(token : String) + @auth.decode_token token + end + + def get_user_data(uid : Int32) + @storage.user_data_per_user.get uid.to_s + rescue e : DODB::MissingEntry + entry = UserData.new uid + entry + end + + def get_user_data(user : ::AuthD::User::Public) + get_user_data user.uid + end + + def update_user_data(user_data : UserData) + @storage.user_data_per_user.update_or_create user_data.uid.to_s, user_data + end + + def handle_request(event : IPC::Event::MessageReceived) + request_start = Time.utc + + request = DNSManager.requests.parse_ipc_json event.message + + if request.nil? + raise "unknown request type" + end + + reqname = request.class.name.sub /^DNSManager::Request::/, "" + Baguette::Log.debug "<< #{reqname}" + + response = DNSManager::Response::Error.new "generic error" + + begin + response = request.handle self, event + rescue e : AuthorizationException + Baguette::Log.error "#{reqname} authorization error" + response = DNSManager::Response::Error.new "authorization error" + rescue e : AdminAuthorizationException + Baguette::Log.error "#{reqname} no admin authorization" + response = DNSManager::Response::Error.new "admin authorization error" + rescue e : NotLoggedException + Baguette::Log.error "#{reqname} user not logged" + response = DNSManager::Response::Error.new "user not logged" + # Do not handle generic exception case: do not provide a response. + # rescue e # Generic case + # Baguette::Log.error "#{reqname} generic error #{e}" + end + + # If clients sent requests with an “id” field, it is copied + # in the responses. Allows identifying responses easily. + response.id = request.id + + send event.fd, response + + duration = Time.utc - request_start + + response_str = response.class.name.sub /^DNSManager::Response::/, "" + + if response.is_a? DNSManager::Response::Error + Baguette::Log.warning ">> #{response_str} (#{response.reason})" + else + Baguette::Log.debug ">> #{response_str} (Total duration: #{duration})" + end + end + + def run + Baguette::Log.title "Starting #{Context.service_name}" + + self.loop do |event| + begin + case event + when IPC::Event::Timer + Baguette::Log.debug "Timer" if Context.print_timer + + when IPC::Event::Connection + Baguette::Log.debug "connection from #{event.fd}" + + when IPC::Event::Disconnection + Baguette::Log.debug "disconnection from #{event.fd}" + fd = event.fd + + # @logged_connections.delete fd + @logged_users.delete fd + + when IPC::Event::MessageSent + Baguette::Log.debug "message sent to #{event.fd}" + + when IPC::Event::MessageReceived + Baguette::Log.debug "message sent to #{event.fd}" + + handle_request event + else + Baguette::Log.warning "unhandled IPC event: #{event.class}" + end + rescue exception + Baguette::Log.error "exception: #{typeof(exception)} - #{exception.message}" + end + end + end +end + +def dnsmanager_webserver_init server = HTTP::Server.new do |context| context.response.content_type = "text/plain" pp! context.request - context.response.print "Hello. New version of DNSManager, soon." + context.response.print "Hello. New version of dnsmanager, soon." end - address = server.bind_tcp Context.activation_server_port + address = server.bind_tcp Context.webserver_domain, Context.webserver_port puts "Listening on http://#{address}" - server.listen -rescue e - puts "Error: #{e}" - exit 1 + server end + +authd = AuthD::Client.new +authd.key = Context.authd_key.not_nil! +server = dnsmanager_webserver_init + +spawn server.listen + +service = DNSManager::Service.new Context.service_name, Context.storage_directory, authd +service.run diff --git a/src/parser.cr b/src/parser.cr deleted file mode 100644 index 19c9706..0000000 --- a/src/parser.cr +++ /dev/null @@ -1,27 +0,0 @@ - -class Context - class_property verbosity = 1 - class_property authd_key_file : String? = nil - class_property activation_server_port : Int32 = 9000 -end - - -OptionParser.parse do |parser| - - parser.on "-v verbosity-level", "--verbosity level", "Verbosity." do |opt| - Context.verbosity = opt.to_i - end - - parser.on "-p port", "--port port", "Listening port." do |port| - Context.activation_server_port = port.to_i - end - - parser.on "-K key-file", "--key-file file", "Key file." do |opt| - Context.authd_key_file = opt - end - - parser.on "-h", "--help", "Show this help" do - puts parser - exit 0 - end -end