Skip to content
Leonard edited this page Feb 19, 2015 · 1 revision

SeleXor's Backend

SeleXor operates as three separate components:

  • Main Server
  • Vessel Database
  • Web Interface

The main server performs requests that are issued by users. When a user sends a request, such as "Get 3 vessels from the US, from 2 different cities", it queries the database for the next vessel that will satisfy this request, and requests it from the Clearinghouse on the user's behalf.

The database holds information on all the vessels that are registered with the Clearinghouse. It is periodically refreshed (default every 10 minutes), and is also updated dynamically while requests are being serviced through SeleXor.

The web interface's sole purpose is to provide a GUI to interact with SeleXor. It uses Ajax to communicate with a client's machine, and relays user requests to the main selexor server.

Adding New Rules

With the way SeleXor is designed, it is possible to add new rules. There are two components to rules: the parameter preprocessor, and the rule callback. See the respective section for more information on how to define these.

Rule Callbacks

Rule callbacks are functions that take a set of vessels and a dictionary of parameters, and returns a subset of those vessels that satisfy a certain condition. The only difference in terms of signature of Vessel-level and Group-level callbacks are that Group-level callbacks have one extra parameter.

def myrulecallback(
      handleset, # Set(vesselhandle) The set of vessels to check.
      database, # The selexor database instance to use.
      invert, # True/False. Should this rule be inverted?
      parameters, # The parsed parameter dictionary.
      acquired_vessels # The list of currently acquired vessels. This only exists for group-level callbacks!
      ):

  good_handles = set()
  for vessel in handleset:
    if is_handle_good(handle, parameters) ^ invert:
      good_handles.add(handle)
  return good_handles

Parameter Preprocessor

Parameter preprocessors are functions that take a dictionary of rule parameters (generally containing string values) and returns a dictionary with parameters expected by the respective rule callback (in whatever type the callback wants). As such, preprocessors should do 3 things:

  1. Ensure that all required parameters exist.
  2. Convert the raw parameters into a form that is expected by the callback.
  3. Raise errors if the above conditions are not or could not be met.

Do note however, preprocessors are optional. Should you require to use a preprocessor, the template for a preprocessor is:

def myrulepreprocessor(raw_parameters):
  # These should all be strings.
  required_parameters = ['anint', 'astring', ...]

  # Do we have all required parameters?
  for required_parameter in required_parameters:
    if required_parameter not in raw_parameters:
      raise selexorexceptions.MissingParameter(required_parameter)

  # Prepare the processed parameters
  preprocessed_parameters = {}
  preprocessed_parameters['myint'] = int(anint)
  preprocessed_parameters['astring'] = astring

  return preprocessed_parameters

Registering/Deregistering Rules

After defining the above, you are now ready to tell SeleXor to use your rule. Simply add your callback and preprocessor into the _init() function in the module. For rules without preprocessors, simply ignore the last argument. To replace an existing rule, you should first deregister the rule using deregister_callback('rulename').

def _init():
  # Other callbacks are registered before this....
  register_callback('myrulename', 'myruleclassification', mycallback, myrulepreprocessor)