2010-08-05 20:47:46 +02:00
|
|
|
# Copyright (c) 2010, Alexander Cherniuk (ts33kr@gmail.com)
|
|
|
|
# All rights reserved.
|
|
|
|
#
|
|
|
|
# Redistribution and use in source and binary forms, with or without
|
|
|
|
# modification, are permitted provided that the following conditions
|
|
|
|
# are met:
|
|
|
|
#
|
|
|
|
# * Redistributions of source code must retain the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer.
|
|
|
|
#
|
|
|
|
# * Redistributions in binary form must reproduce the above copyright
|
|
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
|
|
# documentation and/or other materials provided with the distribution.
|
|
|
|
#
|
|
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
"""
|
|
|
|
Backbone of the command system. Provides smart and controllable
|
|
|
|
dispatching mechanism with an auto-discovery functionality. In addition
|
|
|
|
to automatic discovery and dispatching, also features manual control
|
|
|
|
over the process.
|
|
|
|
"""
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
from typing import Any # pylint: disable=unused-import
|
|
|
|
from typing import Dict # pylint: disable=unused-import
|
|
|
|
|
2017-06-13 23:58:06 +02:00
|
|
|
from gajim.command_system.tools import remove
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
COMMANDS = {} # type: Dict[Any, Any]
|
|
|
|
CONTAINERS = {} # type: Dict[Any, Any]
|
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
|
|
|
|
def add_host(host):
|
|
|
|
CONTAINERS[host] = []
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def remove_host(host):
|
|
|
|
remove(CONTAINERS, host)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def add_container(container):
|
|
|
|
for host in container.HOSTS:
|
|
|
|
CONTAINERS[host].append(container)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def remove_container(container):
|
|
|
|
for host in container.HOSTS:
|
|
|
|
remove(CONTAINERS[host], container)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def add_commands(container):
|
|
|
|
commands = COMMANDS.setdefault(container, {})
|
|
|
|
for command in traverse_commands(container):
|
|
|
|
for name in command.names:
|
|
|
|
commands[name] = command
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def remove_commands(container):
|
|
|
|
remove(COMMANDS, container)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def traverse_commands(container):
|
|
|
|
for name in dir(container):
|
|
|
|
attribute = getattr(container, name)
|
|
|
|
if is_command(attribute):
|
|
|
|
yield attribute
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def is_command(attribute):
|
2017-06-13 23:58:06 +02:00
|
|
|
from gajim.command_system.framework import Command
|
2010-08-05 20:47:46 +02:00
|
|
|
return isinstance(attribute, Command)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def is_root(namespace):
|
2013-01-02 13:54:02 +01:00
|
|
|
metaclass = namespace.get("__metaclass__", None)
|
2013-01-27 19:51:11 +01:00
|
|
|
if not metaclass:
|
|
|
|
return False
|
2010-08-05 20:47:46 +02:00
|
|
|
return issubclass(metaclass, Dispatchable)
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def get_command(host, name):
|
|
|
|
for container in CONTAINERS[host]:
|
|
|
|
command = COMMANDS[container].get(name)
|
|
|
|
if command:
|
|
|
|
return command
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
def list_commands(host):
|
|
|
|
for container in CONTAINERS[host]:
|
|
|
|
commands = COMMANDS[container]
|
2013-01-02 13:54:02 +01:00
|
|
|
for name, command in commands.items():
|
2010-08-05 20:47:46 +02:00
|
|
|
yield name, command
|
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
class Dispatchable(type):
|
2018-09-12 20:58:48 +02:00
|
|
|
# pylint: disable=no-value-for-parameter
|
2018-09-18 15:45:39 +02:00
|
|
|
def __init__(cls, name, bases, namespace):
|
|
|
|
parents = super(Dispatchable, cls)
|
2010-08-05 20:47:46 +02:00
|
|
|
parents.__init__(name, bases, namespace)
|
|
|
|
if not is_root(namespace):
|
2018-09-18 15:45:39 +02:00
|
|
|
cls.dispatch()
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-18 15:45:39 +02:00
|
|
|
def dispatch(cls):
|
|
|
|
if cls.AUTOMATIC:
|
|
|
|
cls.enable()
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
class Host(Dispatchable):
|
|
|
|
|
2018-09-18 15:45:39 +02:00
|
|
|
def enable(cls):
|
|
|
|
add_host(cls)
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-18 15:45:39 +02:00
|
|
|
def disable(cls):
|
|
|
|
remove_host(cls)
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-13 23:56:12 +02:00
|
|
|
|
2010-08-05 20:47:46 +02:00
|
|
|
class Container(Dispatchable):
|
|
|
|
|
2018-09-18 15:45:39 +02:00
|
|
|
def enable(cls):
|
|
|
|
add_container(cls)
|
|
|
|
add_commands(cls)
|
2010-08-05 20:47:46 +02:00
|
|
|
|
2018-09-18 15:45:39 +02:00
|
|
|
def disable(cls):
|
|
|
|
remove_commands(cls)
|
|
|
|
remove_container(cls)
|