Module: Chook::HandledEvent::Handlers

Defined in:
lib/chook/event/handled_event/handlers.rb

Overview

The Handlers namespace module

Constant Summary collapse

DEFAULT_HANDLER_DIR =
'/Library/Application Support/Chook'.freeze
INTERNAL_HANDLER_BLOCK_START_RE =

internal handler files must match this regex somewhere

/Chook.event_handler( ?\{| do) *\|/

Class Method Summary collapse

Class Method Details

.event_name_from_handler_filename(filename) ⇒ String?

Given a handler filename, return the event name it wants to handle

Parameters:

  • filename (Pathname)

    The filename from which to glean the event name.

Returns:

  • (String, nil)

    The matching event name or nil if no match



242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/chook/event/handled_event/handlers.rb', line 242

def self.event_name_from_handler_filename(filename)
  filename = filename.basename
  @event_names ||= Chook::Event::EVENTS.keys
  desired_event_name = filename.to_s.split(/\.|-|_/).first
  ename = @event_names.select { |n| desired_event_name.casecmp(n).zero? }.first
  if ename
    Chook.logger.debug "Found event name '#{ename}' at start of filename '#{filename}'"
  else
    Chook.logger.debug "No known event name at start of filename '#{filename}'"
  end
  ename
end

.handlersHash{String => Array}

Getter for @handlers

come from the JSS to an Array of handlers for the event. The handlers are either Pathnames to executable external handlers or Objcts with a #handle method, for internal handlers

(The objects also have a #handler_file attribute that is the Pathname)

Returns:

  • (Hash{String => Array})

    a mapping of Event Names as they



103
104
105
# File 'lib/chook/event/handled_event/handlers.rb', line 103

def self.handlers
  @handlers
end

.load_external_handler(handler_file, event_name) ⇒ Object

if the given file is executable, store it’s path as a handler for the event



192
193
194
195
196
197
198
199
200
# File 'lib/chook/event/handled_event/handlers.rb', line 192

def self.load_external_handler(handler_file, event_name)
  return false unless handler_file.executable?

  Chook.logger.info "Loading external handler file '#{handler_file.basename}' for #{event_name} events"

  # store the Pathname, we'll pipe JSON to it
  @handlers[event_name] << handler_file
  true
end

.load_handler(from_file) ⇒ void

This method returns an undefined value.

Load an event handler from a file. Handler files must begin with the name of the event they handle, e.g. ComputerAdded, followed by: nothing, a dot, a dash, or and underscore. Case doesn’t matter. So all of these are OK: ComputerAdded computeradded.sh COMPUTERAdded_notify_team Computeradded-update-ldap There can be as many as desired for each event.

Each must be either:

- An executable file, which will have the raw JSON from the JSS piped
  to it's stdin when executed

or

- A non-executable file of ruby code like this:
  Chook.event_handler do |event|
    # your code goes here.
  end

(see the Chook README for details about writing the ruby handlers)

Parameters:

  • from_file (Pathname)

    the file from which to load the handler



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/chook/event/handled_event/handlers.rb', line 172

def self.load_handler(from_file)
  Chook.logger.debug "Starting load of handler file '#{from_file.basename}'"
  handler_file = Pathname.new from_file
  event_name = event_name_from_handler_filename(handler_file)
  unless event_name
    Chook.logger.debug "Ignoring file '#{from_file.basename}'"
    return
  end

  # create an array for this event's handlers, if needed
  @handlers[event_name] ||= []

  return if load_external_handler(handler_file, event_name)

  load_internal_handler(handler_file, event_name)
end

.load_handlers(from_dir: Chook.config.handler_dir, reload: false) ⇒ void

This method returns an undefined value.

Load all the event handlers from the handler_dir or an arbitrary dir.

Parameters:

  • from_dir (String, Pathname) (defaults to: Chook.config.handler_dir)

    directory from which to load the handlers. Defaults to CONFIG.handler_dir or DEFAULT_HANDLER_DIR if config is unset

  • reload (Boolean) (defaults to: false)

    should we reload handlers if they’ve already been loaded?



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/chook/event/handled_event/handlers.rb', line 119

def self.load_handlers(from_dir: Chook.config.handler_dir, reload: false)
  # use default if needed
  from_dir ||= DEFAULT_HANDLER_DIR
  handler_dir = Pathname.new(from_dir)
  load_type = 'Loading'

  if reload
    @handlers = {}
    @loaded_handler = nil
    load_type = 'Re-loading'
  end

  Chook.logger.info "#{load_type} handlers from directory: #{handler_dir}"

  unless handler_dir.directory? && handler_dir.readable?
    Chook.logger.error "Handler directory '#{from_dir}' not a readable directory. No handlers loaded. "
    return
  end

  handler_dir.children.each do |handler_file|
    load_handler(handler_file) if handler_file.file? && handler_file.readable?
  end

  Chook.logger.info "Loaded #{@handlers.values.flatten.size} handlers for #{@handlers.keys.size} event triggers"
  @loaded_handler = nil
end

.load_internal_handler(handler_file, event_name) ⇒ Object

if a given path is not executable, try to load it as an internal handler



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/chook/event/handled_event/handlers.rb', line 205

def self.load_internal_handler(handler_file, event_name)
  # load the file. If written correctly, it will
  # put an anon. Object with a #handle method into @loaded_handler
  Chook.logger.info "Loading internal handler file '#{handler_file.basename}' for #{event_name} events"

  unless handler_file.read =~ INTERNAL_HANDLER_BLOCK_START_RE
    Chook.logger.error "Internal handler file '#{handler_file.basename}' missing event_handler block"
    return
  end

  # reset @loaded_handler - the `load` call will refill it
  # see Chook.event_handler
  @loaded_handler = nil
  begin
    load handler_file.to_s
    raise '@loaded handler nil after loading file' unless @loaded_handler
  rescue => e
    Chook.logger.error "FAILED loading internal handler file '#{handler_file.basename}': #{e}"
    return
  end

  # add a method to the object to get its filename
  @loaded_handler.define_singleton_method(:handler_file) { handler_file.basename.to_s }

  @handlers[event_name] << @loaded_handler

  Chook.logger.debug "Loaded internal handler file '#{handler_file.basename}'"
  @loaded_handler = nil
end

.loaded_handlerObj?

self loaded_handler=

destined for storage in @handlers

Returns:

  • (Obj, nil)

    the most recent Proc loaded from a handler file.



81
82
83
# File 'lib/chook/event/handled_event/handlers.rb', line 81

def self.loaded_handler
  @loaded_handler
end

.loaded_handler=(anon_obj) ⇒ Object

A holding place for internal handlers as they are loaded before being added to the @handlers Hash see Chook.event_handler(&block)

Parameters:

  • a_proc (Object)

    An object instance with a #handle method



91
92
93
# File 'lib/chook/event/handled_event/handlers.rb', line 91

def self.loaded_handler=(anon_obj)
  @loaded_handler = anon_obj
end