require "hara/version" require 'celluloid' require 'socket' require 'json' module Hara class << self def env @_env ||= (ENV['APP_ENV'] || :development).to_sym end def env= env @_env = env end #decode message, return action and args def decode_msg msg msg = JSON.parse(msg) msg.values_at 'action', 'args' end def encode_msg action, *args {action: action, args: args}.to_json end end module App attr_reader :socket, :handshake, :client_ip, :client_port Actions = {} class << self def included klass klass.send :include, Celluloid klass.send :include, Celluloid::Logger klass.send :finalizer, :app_finalizer klass.send :extend, ClassMethods ::Hara.const_set :Application, klass end end module ClassMethods def define_action action, &block action = action.to_s warn "Action #{action} duplication defined" if Actions.has_key? action Hara::Application.send :define_method, action, &block method = Hara::Application.send :instance_method, action Hara::Application.send :remove_method, action Actions[action] = method end end ##callback methods def after_connect end def before_action action, args end def after_action action, args end def on_close end ################## #like method_missing def action_missing action, args info "#{client_ip} request action: #{action} args: #{args.inspect}, action not defined" raise NoMethodError, "undefined action '#{action}' for #{self}:#{self.class}" end #get client headers def headers handshake.headers_downcased end #below are internal functions(should not been overriding) def initialize handshake, socket @handshake = handshake @socket = socket @client_port, @client_ip = Socket.unpack_sockaddr_in(socket.get_peername) #to get ip address of user async.hara_setup end def hara_setup info "#{client_ip} coming" after_connect end def process_msg message action, args = Hara.decode_msg(message) info "#{client_ip} request action: #{action} args: #{args.inspect}" before_action action, *args call_action action, *args after_action action, *args rescue StandardError => e info "#{client_ip} processing error:\n#{e.inspect}" terminate end def call_action action, *args if Actions.has_key? action Actions[action].bind(self).call *args else action_missing action, *args end end def app_finalizer on_close ensure @socket.close if @socket end end end