annotate src/plugins/plugin_exp_pubsub_hook.py @ 2307:8fa7edd0da24

plugin Pubsub Hook: first draft: This new plugin allow to attach an external action to a Pubsub event (i.e. notification). Hook can be persitent accross restarts, or temporary (will be deleted on profile disconnection). Only Python files are handled for now. In the future, it may make sense to move hooks in a generic plugin which could be used by ad-hoc commands, messages, pubsub, etc.
author Goffi <goffi@goffi.org>
date Wed, 05 Jul 2017 15:05:47 +0200
parents
children 30278ea1ca7c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2307
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python2
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
3
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
4 # SAT plugin for Pubsub Hooks
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
5 # Copyright (C) 2009-2017 Jérôme Poisson (goffi@goffi.org)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
6
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # This program is free software: you can redistribute it and/or modify
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
10 # (at your option) any later version.
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
11
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # This program is distributed in the hope that it will be useful,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
15 # GNU Affero General Public License for more details.
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
16
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
19
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
20 from sat.core.i18n import _
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
21 from sat.core.constants import Const as C
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from sat.core import exceptions
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from sat.core.log import getLogger
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from sat.memory import persistent
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.protocols.jabber import jid
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from twisted.internet import defer
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 log = getLogger(__name__)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
28
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
29 NS_PUBSUB_HOOK = 'PUBSUB_HOOK'
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
30
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 PLUGIN_INFO = {
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 C.PI_NAME: "PubSub Hook",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 C.PI_IMPORT_NAME: NS_PUBSUB_HOOK,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 C.PI_TYPE: "EXP",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 C.PI_PROTOCOLS: [],
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 C.PI_DEPENDENCIES: ["XEP-0060"],
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 C.PI_MAIN: "PubsubHook",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 C.PI_HANDLER: "no",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 C.PI_DESCRIPTION: _("""Experimental plugin to launch on action on Pubsub notifications""")
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 }
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 # python module
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 HOOK_TYPE_PYTHON = u'python'
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 # python file path
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 HOOK_TYPE_PYTHON_FILE = u'python_file'
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 # python code directly
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 HOOK_TYPE_PYTHON_CODE = u'python_code'
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 HOOK_TYPES = (HOOK_TYPE_PYTHON, HOOK_TYPE_PYTHON_FILE, HOOK_TYPE_PYTHON_CODE)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
49
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
50
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 class PubsubHook(object):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
52
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 def __init__(self, host):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 log.info(_(u"PubSub Hook initialization"))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 self.host = host
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 self.node_hooks = {} # keep track of the number of hooks per node (for all profiles)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 host.bridge.addMethod("psHookAdd", ".plugin",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 in_sign='ssssbs', out_sign='',
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 method=self._addHook
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
60 )
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 host.bridge.addMethod("psHookRemove", ".plugin",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 in_sign='sssss', out_sign='i',
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
63 method=self._removeHook
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 )
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 host.bridge.addMethod("psHookList", ".plugin",
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 in_sign='s', out_sign='aa{ss}',
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 method=self._listHooks
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 )
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
69
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 @defer.inlineCallbacks
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 def profileConnected(self, client):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 hooks = client._hooks = persistent.PersistentBinaryDict(NS_PUBSUB_HOOK, client.profile)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 client._hooks_temporary = {}
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 yield hooks.load()
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 for node in hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 self._installNodeManager(client, node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
77
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 def profileDisconnected(self, client):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 for node in client._hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 self._removeNodeManager(client, node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
81
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 def _installNodeManager(self, client, node):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 if node in self.node_hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 log.debug(_(u"node manager already set for {node}").format(node=node))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 self.node_hooks[node] += 1
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 # first hook on this node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 self.host.plugins['XEP-0060'].addManagedNode(node, items_cb=self._itemsReceived)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 self.node_hooks[node] = 0
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 log.info(_(u"node manager installed on {node}").format(
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 node = node))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
92
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 def _removeNodeManager(self, client, node):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 try:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 self.node_hooks[node] -= 1
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 except KeyError:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 log.error(_(u"trying to remove a {node} without hook").format(node=node))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 if self.node_hooks[node] == 0:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 del self.node_hooks[node]
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 self.host.plugins['XEP-0060'].removeManagedNode(node, self._itemsReceived)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 log.debug(_(u"hook removed"))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 log.debug(_(u"node still needed for an other hook"))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
105
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 def installHook(self, client, service, node, hook_type, hook_arg, persistent):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 if hook_type not in HOOK_TYPES:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 raise exceptions.DataError(_(u'{hook_type} is not handled').format(hook_type=hook_type))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 if hook_type != HOOK_TYPE_PYTHON_FILE:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 raise NotImplementedError(_(u'{hook_type} hook type not implemented yet').format(hook_type=hook_type))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 self._installNodeManager(client, node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 hook_data = {'service': service,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 'type': hook_type,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 'arg': hook_arg
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 }
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
116
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 if persistent:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 hooks_list = client._hooks.setdefault(node,[])
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 hooks_list.append(hook_data)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 client._hooks.force(node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 hooks_list = client._hooks_temporary.setdefault(node,[])
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 hooks_list.append(hook_data)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
124
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 log.info(_(u"{persistent} hook installed on {node} for {profile}").format(
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 persistent = _(u'persistent') if persistent else _(u'temporary'),
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 node = node,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 profile = client.profile))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
129
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 def _itemsReceived(self, client, itemsEvent):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 node = itemsEvent.nodeIdentifier
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 for hooks in (client._hooks, client._hooks_temporary):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 if node not in hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 continue
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 hooks_list = hooks[node]
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 for hook_data in hooks_list[:]:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 if hook_data['service'] != itemsEvent.sender.userhostJID():
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 continue
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 try:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 callback = hook_data['callback']
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 except KeyError:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 # first time we get this hook, we create the callback
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 hook_type = hook_data['type']
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 try:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 if hook_type == HOOK_TYPE_PYTHON_FILE:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 hook_globals = {}
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 execfile(hook_data['arg'], hook_globals)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 callback = hook_globals['hook']
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 raise NotImplementedError(_(u'{hook_type} hook type not implemented yet').format(
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 hook_type=hook_type))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 except Exception as e:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 log.warning(_(u"Can't load Pubsub hook at node {node}, it will be removed: {reason}").format(
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 node=node, reason=e))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 hooks_list.remove(hook_data)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 continue
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
157
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 for item in itemsEvent.items:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 try:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 callback(self.host, client, item)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 except Exception as e:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 log.warning(_(u"Error while running Pubsub hook for node {node}: {msg}").format(
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 node = node,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 msg = e))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
165
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 def _addHook(self, service, node, hook_type, hook_arg, persistent, profile):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 client = self.host.getClient(profile)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 service = jid.JID(service) if service else client.jid.userhostJID()
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 return self.addHook(client, service, unicode(node), unicode(hook_type), unicode(hook_arg), persistent)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
170
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 def addHook(self, client, service, node, hook_type, hook_arg, persistent):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 r"""Add a hook which will be triggered on a pubsub notification
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
173
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 @param service(jid.JID): service of the node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 @param node(unicode): Pubsub node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 @param hook_type(unicode): type of the hook, one of:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 - HOOK_TYPE_PYTHON: a python module (must be in path)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 module must have a "hook" method which will be called
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 - HOOK_TYPE_PYTHON_FILE: a python file
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 file must have a "hook" method which will be called
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 - HOOK_TYPE_PYTHON_CODE: direct python code
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 /!\ Python hooks will be executed in SàT context,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 with host, client and item as arguments, it means that:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 - they can do whatever they wants, so don't run untrusted hooks
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 - they MUST NOT BLOCK, they are run in Twisted async environment and blocking would block whole SàT process
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 - item are domish.Element
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 @param hook_arg(unicode): argument of the hook, depending on the hook_type
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 can be a module path, file path, python code
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 """
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 assert service is not None
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 return self.installHook(client, service, node, hook_type, hook_arg, persistent)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
192
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 def _removeHook(self, service, node, hook_type, hook_arg, profile):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 client = self.host.getClient(profile)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 service = jid.JID(service) if service else client.jid.userhostJID()
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 return self.removeHook(client, service, node, hook_type or None, hook_arg or None)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
197
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 def removeHook(self, client, service, node, hook_type=None, hook_arg=None):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 """Remove a persistent or temporaty root
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
200
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 @param service(jid.JID): service of the node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 @param node(unicode): Pubsub node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 @param hook_type(unicode, None): same as for [addHook]
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 match all if None
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 @param hook_arg(unicode, None): same as for [addHook]
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 match all if None
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 @return(int): number of hooks removed
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 """
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 removed = 0
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 for hooks in (client._hooks, client._hooks_temporary):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 if node in hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 for hook_data in hooks[node]:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 if (service != hook_data[u'service']
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 or hook_type is not None and hook_type != hook_data[u'type']
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 or hook_arg is not None and hook_arg != hook_data[u'arg']):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
216 continue
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 hooks[node].remove(hook_data)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 removed += 1
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 if not hooks[node]:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
220 # no more hooks, we can remove the node
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 del hooks[node]
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 self._removeNodeManager(client, node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 else:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 if hooks == client._hooks:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 hooks.force(node)
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 return removed
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
227
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 def _listHooks(self, profile):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
229 hooks_list = self.listHooks(self.host.getClient(profile))
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 for hook in hooks_list:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 hook[u'service'] = hook[u'service'].full()
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 hook[u'persistent'] = C.boolConst(hook[u'persistent'])
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 return hooks_list
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
234
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 def listHooks(self, client):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 """return list of registered hooks"""
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 hooks_list = []
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 for hooks in (client._hooks, client._hooks_temporary):
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 persistent = hooks is client._hooks
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 for node, hooks_data in hooks.iteritems():
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 for hook_data in hooks_data:
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 hooks_list.append({u'service': hook_data[u'service'],
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 u'node': node,
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 u'type': hook_data[u'type'],
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 u'arg': hook_data[u'arg'],
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 u'persistent': persistent
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 })
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 return hooks_list
8fa7edd0da24 plugin Pubsub Hook: first draft:
Goffi <goffi@goffi.org>
parents:
diff changeset
249