class Fancybox2::Module::Base
Attributes
configs[RW]
fbxfile[R]
fbxfile_path[R]
logger[R]
mqtt_client[R]
status[R]
Public Class Methods
new(fbxfile_path, options = {})
click to toggle source
# File lib/fancybox2/module/base.rb, line 16 def initialize(fbxfile_path, options = {}) unless fbxfile_path || fbxfile_path.is_a?(String) || fbxfile_path.empty? raise FbxfileNotProvided end @fbxfile_path = fbxfile_path options.deep_symbolize_keys! @internal_mqtt_client = false @fbxfile = check_and_return_fbxfile options.fetch(:fbxfile, load_fbx_file) @mqtt_client_params = options[:mqtt_client_params] || {} check_or_build_mqtt_client options[:mqtt_client] @log_level = options.fetch :log_level, ::Logger::INFO @log_progname = options.fetch :log_progname, 'Fancybox2::Module::Base' @logger = options.fetch :logger, create_default_logger @status = :stopped @alive_task = nil @configs = {} end
Public Instance Methods
alive_message_data(&block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 36 def alive_message_data(&block) if block_given? @alive_message_data = block return end @alive_message_data.call if @alive_message_data end
alive_message_data=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 44 def alive_message_data=(callback) @alive_message_data = callback if callback.is_a?(Proc) end
message_to(dest, action = '', payload = '', retain = false, qos = 2)
click to toggle source
# File lib/fancybox2/module/base.rb, line 48 def message_to(dest, action = '', payload = '', retain = false, qos = 2) if mqtt_client.connected? topic = topic_for dest: dest, action: action payload = case payload when Hash, Array payload.to_json else payload end logger.debug "#{self.class}#message_to '#{topic}' payload: #{payload}" mqtt_client.publish topic, payload, retain, qos else logger.error 'MQTT client not connected to broker' end end
name()
click to toggle source
# File lib/fancybox2/module/base.rb, line 64 def name fbxfile[:name] end
on_action(action, callback = nil, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 68 def on_action(action, callback = nil, &block) topic = topic_for source: :core, action: action mqtt_client.add_topic_callback topic do |packet| # :nocov: payload = packet.payload # Try to parse payload as JSON. Rescue with original payload in case of error packet.payload = JSON.parse(payload) rescue payload if block_given? block.call packet elsif callback && callback.is_a?(Proc) callback.call packet end # :nocov: end end
on_client_connack()
click to toggle source
MQTT Client callbacks
# File lib/fancybox2/module/base.rb, line 281 def on_client_connack logger.debug 'Connected to the broker' # Setup default callbacks default_actions.each do |action_name, callback| action_name = action_name.to_s on_action action_name do |packet| # :nocov: if callback.is_a? Proc callback.call packet else logger.warn "No valid callback defined for '#{action_name}'" end # :nocov: end end if mqtt_client.subscribed_topics.size.zero? # Subscribe to all messages directed to me logger.debug 'Making broker subscriptions' mqtt_client.subscribe [topic_for(source: '+', action: '+'), 2] end end
on_client_message(message)
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 334 def on_client_message(message) end
on_client_puback(message)
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 318 def on_client_puback(message) end
on_client_pubcomp(message)
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 330 def on_client_pubcomp(message) end
on_client_pubrec(message)
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 326 def on_client_pubrec(message) end
on_client_pubrel(message)
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 322 def on_client_pubrel(message) end
on_client_suback()
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 306 def on_client_suback # Client subscribed, we're ready to rock -> Tell core logger.debug 'Subscriptions done' logger.debug "Sending 'ready' to core" message_to :core, :ready end
on_client_unsuback()
click to toggle source
@note Call super if you override this method
# File lib/fancybox2/module/base.rb, line 314 def on_client_unsuback end
on_configs(packet = nil, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 84 def on_configs(packet = nil, &block) logger.debug 'on_configs' if block_given? @on_configs = block return end cfg = packet.payload if cfg && cfg.is_a?(Hash) && cfg['configs'] self.configs.merge! cfg['configs'] end @on_configs.call(packet) if @on_configs end
on_configs=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 99 def on_configs=(callback) @on_configs = callback if callback.is_a?(Proc) end
on_logger(packet = nil, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 103 def on_logger(packet = nil, &block) if block_given? @on_logger = block return end @on_logger.call(packet) if @on_logger logger_configs = packet.payload logger.level = logger_configs['level'] if logger_configs['level'] end
on_logger=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 113 def on_logger=(callback) @on_logger = callback if callback.is_a?(Proc) end
on_restart(packet = nil, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 117 def on_restart(packet = nil, &block) if block_given? @on_restart = block return end @on_restart.call(packet) if @on_restart # Stop + start on_stop on_start packet end
on_restart=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 128 def on_restart=(callback) @on_restart = callback if callback.is_a?(Proc) end
on_shutdown(do_exit = true, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 132 def on_shutdown(do_exit = true, &block) if block_given? @on_shutdown = block return end @status = :on_shutdown shutdown_ok = true logger.debug "Received 'shutdown' command" # Stop sending alive messages @alive_task.shutdown if @alive_task begin # Call user code if any @on_shutdown.call if @on_shutdown rescue StandardError => e logger.error "Error during shutdown: #{e.message}" shutdown_ok = false end # Signal core that we've executed shutdown operations. # This message is not mandatory, so keep it simple shutdown_message = shutdown_ok ? 'ok' : 'nok' logger.debug "Sending shutdown message to core with status '#{shutdown_message}'" message_to :core, :shutdown, { status: shutdown_message } sleep 0.05 # Wait some time in order to be sure that the message has been published (message is not mandatory) Thread.new do if mqtt_client && mqtt_client.connected? # Gracefully disconnect from broker and exit logger.debug 'Disconnecting from broker, bye' mqtt_client.disconnect @mqtt_client = nil end if do_exit # Exit from process status_code = shutdown_ok ? 0 : 1 logger.debug "Exiting with status code #{status_code}" exit status_code end end end
on_shutdown=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 177 def on_shutdown=(callback) @on_shutdown = callback if callback.is_a?(Proc) end
on_start(packet = nil, &block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 181 def on_start(packet = nil, &block) if block_given? @on_start = block return end # Call user code @on_start.call(packet) if @on_start cfg = packet ? packet.payload : {} interval = cfg['aliveTimeout'] || 1000 # Start code execution from scratch logger.debug "Received 'start'" @status = :running start_sending_alive interval: interval end
on_start=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 197 def on_start=(callback) @on_start = callback if callback.is_a?(Proc) end
on_stop(&block)
click to toggle source
# File lib/fancybox2/module/base.rb, line 201 def on_stop(&block) if block_given? @on_stop = block return end @on_stop.call if @on_stop @status = :stopped # Stop code execution, but keep broker connection and continue to send alive end
on_stop=(callback)
click to toggle source
# File lib/fancybox2/module/base.rb, line 211 def on_stop=(callback) @on_stop = callback if callback.is_a?(Proc) end
remove_action(action)
click to toggle source
# File lib/fancybox2/module/base.rb, line 215 def remove_action(action) topic = topic_for source: :core, action: action mqtt_client.remove_topic_callback topic end
running?()
click to toggle source
# File lib/fancybox2/module/base.rb, line 246 def running? @status.eql? :running end
setup(retry_connection = true)
click to toggle source
# File lib/fancybox2/module/base.rb, line 254 def setup(retry_connection = true) unless @setted_up begin logger.debug 'Connecting to the broker...' mqtt_client.connect rescue PahoMqtt::Exception => e # :nocov: logger.error "Error while connecting to the broker: #{e.message}" retry if retry_connection # :nocov: end @setted_up = true end end
shutdown(do_exit = true)
click to toggle source
# File lib/fancybox2/module/base.rb, line 220 def shutdown(do_exit = true) on_shutdown do_exit end
start()
click to toggle source
# File lib/fancybox2/module/base.rb, line 224 def start on_start end
start_sending_alive(interval: 5000)
click to toggle source
# File lib/fancybox2/module/base.rb, line 228 def start_sending_alive(interval: 5000) # TODO: replace the alive interval task with Eventmachine? # Interval is expected to be msec, so convert it to secs interval /= 1000.0 @alive_task.shutdown if @alive_task @alive_task = Concurrent::TimerTask.new(execution_interval: interval, timeout_interval: 2, run_now: true) do packet = { status: @status, lastSeen: Time.now.utc, data: nil } begin packet[:data] = alive_message_data message_to :core, :alive, packet rescue StandardError => e logger.error "Error in alive_message_data callback: #{e.message}" logger.error e.backtrace.join "\n" end end @alive_task.execute end
stopped?()
click to toggle source
# File lib/fancybox2/module/base.rb, line 250 def stopped? @status.eql? :stopped end
topic_for(source: self.name, dest: self.name, action: nil, packet_type: :msg)
click to toggle source
# File lib/fancybox2/module/base.rb, line 270 def topic_for(source: self.name, dest: self.name, action: nil, packet_type: :msg) source = source.to_s packet_type = packet_type.to_s dest = dest.to_s action = action.to_s Config::DEFAULT_TOPIC_FORMAT % [source, packet_type, dest, action] end
Private Instance Methods
check_and_return_fbxfile(hash_attributes)
click to toggle source
# File lib/fancybox2/module/base.rb, line 352 def check_and_return_fbxfile(hash_attributes) raise ArgumentError, 'You must provide an Hash as argument' unless hash_attributes.is_a?(Hash) hash_attributes.deep_symbolize_keys end
check_or_build_mqtt_client(mqtt_client = nil)
click to toggle source
# File lib/fancybox2/module/base.rb, line 339 def check_or_build_mqtt_client(mqtt_client = nil) if mqtt_client unless mqtt_client.is_a? PahoMqtt::Client raise Exceptions::NotValidMQTTClient.new end @internal_mqtt_client = false @mqtt_client = mqtt_client else @internal_mqtt_client = true @mqtt_client = PahoMqtt::Client.new mqtt_params end end
create_default_logger()
click to toggle source
# File lib/fancybox2/module/base.rb, line 357 def create_default_logger stdout_logger = ::Logger.new STDOUT # broker_logger = ::Logger.new(Logger::MQTTLogDevice.new(topic_for(dest: :core, action: :logs), # client: mqtt_client), # formatter: Logger::JSONFormatter.new) logger = Logger::Multi.new stdout_logger,# broker_logger, level: @log_level, progname: @log_progname logger end
default_actions()
click to toggle source
:nocov:
# File lib/fancybox2/module/base.rb, line 369 def default_actions { start: proc { |packet| on_start packet }, stop: proc { on_stop }, restart: proc { |packet| on_restart packet }, shutdown: proc { on_shutdown }, logger: proc { |packet| on_logger packet }, configs: proc { |packet| on_configs packet } } end
load_fbx_file()
click to toggle source
:nocov:
# File lib/fancybox2/module/base.rb, line 381 def load_fbx_file if File.exists? @fbxfile_path @fbxfile = YAML.load(File.read(@fbxfile_path)).deep_symbolize_keys else raise Exceptions::FbxfileNotFound.new @fbxfile_path end end
mqtt_default_params()
click to toggle source
:nocov:
# File lib/fancybox2/module/base.rb, line 390 def mqtt_default_params { host: 'localhost', port: 1883, mqtt_version: '3.1.1', clean_session: true, persistent: true, blocking: false, reconnect_limit: -1, reconnect_delay: 1, client_id: nil, username: nil, password: nil, ssl: false, will_topic: nil, will_payload: nil, will_qos: 0, will_retain: false, keep_alive: 7, ack_timeout: 5, on_connack: proc { on_client_connack }, on_suback: proc { on_client_suback }, on_unsuback: proc { on_client_unsuback }, on_puback: proc { |msg| on_client_puback msg }, on_pubrel: proc { |msg| on_client_pubrel msg }, on_pubrec: proc { |msg| on_client_pubrec msg }, on_pubcomp: proc { |msg| on_client_pubcomp msg }, on_message: proc { |msg| on_client_message msg } } end
mqtt_params()
click to toggle source
:nocov:
# File lib/fancybox2/module/base.rb, line 422 def mqtt_params return @mqtt_params if @mqtt_params @mqtt_params = mqtt_default_params.merge(@mqtt_client_params) { |key, old_val, new_val| new_val.nil? ? old_val : new_val } @mqtt_params end