Class: Heathrow::PluginManager

Inherits:
Object
  • Object
show all
Defined in:
lib/heathrow/plugin_manager.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(logger: nil, event_bus: nil) ⇒ PluginManager

Returns a new instance of PluginManager.



6
7
8
9
10
11
12
13
14
# File 'lib/heathrow/plugin_manager.rb', line 6

def initialize(logger: nil, event_bus: nil)
  @plugins = {}
  @plugin_errors = {}
  @plugin_dir = HEATHROW_PLUGINS
  @logger = logger
  @event_bus = event_bus
  ensure_plugin_directory
  load_plugins
end

Instance Attribute Details

#event_busObject (readonly)

Returns the value of attribute event_bus.



4
5
6
# File 'lib/heathrow/plugin_manager.rb', line 4

def event_bus
  @event_bus
end

#loggerObject (readonly)

Returns the value of attribute logger.



4
5
6
# File 'lib/heathrow/plugin_manager.rb', line 4

def logger
  @logger
end

#plugin_errorsObject (readonly)

Returns the value of attribute plugin_errors.



4
5
6
# File 'lib/heathrow/plugin_manager.rb', line 4

def plugin_errors
  @plugin_errors
end

#pluginsObject (readonly)

Returns the value of attribute plugins.



4
5
6
# File 'lib/heathrow/plugin_manager.rb', line 4

def plugins
  @plugins
end

Instance Method Details

#available_typesObject



61
62
63
# File 'lib/heathrow/plugin_manager.rb', line 61

def available_types
  @plugins.keys
end

#create_source(type, source) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/heathrow/plugin_manager.rb', line 69

def create_source(type, source)
  # Try to load the source module dynamically with error boundary
  begin
    # Handle 'web' as 'webpage' for the module
    module_name = type == 'web' ? 'webpage' : type
    require_relative "sources/#{module_name}"

    # Get the class
    class_name = module_name.capitalize
    source_class = Heathrow::Sources.const_get(class_name)

    # Create instance with error boundary
    instance = source_class.new(source)

    @logger&.info("PluginManager: Created source instance for type '#{type}'", source_id: source['id'])
    @event_bus&.publish('source.created', type: type, source_id: source['id'])

    instance
  rescue LoadError => e
    error_msg = "Source module not found: #{module_name}"
    @logger&.error(error_msg, error: e, type: type)
    @event_bus&.publish('source.create_failed', type: type, error: e.message)
    nil
  rescue StandardError => e
    error_msg = "Error creating source"
    @logger&.error(error_msg, error: e, type: type)
    @event_bus&.publish('source.create_failed', type: type, error: e.message)
    nil
  end
end

#ensure_plugin_directoryObject



16
17
18
19
# File 'lib/heathrow/plugin_manager.rb', line 16

def ensure_plugin_directory
  require 'fileutils'
  FileUtils.mkdir_p(@plugin_dir) unless Dir.exist?(@plugin_dir)
end

#get_plugin(type) ⇒ Object



57
58
59
# File 'lib/heathrow/plugin_manager.rb', line 57

def get_plugin(type)
  @plugins[type]
end

#load_builtin_pluginsObject



34
35
36
37
# File 'lib/heathrow/plugin_manager.rb', line 34

def load_builtin_plugins
  # Built-in source plugins will auto-register when required
  # This is handled by the create_source method
end

#load_plugin(plugin_file) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/heathrow/plugin_manager.rb', line 39

def load_plugin(plugin_file)
  begin
    require plugin_file
    # Plugin should register itself via PluginManager.register
    @logger&.info("PluginManager: Loaded plugin from #{plugin_file}")
  rescue StandardError => e
    error_msg = "Failed to load plugin #{plugin_file}: #{e.message}"
    @logger&.error(error_msg, error: e)
    @plugin_errors[plugin_file] = e
  end
end

#load_pluginsObject



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/heathrow/plugin_manager.rb', line 21

def load_plugins
  # Load built-in plugins
  load_builtin_plugins

  # Load user plugins from ~/.heathrow/plugins/
  Dir.glob(File.join(@plugin_dir, '*.rb')).each do |plugin_file|
    load_plugin(plugin_file)
  end

  @logger&.info("PluginManager: Loaded #{@plugins.size} plugin(s)")
  @event_bus&.publish('plugins.loaded', plugin_types: @plugins.keys)
end

#plugin_healthObject

Get plugin health status



115
116
117
118
119
120
121
# File 'lib/heathrow/plugin_manager.rb', line 115

def plugin_health
  {
    total_plugins: @plugins.size,
    plugin_types: @plugins.keys,
    errors: @plugin_errors.transform_values { |e| e.message }
  }
end

#plugin_registered?(type) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/heathrow/plugin_manager.rb', line 65

def plugin_registered?(type)
  @plugins.key?(type)
end

#register(type, plugin_class) ⇒ Object



51
52
53
54
55
# File 'lib/heathrow/plugin_manager.rb', line 51

def register(type, plugin_class)
  @plugins[type] = plugin_class
  @logger&.debug("PluginManager: Registered plugin type '#{type}'")
  @event_bus&.publish('plugin.registered', type: type, class: plugin_class.name)
end

#reload_plugin(type) ⇒ Object

Reload a specific plugin



124
125
126
127
128
# File 'lib/heathrow/plugin_manager.rb', line 124

def reload_plugin(type)
  @plugins.delete(type)
  load_plugins
  @logger&.info("PluginManager: Reloaded plugin type '#{type}'")
end

#safe_execute(plugin_instance, method_name, *args) ⇒ Object

Execute plugin method with error boundary Returns [success, result_or_error]



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/heathrow/plugin_manager.rb', line 102

def safe_execute(plugin_instance, method_name, *args)
  begin
    result = plugin_instance.send(method_name, *args)
    @logger&.debug("PluginManager: Executed #{method_name} successfully")
    [true, result]
  rescue => e
    @logger&.error("PluginManager: Error in #{method_name}", error: e)
    @event_bus&.publish('plugin.error', method: method_name, error: e.message)
    [false, e]
  end
end

#unregister(type) ⇒ Object

Unregister a plugin



131
132
133
134
135
136
137
138
139
# File 'lib/heathrow/plugin_manager.rb', line 131

def unregister(type)
  if @plugins.delete(type)
    @logger&.info("PluginManager: Unregistered plugin type '#{type}'")
    @event_bus&.publish('plugin.unregistered', type: type)
    true
  else
    false
  end
end