2018-10-10 17:25:03 +00:00
from enum import Enum
2019-02-16 18:40:10 +00:00
from functools import wraps
2019-09-28 01:18:19 +00:00
import importlib
import os
2018-10-10 17:25:03 +00:00
2019-09-23 19:25:08 +00:00
from . log import logger
2019-09-18 16:28:22 +00:00
plugins = { }
2018-03-15 19:04:58 +00:00
cmds = { }
lstnrs = { }
2017-12-06 18:45:34 +00:00
2018-10-10 17:25:03 +00:00
class OutputType ( Enum ) :
Message = ' message '
Action = ' action '
2017-09-27 21:55:00 +00:00
class Output :
def __init__ ( self , msg_type , msg ) :
self . msg_type = msg_type
2017-11-27 05:10:40 +00:00
self . msg = self . sanitize ( msg )
def sanitize ( self , msg ) :
2017-12-06 18:45:34 +00:00
try :
return msg . splitlines ( )
except AttributeError :
return msg
2017-09-27 21:55:00 +00:00
2019-09-28 01:18:19 +00:00
2019-09-18 16:28:22 +00:00
class _BasePlugin :
enabled = True
2019-09-23 19:25:08 +00:00
logger = logger
2019-09-18 16:28:22 +00:00
def enable ( self ) :
self . enabled = True
def disable ( self ) :
self . enabled = False
class Listener ( _BasePlugin ) :
def __init__ ( self , name , run = None ) :
self . name = name
if run :
self . run = run
2019-09-28 01:18:19 +00:00
self . _add_listener ( )
2019-09-18 16:28:22 +00:00
def __str__ ( self ) :
return self . name
def run ( self ) :
pass
2019-09-28 01:18:19 +00:00
def _add_listener ( self ) :
2019-09-18 16:28:22 +00:00
lstnrs [ self . name ] = self
plugins [ self . name ] = self
2017-09-27 21:55:00 +00:00
2019-09-18 16:28:22 +00:00
class Command ( _BasePlugin ) :
2019-09-16 19:27:43 +00:00
def __init__ ( self , cmd , * * kwargs ) :
self . cmd = cmd
2019-09-18 16:28:22 +00:00
self . help_text = kwargs . get ( ' help_text ' , ' N/A ' )
2019-09-12 17:14:56 +00:00
self . ops = kwargs . get ( ' ops ' , False )
self . ops_msg = kwargs . get ( ' ops_msg ' , ' ' )
2019-09-16 19:27:43 +00:00
self . run = kwargs . get ( ' run ' , self . run )
2019-09-28 01:18:19 +00:00
self . _add_command ( )
2019-09-18 16:28:22 +00:00
def __str__ ( self ) :
return self . cmd
2019-09-12 17:14:56 +00:00
def run ( self , msg ) :
pass
2019-09-28 01:18:19 +00:00
def _enable_ops ( self , ops_msg ) :
2019-09-16 19:27:43 +00:00
self . ops = True
self . ops_msg = ops_msg
2019-09-28 01:18:19 +00:00
def _update_plugin ( self , * * kwargs ) :
2019-09-18 16:28:22 +00:00
self . help_text = kwargs . get ( ' help_text ' , ' N/A ' )
2019-09-16 19:27:43 +00:00
self . run = kwargs . get ( ' run ' , self . run )
2019-09-28 01:18:19 +00:00
def _add_command ( self ) :
2019-09-16 19:27:43 +00:00
cmds [ self . cmd ] = self
2019-09-18 16:28:22 +00:00
plugins [ self . cmd ] = self
2019-09-12 17:14:56 +00:00
2017-09-27 21:55:00 +00:00
def action ( msg ) :
2018-10-10 17:25:03 +00:00
return Output ( OutputType . Action , msg )
2017-09-27 21:55:00 +00:00
def message ( msg ) :
2018-10-10 17:25:03 +00:00
return Output ( OutputType . Message , msg )
2017-09-27 21:55:00 +00:00
2019-10-02 16:56:56 +00:00
def _add_command ( command , help_text , func , ops = False , ops_msg = ' ' ) :
2019-02-16 18:40:10 +00:00
if command not in cmds :
2019-10-02 16:56:56 +00:00
Command ( command , help_text = help_text , ops = ops , ops_msg = ops_msg , run = func )
2019-09-16 19:27:43 +00:00
else :
2019-09-28 01:18:19 +00:00
cmds [ command ] . _update_plugin ( help_text = help_text , run = func )
2019-09-16 19:27:43 +00:00
2019-02-16 18:40:10 +00:00
def _ops_plugin ( command , ops_msg , func ) :
if command not in cmds :
2019-09-28 01:18:19 +00:00
Command ( command , ops = True , ops_msg = ops_msg )
2019-09-16 19:27:43 +00:00
else :
2019-09-28 01:18:19 +00:00
cmds [ command ] . _enable_ops ( ops_msg )
2018-03-15 19:04:58 +00:00
def _add_listener ( name , func ) :
2019-09-28 01:18:19 +00:00
Listener ( name , run = func )
2017-09-27 21:55:00 +00:00
2017-11-30 11:12:33 +00:00
def clear_plugins ( ) :
cmds . clear ( )
2017-12-06 19:05:57 +00:00
lstnrs . clear ( )
2017-11-30 11:12:33 +00:00
2019-09-28 01:18:19 +00:00
def load_plugins ( plugin_dir , use_prefix = False , cmd_prefix = ' ! ' ) :
# i'm not sure why i need this but i do
global cmds
global plugins
global lstnrs
#check for all the disabled plugins so that we don't re-enable them
disabled_plugins = [ i for i in plugins if not plugins [ i ] . enabled ]
logger . debug ( disabled_plugins )
# clear plugin list to ensure no old plugins remain
logger . info ( ' clearing plugin cache ' )
clear_plugins ( )
# ensure plugin folder exists
logger . info ( ' checking plugin directory ' )
if not os . path . exists ( plugin_dir ) :
logger . info ( ' plugin directory {} not found, creating ' . format ( plugin_dir ) )
os . makedirs ( plugin_dir )
# load all plugins
for m in os . listdir ( plugin_dir ) :
if m . endswith ( ' .py ' ) :
try :
name = m [ : - 3 ]
logger . info ( ' loading plugin {} ' . format ( name ) )
spec = importlib . machinery . PathFinder ( ) . find_spec ( name , [ plugin_dir ] )
spec . loader . load_module ( )
except Exception :
logger . exception ( ' could not load plugin ' )
# gather all commands and listeners
if use_prefix : # use prefixes if needed
cmds = { cmd_prefix + k : v for k , v in cmds . items ( ) }
for p in plugins :
if p in disabled_plugins :
plugins [ p ] . disable ( )
for cmd in cmds :
logger . debug ( ' adding command {} ' . format ( cmd ) )
for lstnr in lstnrs :
logger . debug ( ' adding listener {} ' . format ( lstnr ) )
2019-10-02 16:56:56 +00:00
def command ( command , help_text = ' N/A ' , ops = False , ops_msg = ' ' ) :
2019-09-23 19:25:08 +00:00
@wraps ( command )
def register_for_command ( func ) :
2019-10-02 16:56:56 +00:00
_add_command ( command , help_text , func , ops = ops , ops_msg = ops_msg )
2019-09-23 19:25:08 +00:00
return func
return register_for_command
2017-11-30 11:12:33 +00:00
2019-09-18 16:28:22 +00:00
def register ( command , help_text = ' N/A ' ) :
2019-09-23 19:25:08 +00:00
logger . warn ( ' @register decorator has been deprecated in favor of @command. This will cause errors in future versions. ' )
2019-02-16 18:40:10 +00:00
@wraps ( command )
2017-09-27 23:54:08 +00:00
def register_for_command ( func ) :
2019-09-16 19:27:43 +00:00
_add_command ( command , help_text , func )
2017-09-27 23:54:08 +00:00
return func
return register_for_command
2017-12-06 18:45:34 +00:00
def listener ( name ) :
def register_as_listener ( func ) :
2018-03-15 19:04:58 +00:00
_add_listener ( name , func )
2017-12-06 18:45:34 +00:00
return func
return register_as_listener
2019-02-16 18:40:10 +00:00
def ops ( command , msg = None ) :
2019-10-02 16:56:56 +00:00
logger . warn ( ' use of the @ops decorator has been deprecated in favor of using the @command decorator with the ops and ops_msg options. Use will cause errors in future versions. ' )
2019-02-16 18:40:10 +00:00
@wraps ( command )
def register_ops_command ( func ) :
_ops_plugin ( command , msg , func )
return func
return register_ops_command