require 'legion/extensions/core' require 'legion/runner' module Legion module Extensions class << self def setup hook_extensions end def hook_extensions @timer_tasks = [] @loop_tasks = [] @once_tasks = [] @poll_tasks = [] @subscription_tasks = [] @actors = [] find_extensions load_extensions end def shutdown return nil if @loaded_extensions.nil? @subscription_tasks.each do |task| task[:threadpool].shutdown task[:threadpool].kill unless task[:threadpool].wait_for_termination(5) end @loop_tasks.each { |task| task[:running_class].cancel if task[:running_class].respond_to?(:cancel) } @once_tasks.each { |task| task[:running_class].cancel if task[:running_class].respond_to?(:cancel) } @timer_tasks.each { |task| task[:running_class].cancel if task[:running_class].respond_to?(:cancel) } @poll_tasks.each { |task| task[:running_class].cancel if task[:running_class].respond_to?(:cancel) } Legion::Logging.info 'Successfully shut down all actors' end def load_extensions @extensions ||= {} @loaded_extensions ||= [] @extensions.each do |extension, values| if values.key(:enabled) && !values[:enabled] Legion::Logging.info "Skipping #{extension} because it's disabled" next end if Legion::Settings[:extensions].key?(extension.to_sym) && Legion::Settings[:extensions][extension.to_sym].key?(:enabled) && !Legion::Settings[:extensions][extension.to_sym][:enabled] # rubocop:disable Layout/LineLength next end unless load_extension(extension, values) Legion::Logging.warn("#{extension} failed to load") next end @loaded_extensions.push(extension) end Legion::Logging.info "#{@extensions.count} extensions loaded with subscription:#{@subscription_tasks.count},every:#{@timer_tasks.count},poll:#{@poll_tasks.count},once:#{@once_tasks.count},loop:#{@loop_tasks.count}" end def load_extension(extension, values) return unless gem_load(values[:gem_name], extension) extension = Kernel.const_get(values[:extension_class]) has_logger = extension.respond_to?(:log) extension.autobuild require 'legion/transport/messages/lex_register' Legion::Transport::Messages::LexRegister.new(function: 'save', opts: extension.runners).publish if extension.respond_to?(:meta_actors) && extension.meta_actors.is_a?(Array) extension.meta_actors.each do |_key, actor| extension.log.debug("hooking meta actor: #{actor}") if has_logger hook_actor(**actor) end end extension.actors.each do |_key, actor| extension.log.debug("hooking literal actor: #{actor}") if has_logger hook_actor(**actor) end extension.log.info "Loaded v#{extension::VERSION}" rescue StandardError => e Legion::Logging.error e.message Legion::Logging.error e.backtrace false end def hook_actor(extension:, extension_name:, actor_class:, size: 1, **opts) size = if Legion::Settings[:extensions].key?(extension_name.to_sym) && Legion::Settings[:extensions][extension_name.to_sym].key?(:workers) Legion::Settings[:extensions][extension_name.to_sym][:workers] elsif size.is_a? Integer size else 1 end extension_hash = { extension: extension, extension_name: extension_name, actor_class: actor_class, size: size, fallback_policy: :abort, **opts } extension_hash[:running_class] = if actor_class.ancestors.include? Legion::Extensions::Actors::Subscription actor_class else actor_class.new end if actor_class.ancestors.include? Legion::Extensions::Actors::Every @timer_tasks.push(extension_hash) elsif actor_class.ancestors.include? Legion::Extensions::Actors::Once @once_tasks.push(extension_hash) elsif actor_class.ancestors.include? Legion::Extensions::Actors::Loop @loop_tasks.push(extension_hash) elsif actor_class.ancestors.include? Legion::Extensions::Actors::Poll @poll_tasks.push(extension_hash) elsif actor_class.ancestors.include? Legion::Extensions::Actors::Subscription extension_hash[:threadpool] = Concurrent::FixedThreadPool.new(size) size.times do extension_hash[:threadpool].post do klass = actor_class.new if klass.respond_to?(:async) klass.async.subscribe else klass.subscribe end end end @subscription_tasks.push(extension_hash) else Legion::Logging.fatal 'did not match any actor classes' end end def gem_load(gem_name, name) gem_path = "#{Gem::Specification.find_by_name(gem_name).gem_dir}/lib/legion/extensions/#{name}" require gem_path true rescue LoadError => e Legion::Logging.error e.message Legion::Logging.error e.backtrace Legion::Logging.error "gem_path: #{gem_path}" unless gem_path.nil? false end def find_extensions @extensions ||= {} # puts Gem.install('lex-esphome') # puts Gem::Installer.new('lex-esphome') # test = Gem::Installer.new('lex-esphome') # puts test.install # puts Gem::Dependency.new('lex-esphome') # $LOAD_PATH << "#{ENV['GEM_HOME']}/gems/lex-esphome-0.1.0/lib" # require 'legion/extensions/esphome' # $LOAD_PATH << "#{ENV['GEM_HOME']}/gems/lex-esphome-0.1.0/lib" # ENV['MY_RUBY_HOME'] #/Users/miverso2/.rvm/rubies/ruby-2.7.0 # ENV['GEM_HOME'] # /Users/miverso2/.rvm/gems/ruby-2.7.0 # require 'rubygems/dependency_installer.rb' # puts Gem::DependencyInstaller.new.install('lex-esphome') # puts Gem::Installer.new('lex-esphome').install # puts Gem::Installer.new('lex-esphome').ensure_loadable_spec # puts Gem.search('lex-esphome') # Gem.clear_paths # require 'legion/extensions/esphome' # puts Gem.use_gemdeps # pp Gem.gemdeps # puts 'gems things' # puts Gem.loaded_specs.key? 'lex-esphome' # pp Gem.loaded_specs.keys # # require 'rubygems' # require 'rubygems/command.rb' # require 'rubygems/dependency_installer.rb' # # Gem::Command.build_args = ARGV # inst = Gem::DependencyInstaller.new # puts inst.installed_gems # puts inst.install 'lex-esphome', install_as_default: true # puts inst.installed_gems # puts '....' # test = Gem::DependencyList.new # test.add(inst) # pp test.find_name('lex-esphome') # pp test.find_name('lex-logger') # pp test.specs # pp Gem::DependencyList.from_specs # pp Gem::DependencyList.from_specs.key? 'lex-logg' # pp inst # # pp Gem.new.all_specs # load 'legion/extensions/esphome.rb' # puts Gem.register_default_spec() # :use_gemdeps, # :detect_gemdeps, # :source_date_epoch, # :gemdeps, # :register_default_spec, # :find_unresolved_default_spec, # :clear_default_specs, # :loaded_specs, # :default_path, Gem::Specification.all_names.each do |gem| next unless gem[0..3] == 'lex-' lex = gem.split('-') @extensions[lex[1]] = { full_gem_name: gem, gem_name: "lex-#{lex[1]}", extension_name: lex[1], version: lex[2], extension_class: "Legion::Extensions::#{lex[1].capitalize}" } end # Legion::Settings[:extensions].each do |extension| # puts extension unless @extensions.key? extension # end end end end end