151 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env python3
 | |
| import argparse
 | |
| import threading
 | |
| import importlib
 | |
| import os.path
 | |
| import sys
 | |
| import logging
 | |
| import json
 | |
| 
 | |
| from eca import *
 | |
| import eca.httpd
 | |
| import eca.http
 | |
| 
 | |
| # logging
 | |
| logger = logging.getLogger(__name__)
 | |
| 
 | |
| 
 | |
| def _hr_items(seq):
 | |
|     """Creates a more readable comma-separated list of things."""
 | |
|     return ', '.join("'{}'".format(e) for e in seq)
 | |
| 
 | |
| 
 | |
| def log_level(level):
 | |
|     """argparse type to allow log level to be set directly."""
 | |
|     numeric_level = getattr(logging, level.upper(), None)
 | |
|     if not isinstance(numeric_level, int):
 | |
|         message_template = "'{}' is not a valid logging level. Choose from {}"
 | |
|         message = message_template.format(level, _hr_items(log_level.allowed))
 | |
|         raise argparse.ArgumentTypeError(message)
 | |
|     return numeric_level
 | |
| 
 | |
| 
 | |
| # the following are allowed names for log levels
 | |
| log_level.allowed = ['debug', 'info', 'warning', 'error', 'critical']
 | |
| 
 | |
| 
 | |
| def main_server(args, rules_module):
 | |
|     """HTTP server entry point."""
 | |
|     # determine initial static content path
 | |
|     rules_path = os.path.dirname(os.path.abspath(rules_module.__file__))
 | |
|     rules_file = os.path.basename(os.path.abspath(rules_module.__file__))
 | |
|     rules_file, rules_ext = os.path.splitext(rules_file)
 | |
|     root_path = os.path.join(rules_path, "{}_static".format(rules_file))
 | |
| 
 | |
|     # see if an override has been given (absolute or relative)
 | |
|     if hasattr(rules_module, 'root_content_path'):
 | |
|         if os.path.isabs(rules_module.root_content_path):
 | |
|             root_path = rules_module.root_content_path
 | |
|         else:
 | |
|             root_path = os.path.join(rules_path, rules_module.root_content_path)
 | |
| 
 | |
|     # configure http server
 | |
|     httpd = eca.httpd.HTTPServer((args.ip, args.port))
 | |
| 
 | |
|     # default root route
 | |
|     httpd.add_content('/', root_path)
 | |
| 
 | |
|     # default events route
 | |
|     httpd.add_route('/events', eca.http.EventStream)
 | |
| 
 | |
|     # default handlers for cookies and sessions
 | |
|     httpd.add_filter('/', eca.http.Cookies)
 | |
|     httpd.add_filter('/', eca.http.SessionManager('eca-session'))
 | |
| 
 | |
|     # invoke module specific configuration
 | |
|     if hasattr(rules_module, 'add_request_handlers'):
 | |
|         rules_module.add_request_handlers(httpd)
 | |
| 
 | |
|     # start serving
 | |
|     httpd.serve_forever()
 | |
| 
 | |
| 
 | |
| def main_engine(args, rules_module):
 | |
|     """
 | |
|     Rules engine only entry point.
 | |
|     """
 | |
|     # create context
 | |
|     context = Context(init_data={'name': '__main__'})
 | |
|     context.start(daemon=False)
 | |
| 
 | |
|     # attach printing emit listener to context    
 | |
|     def emitter(name, event):
 | |
|         print("emit '{}': {}".format(event.name, json.loads(event.get('json'))))
 | |
|     context.channel.subscribe(emitter, 'emit')
 | |
| 
 | |
|     # fire main event
 | |
|     with context_switch(context):
 | |
|         logger.info("Starting module '{}'...".format(args.file))
 | |
|         fire('main')
 | |
|         # then read each line and process
 | |
|         for line in sys.stdin:
 | |
|             fire('line', line)
 | |
|         fire('end-of-input')
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     """
 | |
|     Main program entry point.
 | |
|     """
 | |
|     parser = argparse.ArgumentParser(description='The Neca HTTP server.')
 | |
|     parser.set_defaults(entry_point=main_engine)
 | |
|     parser.add_argument('file',
 | |
|                         default='simple.py',
 | |
|                         help="The rules file to load (defaults to %(default)s).",
 | |
|                         nargs='?')
 | |
|     parser.add_argument('-t', '--trace',
 | |
|                         default=False,
 | |
|                         action='store_true',
 | |
|                         help='Trace the execution of rules.')
 | |
|     parser.add_argument('-l', '--log',
 | |
|                         default='warning',
 | |
|                         help="The log level to use. One of {} (defaults to '%(default)s')".format(_hr_items(log_level.allowed)),
 | |
|                         metavar='LEVEL',
 | |
|                         type=log_level)
 | |
|     parser.add_argument('-s', '--server',
 | |
|                         dest='entry_point',
 | |
|                         action='store_const',
 | |
|                         const=main_server,
 | |
|                         help='Start HTTP server instead of directly executing the module.')
 | |
|     parser.add_argument('-p', '--port',
 | |
|                         default=8080,
 | |
|                         help="The port to bind the HTTP server to (default to '%(default)s')",
 | |
|                         type=int)
 | |
|     parser.add_argument('-i', '--ip',
 | |
|                         default='localhost',
 | |
|                         help="The IP to bind the HTTP server to (defaults to '%(default)s'")
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     # set logging level
 | |
|     logging.basicConfig(level=args.log)
 | |
| 
 | |
|     # enable trace logger if requested
 | |
|     if args.trace:
 | |
|         logging.getLogger('trace').setLevel(logging.DEBUG)
 | |
| 
 | |
|     # load module
 | |
|     rules_dir, rules_file = os.path.split(args.file)
 | |
|     rules_name = os.path.splitext(rules_file)[0]
 | |
|     
 | |
|     old_path = list(sys.path)
 | |
|     sys.path.insert(0, rules_dir)
 | |
|     try:
 | |
|         rules_module = importlib.import_module(rules_name)
 | |
|     finally:
 | |
|         sys.path[:] = old_path
 | |
|     
 | |
|     args.entry_point(args, rules_module)
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 | 
