-
Notifications
You must be signed in to change notification settings - Fork 3
Create a search method
A search method class contains instructions for running a particular query on a given adapter, as well as formatting the input and output of that query so that the search method can act as middleware in a recipe (middleware stack).
First, generate a template:
rails generate whowas:search_method MySearchMethod
This will create a file app/whowas/search_methods/my_search_method.rb
that looks like this:
module Whowas
class MySearchMethod
include Whowas::Middleware
include Whowas::Searchable
@@adapter = ADAPTER_CLASS_HERE
private
def required_inputs
[
# :ip,
# :timestamp
]
end
def input_formats
{
# timestamp: lambda { |input| DateTime.parse(input) && true rescue false }
}
end
def format_input(input)
input
end
def output_formats
{
# username: /User <\K\w*/
}
end
end
end
The public interface consists of one method, search
, which is provided by Whowas::Searchable
. The only required configuration is setting the @@adapter class variable. However, a search method is only as useful as its input and output, so configuring the optional methods is highly recommended. Like adapters, search methods can be validatable and formattable, and they can also be parsable.
Validatable uses the following configuration methods to ensure input a) exists and b) is correct.
The input
argument should always be a hash. required_inputs
lists the required keys in an array. If there are no required inputs, this should return an empty array.
Example:
def required_inputs
[:ip, :timestamp]
end
Validates required input against specific requirements. You may specify none, some, or all of the keys enumerated in required_inputs
. The value must be a lambda which takes one argument and returns a boolean. If there are no validations, this should return an empty hash.
Example:
def input_formats
{
ip: lambda { |input| IPAddr.new(input) && true rescue false }
timestamp: lambda { |input| DateTime.parse(input) && true rescue false }
}
end
If any Validatable condition fails, the search will halt and return an error message with the results hash.
Performs search method-wide transformations on the input. Adapter-wide transformations can be done in the adapter class. If there is no formatting to be done, this should return input unchanged.
In the example below transforms the input twice:
- The input[:query] pair is created from the input argument and a search method-specific string, and
- The input[:offset] pair is added to tell the adapter what range of time before the timestamp to search. (This particular adapter is configured to require an offset or use a default, but the value can vary by search method.)
def format_input(input)
input[:query] = "#{input[:mac].tr(':','')} index=main | head 1"
input[:offset] = -3600 * 24 * 7
input
end
For the most part, Whowas is unconcerned with extra values in the input
hash. Thus, input[:mac]
is passed to the adapter class but is not used.
Parsable transforms the output of the search.
The adapter for each search returns its results as a string, which is useful for the final search method in a recipe but not so much for beginning or intermediate steps, which need to provide specific information to the next search. output_formats
breaks information out of the results string into the input hash.
ouput_formats
is a hash where the key is an input (required or otherwise) for the next search method, and the value is a regular expression matching part of the results hash.
For example, if the next search takes a mac address, which is part of the result string of this search:
def output_formats
{
mac: /([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})/
}
end
If no inputs are required for the next search, this can return an empty hash. Even for the final search method in a recipe, however, it can be useful to break out the desired piece of information from the entire results string for the user to consume.