require "hara/version" require 'celluloid' require 'json' module Hara class << self def env @_env ||= (ENV['APP_ENV'] || :development).to_sym end def env= env @_env = env end 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 class App include Celluloid include Celluloid::Logger attr_reader :socket, :handshake finalizer :app_finalizer Actions = {} class << self def inherited klass ::Hara.const_set :Application, klass end 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 def after_connect end def before_action action, args end def after_action action, args end def action_missing action, args info "#{headers['host']} request action: #{action} args: #{args.inspect}, action not defined" raise NoMethodError, "undefined action '#{action}' for #{self}:#{self.class}" end def headers handshake.headers_downcased end def on_close end #below are internal functions(should not been overriding) def initialize handshake, socket @handshake = handshake @socket = socket async.hara_setup end def hara_setup info "#{headers['host']} coming" after_connect end def process_msg message action, args = Hara.decode_msg(message) info "#{headers['host']} request action: #{action} args: #{args.inspect}" before_action action, *args call_action action, *args after_action action, *args rescue StandardError => e info "#{headers['host']} 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