forked from platypush/platypush
Implemented RunnablePlugin.wait_stop() utility method
This commit is contained in:
parent
061268cdaf
commit
d52ae2fb80
3 changed files with 93 additions and 71 deletions
|
@ -19,12 +19,12 @@ def action(f):
|
||||||
result = f(*args, **kwargs)
|
result = f(*args, **kwargs)
|
||||||
|
|
||||||
if result and isinstance(result, Response):
|
if result and isinstance(result, Response):
|
||||||
result.errors = result.errors \
|
result.errors = (
|
||||||
if isinstance(result.errors, list) else [result.errors]
|
result.errors if isinstance(result.errors, list) else [result.errors]
|
||||||
|
)
|
||||||
response = result
|
response = result
|
||||||
elif isinstance(result, tuple) and len(result) == 2:
|
elif isinstance(result, tuple) and len(result) == 2:
|
||||||
response.errors = result[1] \
|
response.errors = result[1] if isinstance(result[1], list) else [result[1]]
|
||||||
if isinstance(result[1], list) else [result[1]]
|
|
||||||
|
|
||||||
if len(response.errors) == 1 and response.errors[0] is None:
|
if len(response.errors) == 1 and response.errors[0] is None:
|
||||||
response.errors = []
|
response.errors = []
|
||||||
|
@ -39,12 +39,14 @@ def action(f):
|
||||||
return _execute_action
|
return _execute_action
|
||||||
|
|
||||||
|
|
||||||
class Plugin(EventGenerator, ExtensionWithManifest): # lgtm [py/missing-call-to-init]
|
class Plugin(EventGenerator, ExtensionWithManifest): # lgtm [py/missing-call-to-init]
|
||||||
""" Base plugin class """
|
"""Base plugin class"""
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.logger = logging.getLogger('platypush:plugin:' + get_plugin_name_by_class(self.__class__))
|
self.logger = logging.getLogger(
|
||||||
|
'platypush:plugin:' + get_plugin_name_by_class(self.__class__)
|
||||||
|
)
|
||||||
if 'logging' in kwargs:
|
if 'logging' in kwargs:
|
||||||
self.logger.setLevel(getattr(logging, kwargs['logging'].upper()))
|
self.logger.setLevel(getattr(logging, kwargs['logging'].upper()))
|
||||||
|
|
||||||
|
@ -53,8 +55,9 @@ class Plugin(EventGenerator, ExtensionWithManifest): # lgtm [py/missing-call-t
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self, method, *args, **kwargs):
|
def run(self, method, *args, **kwargs):
|
||||||
assert method in self.registered_actions, '{} is not a registered action on {}'.\
|
assert (
|
||||||
format(method, self.__class__.__name__)
|
method in self.registered_actions
|
||||||
|
), '{} is not a registered action on {}'.format(method, self.__class__.__name__)
|
||||||
return getattr(self, method)(*args, **kwargs)
|
return getattr(self, method)(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,6 +65,7 @@ class RunnablePlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
Class for runnable plugins - i.e. plugins that have a start/stop method and can be started.
|
Class for runnable plugins - i.e. plugins that have a start/stop method and can be started.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, poll_interval: Optional[float] = None, **kwargs):
|
def __init__(self, poll_interval: Optional[float] = None, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param poll_interval: How often the :meth:`.loop` function should be execute (default: None, no pause/interval).
|
:param poll_interval: How often the :meth:`.loop` function should be execute (default: None, no pause/interval).
|
||||||
|
@ -78,6 +82,9 @@ class RunnablePlugin(Plugin):
|
||||||
def should_stop(self):
|
def should_stop(self):
|
||||||
return self._should_stop.is_set()
|
return self._should_stop.is_set()
|
||||||
|
|
||||||
|
def wait_stop(self, timeout=None):
|
||||||
|
return self._should_stop.wait(timeout)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
set_thread_name(self.__class__.__name__)
|
set_thread_name(self.__class__.__name__)
|
||||||
self._thread = threading.Thread(target=self._runner)
|
self._thread = threading.Thread(target=self._runner)
|
||||||
|
|
|
@ -2,7 +2,11 @@ import os
|
||||||
from typing import Sequence, Dict, Tuple, Union, Optional
|
from typing import Sequence, Dict, Tuple, Union, Optional
|
||||||
|
|
||||||
from platypush.plugins import RunnablePlugin, action
|
from platypush.plugins import RunnablePlugin, action
|
||||||
from platypush.schemas.irc import IRCServerSchema, IRCServerStatusSchema, IRCChannelSchema
|
from platypush.schemas.irc import (
|
||||||
|
IRCServerSchema,
|
||||||
|
IRCServerStatusSchema,
|
||||||
|
IRCChannelSchema,
|
||||||
|
)
|
||||||
|
|
||||||
from ._bot import IRCBot
|
from ._bot import IRCBot
|
||||||
from .. import ChatPlugin
|
from .. import ChatPlugin
|
||||||
|
@ -59,29 +63,19 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _bots_by_server(self) -> Dict[str, IRCBot]:
|
def _bots_by_server(self) -> Dict[str, IRCBot]:
|
||||||
return {
|
return {bot.server: bot for srv, bot in self._bots.items()}
|
||||||
bot.server: bot
|
|
||||||
for srv, bot in self._bots.items()
|
|
||||||
}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _bots_by_server_and_port(self) -> Dict[Tuple[str, int], IRCBot]:
|
def _bots_by_server_and_port(self) -> Dict[Tuple[str, int], IRCBot]:
|
||||||
return {
|
return {(bot.server, bot.port): bot for srv, bot in self._bots.items()}
|
||||||
(bot.server, bot.port): bot
|
|
||||||
for srv, bot in self._bots.items()
|
|
||||||
}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _bots_by_alias(self) -> Dict[str, IRCBot]:
|
def _bots_by_alias(self) -> Dict[str, IRCBot]:
|
||||||
return {
|
return {bot.alias: bot for srv, bot in self._bots.items() if bot.alias}
|
||||||
bot.alias: bot
|
|
||||||
for srv, bot in self._bots.items()
|
|
||||||
if bot.alias
|
|
||||||
}
|
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
self._connect()
|
self._connect()
|
||||||
self._should_stop.wait()
|
self.wait_stop()
|
||||||
|
|
||||||
def _connect(self):
|
def _connect(self):
|
||||||
for srv, bot in self._bots.items():
|
for srv, bot in self._bots.items():
|
||||||
|
@ -109,7 +103,11 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def send_file(
|
def send_file(
|
||||||
self, file: str, server: Union[str, Tuple[str, int]], nick: str, bind_address: Optional[str] = None
|
self,
|
||||||
|
file: str,
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
nick: str,
|
||||||
|
bind_address: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Send a file to an IRC user over DCC connection.
|
Send a file to an IRC user over DCC connection.
|
||||||
|
@ -127,7 +125,10 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def send_message(
|
def send_message(
|
||||||
self, text: str, server: Union[str, Tuple[str, int]], target: Union[str, Sequence[str]]
|
self,
|
||||||
|
text: str,
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
target: Union[str, Sequence[str]],
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Send a message to a channel or a nick.
|
Send a message to a channel or a nick.
|
||||||
|
@ -139,15 +140,14 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
"""
|
"""
|
||||||
bot = self._get_bot(server)
|
bot = self._get_bot(server)
|
||||||
method = (
|
method = (
|
||||||
bot.connection.privmsg if isinstance(target, str)
|
bot.connection.privmsg
|
||||||
|
if isinstance(target, str)
|
||||||
else bot.connection.privmsg_many
|
else bot.connection.privmsg_many
|
||||||
)
|
)
|
||||||
method(target, text)
|
method(target, text)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def send_notice(
|
def send_notice(self, text: str, server: Union[str, Tuple[str, int]], target: str):
|
||||||
self, text: str, server: Union[str, Tuple[str, int]], target: str
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Send a notice to a channel or a nick.
|
Send a notice to a channel or a nick.
|
||||||
|
|
||||||
|
@ -192,22 +192,28 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
channel_name = channel
|
channel_name = channel
|
||||||
channel = bot.channels.get(channel)
|
channel = bot.channels.get(channel)
|
||||||
assert channel, f'Not connected to channel {channel}'
|
assert channel, f'Not connected to channel {channel}'
|
||||||
return IRCChannelSchema().dump({
|
return IRCChannelSchema().dump(
|
||||||
'is_invite_only': channel.is_invite_only(),
|
{
|
||||||
'is_moderated': channel.is_moderated(),
|
'is_invite_only': channel.is_invite_only(),
|
||||||
'is_protected': channel.is_protected(),
|
'is_moderated': channel.is_moderated(),
|
||||||
'is_secret': channel.is_secret(),
|
'is_protected': channel.is_protected(),
|
||||||
'name': channel_name,
|
'is_secret': channel.is_secret(),
|
||||||
'modes': channel.modes,
|
'name': channel_name,
|
||||||
'opers': list(channel.opers()),
|
'modes': channel.modes,
|
||||||
'owners': channel.owners(),
|
'opers': list(channel.opers()),
|
||||||
'users': list(channel.users()),
|
'owners': channel.owners(),
|
||||||
'voiced': list(channel.voiced()),
|
'users': list(channel.users()),
|
||||||
})
|
'voiced': list(channel.voiced()),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def send_ctcp_message(
|
def send_ctcp_message(
|
||||||
self, ctcp_type: str, body: str, server: Union[str, Tuple[str, int]], target: str
|
self,
|
||||||
|
ctcp_type: str,
|
||||||
|
body: str,
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
target: str,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Send a CTCP message to a target.
|
Send a CTCP message to a target.
|
||||||
|
@ -222,7 +228,7 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def send_ctcp_reply(
|
def send_ctcp_reply(
|
||||||
self, body: str, server: Union[str, Tuple[str, int]], target: str
|
self, body: str, server: Union[str, Tuple[str, int]], target: str
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Send a CTCP REPLY command.
|
Send a CTCP REPLY command.
|
||||||
|
@ -235,7 +241,9 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
bot.connection.ctcp_reply(target, body)
|
bot.connection.ctcp_reply(target, body)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def disconnect(self, server: Union[str, Tuple[str, int]], message: Optional[str] = None):
|
def disconnect(
|
||||||
|
self, server: Union[str, Tuple[str, int]], message: Optional[str] = None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Disconnect from a server.
|
Disconnect from a server.
|
||||||
|
|
||||||
|
@ -246,9 +254,7 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
bot.connection.disconnect(message or bot.stop_message)
|
bot.connection.disconnect(message or bot.stop_message)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def invite(
|
def invite(self, nick: str, channel: str, server: Union[str, Tuple[str, int]]):
|
||||||
self, nick: str, channel: str, server: Union[str, Tuple[str, int]]
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Invite a nick to a channel.
|
Invite a nick to a channel.
|
||||||
|
|
||||||
|
@ -272,7 +278,11 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def kick(
|
def kick(
|
||||||
self, nick: str, channel: str, server: Union[str, Tuple[str, int]], reason: Optional[str] = None
|
self,
|
||||||
|
nick: str,
|
||||||
|
channel: str,
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
reason: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Kick a nick from a channel.
|
Kick a nick from a channel.
|
||||||
|
@ -286,9 +296,7 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
bot.connection.kick(channel, nick, reason)
|
bot.connection.kick(channel, nick, reason)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def mode(
|
def mode(self, target: str, command: str, server: Union[str, Tuple[str, int]]):
|
||||||
self, target: str, command: str, server: Union[str, Tuple[str, int]]
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Send a MODE command on the selected target.
|
Send a MODE command on the selected target.
|
||||||
|
|
||||||
|
@ -324,8 +332,10 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def part(
|
def part(
|
||||||
self, channel: Union[str, Sequence[str]], server: Union[str, Tuple[str, int]],
|
self,
|
||||||
message: Optional[str] = None
|
channel: Union[str, Sequence[str]],
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
message: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Parts/exits a channel.
|
Parts/exits a channel.
|
||||||
|
@ -339,9 +349,7 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
bot.connection.part(channels=channels, message=message or bot.stop_message)
|
bot.connection.part(channels=channels, message=message or bot.stop_message)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def quit(
|
def quit(self, server: Union[str, Tuple[str, int]], message: Optional[str] = None):
|
||||||
self, server: Union[str, Tuple[str, int]], message: Optional[str] = None
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Send a QUIT command.
|
Send a QUIT command.
|
||||||
|
|
||||||
|
@ -363,7 +371,12 @@ class ChatIrcPlugin(RunnablePlugin, ChatPlugin):
|
||||||
bot.connection.send_raw(message)
|
bot.connection.send_raw(message)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def topic(self, channel: str, server: Union[str, Tuple[str, int]], topic: Optional[str] = None) -> str:
|
def topic(
|
||||||
|
self,
|
||||||
|
channel: str,
|
||||||
|
server: Union[str, Tuple[str, int]],
|
||||||
|
topic: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Get/set the topic of an IRC channel.
|
Get/set the topic of an IRC channel.
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,11 @@ class GpioPlugin(RunnablePlugin):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
pins: Optional[Dict[str, int]] = None,
|
pins: Optional[Dict[str, int]] = None,
|
||||||
monitored_pins: Optional[Collection[Union[str, int]]] = None,
|
monitored_pins: Optional[Collection[Union[str, int]]] = None,
|
||||||
mode: str = 'board',
|
mode: str = 'board',
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
:param mode: Specify ``board`` if you want to use the board PIN numbers,
|
:param mode: Specify ``board`` if you want to use the board PIN numbers,
|
||||||
|
@ -64,8 +64,9 @@ class GpioPlugin(RunnablePlugin):
|
||||||
self._initialized_pins = {}
|
self._initialized_pins = {}
|
||||||
self._monitored_pins = monitored_pins or []
|
self._monitored_pins = monitored_pins or []
|
||||||
self.pins_by_name = pins if pins else {}
|
self.pins_by_name = pins if pins else {}
|
||||||
self.pins_by_number = {number: name
|
self.pins_by_number = {
|
||||||
for (name, number) in self.pins_by_name.items()}
|
number: name for (name, number) in self.pins_by_name.items()
|
||||||
|
}
|
||||||
|
|
||||||
def _init_board(self):
|
def _init_board(self):
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
@ -98,6 +99,7 @@ class GpioPlugin(RunnablePlugin):
|
||||||
def on_gpio_event(self):
|
def on_gpio_event(self):
|
||||||
def callback(pin: int):
|
def callback(pin: int):
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
value = GPIO.input(pin)
|
value = GPIO.input(pin)
|
||||||
pin = self.pins_by_number.get(pin, pin)
|
pin = self.pins_by_number.get(pin, pin)
|
||||||
get_bus().post(GPIOEvent(pin=pin, value=value))
|
get_bus().post(GPIOEvent(pin=pin, value=value))
|
||||||
|
@ -106,23 +108,23 @@ class GpioPlugin(RunnablePlugin):
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
if not self._monitored_pins:
|
if not self._monitored_pins:
|
||||||
return # No need to start the monitor
|
return # No need to start the monitor
|
||||||
|
|
||||||
self._init_board()
|
self._init_board()
|
||||||
monitored_pins = [
|
monitored_pins = [self._get_pin_number(pin) for pin in self._monitored_pins]
|
||||||
self._get_pin_number(pin) for pin in self._monitored_pins
|
|
||||||
]
|
|
||||||
|
|
||||||
for pin in monitored_pins:
|
for pin in monitored_pins:
|
||||||
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
GPIO.add_event_detect(pin, GPIO.BOTH, callback=self.on_gpio_event())
|
GPIO.add_event_detect(pin, GPIO.BOTH, callback=self.on_gpio_event())
|
||||||
|
|
||||||
self._should_stop.wait()
|
self.wait_stop()
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def write(self, pin: Union[int, str], value: Union[int, bool],
|
def write(
|
||||||
name: Optional[str] = None) -> Dict[str, Any]:
|
self, pin: Union[int, str], value: Union[int, bool], name: Optional[str] = None
|
||||||
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Write a byte value to a pin.
|
Write a byte value to a pin.
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue