summaryrefslogtreecommitdiff
path: root/docs/howto/make_plugin_extension_for_message_and_iq.pl.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/howto/make_plugin_extension_for_message_and_iq.pl.rst')
-rw-r--r--docs/howto/make_plugin_extension_for_message_and_iq.pl.rst689
1 files changed, 344 insertions, 345 deletions
diff --git a/docs/howto/make_plugin_extension_for_message_and_iq.pl.rst b/docs/howto/make_plugin_extension_for_message_and_iq.pl.rst
index 8911ea14..b85c01f5 100644
--- a/docs/howto/make_plugin_extension_for_message_and_iq.pl.rst
+++ b/docs/howto/make_plugin_extension_for_message_and_iq.pl.rst
@@ -1,13 +1,13 @@
Jak stworzyć własny plugin rozszerzający obiekty Message i Iq w Slixmpp
-====================================================================
+========================================================================
Wstęp i wymagania
------------------
+------------------
* `'python3'`
Kod użyty w tutorialu jest kompatybilny z pythonem w wersji 3.6 lub nowszej.
-Dla wstecznej kompatybilności z wcześniejszymi wersjami należy zastąpić f-strings starszym formatowaniem napisów `'"{}".format("content")'` lub `'%s, "content"'`.
+Dla uzyskania kompatybilności z wcześniejszymi wersjami należy zastąpić f-strings starszym formatowaniem napisów `'"{}".format("content")'` lub `'%s, "content"'`.
Instalacja dla Ubuntu linux:
@@ -43,7 +43,7 @@ Wynik w terminalu:
~ $ python3 -c "import argparse; print(argparse.__version__)"
1.1
~ $ python3 -c "import logging; print(logging.__version__)"
- 0.5.1.2
+ 0.5.1.2
~ $ python3 -m subprocess # Nie powinno nic zwrócić
~ $ python3 -m threading # Nie powinno nic zwrócić
@@ -61,12 +61,11 @@ Jeśli jakaś biblioteka zwróci NameError, należy zainstalować pakiet ponowni
* `Konta dla Jabber`
-Do testowania niezbędne będą dwa prywatne konta jabbera. Można je stworzyć na jednym z dostępnych darmowych serwerów:
-
+Do testowania niezbędne będą dwa prywatne konta jabbera. Można je stworzyć na jednym z dostępnych darmowych serwerów:
https://www.google.com/search?q=jabber+server+list
Skrypt uruchamiający klientów
------------------------------
+------------------------------
Skrypt pozwalający testować klientów powinien zostać stworzony poza lokalizacją projektu. Pozwoli to szybko sprawdzać wyniki skryptów oraz uniemożliwi przypadkowe wysłanie swoich danych na gita.
@@ -86,10 +85,10 @@ Taki plik powinien wymagać uprawnień superuser do odczytu i edycji. Plik zawie
import subprocess
import threading
import time
-
+
def start_shell(shell_string):
subprocess.run(shell_string, shell=True, universal_newlines=True)
-
+
if __name__ == "__main__":
#~ prefix = "x-terminal-emulator -e" # Oddzielny terminal dla każdego klienta, można zastąpić własnym emulatorem terminala
#~ prefix = "xterm -e"
@@ -97,24 +96,24 @@ Taki plik powinien wymagać uprawnień superuser do odczytu i edycji. Plik zawie
#~ postfix = " -d" # Debug
#~ postfix = " -q" # Quiet
postfix = ""
-
+
sender_path = "./example/sender.py"
sender_jid = "SENDER_JID"
sender_password = "SENDER_PASSWORD"
-
+
example_file = "./test_example_tag.xml"
-
+
responder_path = "./example/responder.py"
responder_jid = "RESPONDER_JID"
responder_password = "RESPONDER_PASSWORD"
-
+
# Pamiętaj o nadaniu praw do wykonywania (`chmod +x ./file.py`)
SENDER_TEST = f"{prefix} {sender_path} -j {sender_jid} -p {sender_password}" + \
" -t {responder_jid} --path {example_file} {postfix}"
-
+
RESPON_TEST = f"{prefix} {responder_path} -j {responder_jid}" + \
" -p {responder_password} {postfix}"
-
+
try:
responder = threading.Thread(target=start_shell, args=(RESPON_TEST, ))
sender = threading.Thread(target=start_shell, args=(SENDER_TEST, ))
@@ -132,7 +131,7 @@ Skrypt uruchamiający powinien być dostosowany do potrzeb urzytkownika: można
W przypadku testowania większych aplikacji, w tworzeniu pluginu szczególnie użyteczne jest nadanie unikalnych nazwy dla każdego klienta (w konsekwencji: różne linie poleceń). Pozwala to szybko określić, który klient co zwraca, bądź który powoduje błąd.
Stworzenie klienta i pluginu
-----------------------------
+-----------------------------
W stosownej dla nas lokalizacji powinniśmy stworzyć dwa klienty slixmpp (w przykładach: `'sender'` i `'responder'`), aby sprawdzić czy skrypt uruchamiający działa poprawnie. Poniżej przedstawiona została minimalna niezbędna implementacja, która może testować plugin w trakcie jego projektowania:
@@ -143,36 +142,36 @@ W stosownej dla nas lokalizacji powinniśmy stworzyć dwa klienty slixmpp (w prz
from argparse import ArgumentParser
from getpass import getpass
import time
-
+
import slixmpp
from slixmpp.xmlstream import ET
-
+
import example_plugin
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
- def start(self, event):
- # Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online.
- self.send_presence()
- self.get_roster()
+ def start(self, event):
+ # Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online.
+ self.send_presence()
+ self.get_roster()
if __name__ == '__main__':
parser = ArgumentParser(description=Sender.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
@@ -181,17 +180,17 @@ W stosownej dla nas lokalizacji powinniśmy stworzyć dwa klienty slixmpp (w prz
help="JID to send the message/iq to")
parser.add_argument("--path", dest="path",
help="path to load example_tag content")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Sender(args.jid, args.password, args.to, args.path)
#xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPlugin jest nazwą klasy example_plugin.
@@ -210,16 +209,16 @@ W stosownej dla nas lokalizacji powinniśmy stworzyć dwa klienty slixmpp (w prz
import logging
from argparse import ArgumentParser
from getpass import getpass
-
+
import slixmpp
import example_plugin
-
+
class Responder(slixmpp.ClientXMPP):
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.add_event_handler("session_start", self.start)
-
+
def start(self, event):
# Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online
self.send_presence()
@@ -227,34 +226,34 @@ W stosownej dla nas lokalizacji powinniśmy stworzyć dwa klienty slixmpp (w prz
if __name__ == '__main__':
parser = ArgumentParser(description=Responder.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-t", "--to", dest="to",
help="JID to send the message to")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Responder(args.jid, args.password)
xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPlugin jest nazwą klasy example_plugin
-
+
xmpp.connect()
try:
xmpp.process()
@@ -268,35 +267,35 @@ Następny plik, który należy stworzyć to `'example_plugin'`. Powinien być w
.. code-block:: python
- #File: $WORKDIR/example/example plugin.py
+ #File: $WORKDIR/example/example_plugin.py
import logging
-
+
from slixmpp.xmlstream import ElementBase, ET, register_stanza_plugin
-
+
from slixmpp import Iq
from slixmpp import Message
-
+
from slixmpp.plugins.base import BasePlugin
-
+
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
-
+
log = logging.getLogger(__name__)
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ Napis czytelny dla człowieka i dla znalezienia pluginu przez inny plugin
self.xep = "ope" ##~ Napis czytelny dla człowieka i dla znalezienia pluginu przez inny plugin poprzez dodanie tego do `slixmpp/plugins/__init__.py`, w polu `__all__` z prefixem xep 'xep_OPE'.
-
+
namespace = ExampleTag.namespace
class ExampleTag(ElementBase):
name = "example_tag" ##~ Nazwa głównego pliku XML w tym rozszerzeniu.
namespace = "https://example.net/our_extension" ##~ Namespace obiektu jest definiowana w tym miejscu, powinien się odnosić do nazwy portalu xmpp; w wiadomości wygląda tak: <example_tag xmlns={namespace} (...)</example_tag>
-
+
plugin_attrib = "example_tag" ##~ Nazwa pod którą można odwoływać się do danych zawartych w tym pluginie. Bardziej szczegółowo: tutaj rejestrujemy nazwę obiektu by móc się do niego odwoływać z zewnątrz. Można się do niego odwoływać jak do słownika: stanza_object['example_tag'], gdzie `'example_tag'` jest nazwą pluginu i powinno być takie samo jak name.
-
+
interfaces = {"boolean", "some_string"} ##~ Zbiór kluczy dla słownika atrybutów elementu które mogą być użyte w elemencie. Na przykład `stanza_object['example_tag']` poda informacje o: {"boolean": "some", "some_string": "some"}, tam gdzie `'example_tag'` jest elementu.
Jeżeli powyższy plugin nie jest w domyślnej lokalizacji, a klienci powinni pozostać poza repozytorium, możemy w miejscu klientów dodać dowiązanie symboliczne do lokalizacji pluginu:
@@ -339,14 +338,14 @@ Przykład:
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
def start(self, event):
@@ -355,28 +354,28 @@ Przykład:
self.get_roster()
#>>>>>>>>>>>>
self.send_example_message(self.to, "example_message")
-
+
def send_example_message(self, to, body):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
- # Domyślnie mtype == "chat";
+ # Domyślnie mtype == "chat";
msg = self.make_message(mto=to, mbody=body)
msg.send()
#<<<<<<<<<<<<
-W przykładzie powyżej, używana jest wbudowana metoda `'make_message'`, która tworzy wiadomość o treści `'example_message'` i wysyła ją pod koniec działania metody start. Czyli: wiadomość ta zostanie wysłana raz, zaraz po uruchomieniu skryptu.
+W przykładzie powyżej, używana jest wbudowana metoda `'make_message'`, która tworzy wiadomość o treści `'example_message'` i wysyła ją pod koniec działania metody start. Czyli: wiadomość ta zostanie wysłana raz, zaraz po uruchomieniu skryptu.
Aby otrzymać tę wiadomość, responder powinien wykorzystać odpowiedni event: metodę, która określa co zrobić, gdy zostanie odebrana wiadomość której nie został przypisany żaden inny event. Przykład takiego kodu:
.. code-block:: python
#File: $WORKDIR/example/responder.py
-
+
class Responder(slixmpp.ClientXMPP):
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.add_event_handler("session_start", self.start)
-
+
#>>>>>>>>>>>>
self.add_event_handler("message", self.message)
#<<<<<<<<<<<<
@@ -385,7 +384,7 @@ Aby otrzymać tę wiadomość, responder powinien wykorzystać odpowiedni event:
# Metody niewymagane, ale pozwalające na zobaczenie dostępności online.
self.send_presence()
self.get_roster()
-
+
#>>>>>>>>>>>>
def message(self, msg):
#Pokazuje cały XML wiadomości
@@ -395,19 +394,19 @@ Aby otrzymać tę wiadomość, responder powinien wykorzystać odpowiedni event:
#<<<<<<<<<<<<
Rozszerzenie Message o nowy tag
--------------------------
+--------------------------------
Aby rozszerzyć obiekt Message o wybrany tag, plugin powinien zostać zarejestrowany jako rozszerzenie dla obiektu Message:
.. code-block:: python
#File: $WORKDIR/example/example plugin.py
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin.
self.xep = "ope" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin przez dodanie go do `slixmpp/plugins/__init__.py` w metodzie `__all__` z 'xep_OPE'.
-
+
namespace = ExampleTag.namespace
#>>>>>>>>>>>>
register_stanza_plugin(Message, ExampleTag) ##~ Zarejestrowany rozszerzony tag dla obiektu Message. Jeśli to nie zostanie zrobione, message['example_tag'] będzie polem tekstowym, a nie rozszerzeniem i nie będzie mogło zawierać atrybutów i pod-elementów.
@@ -416,15 +415,15 @@ Aby rozszerzyć obiekt Message o wybrany tag, plugin powinien zostać zarejestro
class ExampleTag(ElementBase):
name = "example_tag" ##~ Nazwa głównego pliku XML dla tego rozszerzenia..
namespace = "https://example.net/our_extension" ##~ Nazwa obiektu, np. <example_tag xmlns={namespace} (...)</example_tag>. Powinna zostać zmieniona na własną.
-
+
plugin_attrib = "example_tag" ##~ Nazwa, którą można odwołać się do obiektu. W szczególności, do zarejestrowanego obiektu można odwołać się przez: nazwa_obiektu['tag']. gdzie `'tag'` jest nazwą ElementBase extension. Nazwa powinna być taka sama jak "name" wyżej.
-
+
interfaces = {"boolean", "some_string"} ##~ Lista kluczy słownika, które mogą być użyte z obiektem. Na przykład: `stanza_object['example_tag']` zwraca {"another": "some", "data": "some"}, gdzie `'example_tag'` jest nazwą rozszerzenia ElementBase.
#>>>>>>>>>>>>
def set_boolean(self, boolean):
self.xml.attrib['boolean'] = str(boolean)
-
+
def set_some_string(self, some_string):
self.xml.attrib['some_string'] = some_string
#<<<<<<<<<<<<
@@ -434,14 +433,14 @@ Teraz, po rejestracji tagu, można rozszerzyć wiadomość.
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
def start(self, event):
@@ -449,13 +448,13 @@ Teraz, po rejestracji tagu, można rozszerzyć wiadomość.
self.send_presence()
self.get_roster()
self.send_example_message(self.to, "example_message")
-
+
def send_example_message(self, to, body):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
- # Default mtype == "chat";
+ # Default mtype == "chat";
msg = self.make_message(mto=to, mbody=body)
#>>>>>>>>>>>>
- msg['example_tag'].set_some_string("Work!")
+ msg['example_tag']['some_string'] = "Work!"
logging.info(msg)
#<<<<<<<<<<<<
msg.send()
@@ -463,19 +462,19 @@ Teraz, po rejestracji tagu, można rozszerzyć wiadomość.
Po uruchomieniu, logging powinien wyświetlić Message wraz z tagiem `'example_tag'` zawartym w środku <message><example_tag/></message>, oraz z napisem `'Work'` i nadanym namespace.
Nadanie oddzielnego sygnału dla rozszerzonej wiadomości
--------------------------
+--------------------------------------------------------
Jeśli event nie zostanie sprecyzowany, to zarówno rozszerzona jak i podstawowa wiadomość będą przechwytywane przez sygnał `'message'`. Aby nadać im oddzielny event, należy zarejestrować odpowiedni handler dla namespace'a i tagu, aby stworzyć unikalną kombinację, która pozwoli na przechwycenie wyłącznie pożądanych wiadomości (lub Iq object).
.. code-block:: python
#File: $WORKDIR/example/example plugin.py
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin.
self.xep = "ope" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin przez dodanie go do `slixmpp/plugins/__init__.py` w metodzie `__all__` z 'xep_OPE'.
-
+
namespace = ExampleTag.namespace
self.xmpp.register_handler(
@@ -501,14 +500,14 @@ Teraz, program przechwyci wszystkie message, które zawierają sprecyzowany name
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
def start(self, event):
@@ -517,10 +516,10 @@ Teraz, program przechwyci wszystkie message, które zawierają sprecyzowany name
self.get_roster()
#>>>>>>>>>>>>
self.send_example_message(self.to, "example_message", "example_string")
-
+
def send_example_message(self, to, body, some_string=""):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
- # Default mtype == "chat";
+ # Default mtype == "chat";
msg = self.make_message(mto=to, mbody=body)
if some_string:
msg['example_tag'].set_some_string(some_string)
@@ -532,11 +531,11 @@ Należy zapamiętać linię: `'self.xmpp.event('example_tag_message', msg)'`. W
.. code-block:: python
#File: $WORKDIR/example/responder.py
-
+
class Responder(slixmpp.ClientXMPP):
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.add_event_handler("session_start", self.start)
#>>>>>>>>>>>>
self.add_event_handler("example_tag_message", self.example_tag_message) # Rejestracja handlera
@@ -546,92 +545,92 @@ Należy zapamiętać linię: `'self.xmpp.event('example_tag_message', msg)'`. W
# Metody niewymagane, ale pozwalające na zobaczenie dostępności online.
self.send_presence()
self.get_roster()
-
+
#>>>>>>>>>>>>
def example_tag_message(self, msg):
logging.info(msg) # Message jest obiektem który nie wymaga wiadomości zwrotnej, ale nic się nie stanie, gdy zostanie wysłana.
#<<<<<<<<<<<<
-Można odesłać wiadomość, ale nic się nie stanie jeśli to nie zostanie zrobione.
+Można odesłać wiadomość, ale nic się nie stanie jeśli to nie zostanie zrobione.
Natomiast obiekt komunikacji (Iq) już będzie wymagał odpowiedzi, więc obydwaj klienci powinni pozostawać online. W innym wypadku, klient otrzyma automatyczny error z powodu timeoutu, jeśli cell Iq nie odpowie za pomocą Iq o tym samym Id.
Użyteczne metody i inne
------------------------
+------------------------
Modyfikacja przykładowego obiektu `Message` na obiekt `Iq`
--------------------------
+----------------------------------------------------------
-Aby przerobić przykładowy obiekt Message na obiekt Iq, należy zarejestrować nowy handler dla Iq, podobnie jak zostało to przedstawione w rozdziale `"Rozszerzenie Message o tag"`. Tym razem, przykład będzie zawierał kilka rodzajów Iq o oddzielnych typami. Poprawia to czytelność kodu oraz usprawnia weryfikację poprawności działania. Wszystkie Iq powinny odesłać odpowiedź z tym samym Id i odpowiedzią do wysyłającego. W przeciwnym wypadku, wysyłający dostanie Iq zwrotne typu error, zawierające informacje o przekroczonym czasie oczekiwania (timeout).
+Aby przerobić przykładowy obiekt Message na obiekt Iq, należy zarejestrować nowy handler dla Iq, podobnie jak zostało to przedstawione w rozdziale `,,Rozszerzenie Message o tag''`. Tym razem, przykład będzie zawierał kilka rodzajów Iq o oddzielnych typami. Poprawia to czytelność kodu oraz usprawnia weryfikację poprawności działania. Wszystkie Iq powinny odesłać odpowiedź z tym samym Id i odpowiedzią do wysyłającego. W przeciwnym wypadku, wysyłający dostanie Iq zwrotne typu error.
.. code-block:: python
#File: $WORKDIR/example/example plugin.py
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin.
self.xep = "ope" ##~ String zrozumiały dla ludzi oraz do znalezienia pluginu przez inny plugin przez dodanie go do `slixmpp/plugins/__init__.py` w metodzie `__all__` z 'xep_OPE'.
-
+
namespace = ExampleTag.namespace
#>>>>>>>>>>>>
self.xmpp.register_handler(
Callback('ExampleGet Event:example_tag', ##~ Nazwa tego Callbacka
StanzaPath(f"iq@type=get/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'get' oraz example_tag
self.__handle_get_iq)) ##~ Metoda obsługująca odpowiednie Iq, powinna wywołać event dla klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleResult Event:example_tag', ##~ Nazwa tego Callbacka
StanzaPath(f"iq@type=result/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'result' oraz example_tag
self.__handle_result_iq)) ##~ Metoda obsługująca odpowiednie Iq, powinna wywołać event dla klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleError Event:example_tag', ##~ Nazwa tego Callbacka
StanzaPath(f"iq@type=error/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'error' oraz example_tag
self.__handle_error_iq)) ##~ Metoda obsługująca odpowiednie Iq, powinna wywołać event dla klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleMessage Event:example_tag',##~ Nazwa tego Callbacka
StanzaPath(f'message/{{{namespace}}}example_tag'), ##~ Obsługuje tylko Iq z example_tag
self.__handle_message)) ##~ Metoda obsługująca odpowiednie Iq, powinna wywołać event dla klienta.
-
+
register_stanza_plugin(Iq, ExampleTag) ##~ Rejestruje rozszerzenie taga dla obiektu Iq. W przeciwnym wypadku, Iq['example_tag'] będzie polem string zamiast kontenerem.
#<<<<<<<<<<<<
register_stanza_plugin(Message, ExampleTag) ##~ Rejestruje rozszerzenie taga dla obiektu Message. W przeciwnym wypadku, message['example_tag'] będzie polem string zamiast kontenerem.
-
+
#>>>>>>>>>>>>
# Wszystkie możliwe typy Iq to: get, set, error, result
def __handle_get_iq(self, iq):
# Zrób coś z otrzymanym iq
self.xmpp.event('example_tag_get_iq', iq) ##~ Wywołuje event, który może być obsłużony przez klienta lub inaczej.
-
+
def __handle_result_iq(self, iq):
# Zrób coś z otrzymanym Iq
self.xmpp.event('example_tag_result_iq', iq) ##~ Wywołuje event, który może być obsłużony przez klienta lub inaczej.
-
+
def __handle_error_iq(self, iq):
# Zrób coś z otrzymanym Iq
self.xmpp.event('example_tag_error_iq', iq) ##~ Wywołuje event, który może być obsłużony przez klienta lub inaczej.
-
+
def __handle_message(self, msg):
# Zrób coś z otrzymanym message
self.xmpp.event('example_tag_message', msg) ##~ Wywołuje event, który może być obsłużony przez klienta lub inaczej.
Eventy wywołane przez powyższe handlery mogą zostać przechwycone tak, jak w przypadku eventu `'example_tag_message'`.
-
+
.. code-block:: python
#File: $WORKDIR/example/responder.py
-
+
class Responder(slixmpp.ClientXMPP):
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_message", self.example_tag_message)
#>>>>>>>>>>>>
self.add_event_handler("example_tag_get_iq", self.example_tag_get_iq)
#<<<<<<<<<<<<
-
+
#>>>>>>>>>>>>
def example_tag_get_iq(self, iq): # Iq stanza powinno zawsze zostać zwrócone, w innym wypadku wysyłający dostanie informacje z błędem.
logging.info(str(iq))
@@ -644,31 +643,31 @@ Domyślnie parametr `'clear'` dla `'Iq.reply'` jest ustawiony na True. Wtedy to,
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
#>>>>>>>>>>>>
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
#<<<<<<<<<<<<
-
+
def start(self, event):
# Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online
self.send_presence()
self.get_roster()
- #>>>>>>>>>>>>
+ #>>>>>>>>>>>>
self.send_example_iq(self.to)
# <iq to=RESPONDER/RESOURCE xml:lang="en" type="get" id="0" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string" boolean="True">Info_inside_tag</example_tag></iq>
#<<<<<<<<<<<<
-
- #>>>>>>>>>>>>
+
+ #>>>>>>>>>>>>
def send_example_iq(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get")
@@ -677,11 +676,11 @@ Domyślnie parametr `'clear'` dla `'Iq.reply'` jest ustawiony na True. Wtedy to,
iq['example_tag'].text = "Info_inside_tag"
iq.send()
#<<<<<<<<<<<<
-
+
#>>>>>>>>>>>>
def example_tag_result_iq(self, iq):
logging.info(str(iq))
-
+
def example_tag_error_iq(self, iq):
logging.info(str(iq))
#<<<<<<<<<<<<
@@ -694,7 +693,7 @@ Jest kilka możliwości dostania się do pól wewnątrz Message lub Iq. Po pierw
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
#...
def example_tag_result_iq(self, iq):
@@ -716,44 +715,44 @@ Z rozszerzenia ExampleTag, dostęp do elementów jest podobny, tyle że, nie wym
class ExampleTag(ElementBase):
name = "example_tag" ##~ Nazwa głównego pliku XML tego rozszerzenia.
namespace = "https://example.net/our_extension" ##~ Nazwa obiektu, np. <example_tag xmlns={namespace} (...)</example_tag>. Powinna zostać zmieniona na własną.
-
+
plugin_attrib = "example_tag" ##~ Nazwa, którą można odwołać się do obiektu. W szczególności, do zarejestrowanego obiektu można odwołać się przez: nazwa_obiektu['tag']. gdzie `'tag'` jest nazwą ElementBase extension. Nazwa powinna być taka sama jak "name" wyżej.
-
+
interfaces = {"boolean", "some_string"} ##~ Lista kluczy słownika, które mogą być użyte z obiektem. Na przykład: `stanza_object['example_tag']` zwraca {"another": "some", "data": "some"}, gdzie `'example_tag'` jest nazwą rozszerzenia ElementBase.
-
+
#>>>>>>>>>>>>
def get_some_string(self):
return self.xml.attrib.get("some_string", None)
-
+
def get_text(self, text):
return self.xml.text
-
+
def set_some_string(self, some_string):
self.xml.attrib['some_string'] = some_string
-
+
def set_text(self, text):
self.xml.text = text
#<<<<<<<<<<<<
-Atrybut `'self.xml'` jest dziedziczony z klasy `'ElementBase'` i jest to dosłownie `'Element'` z pakietu `'ElementTree'`.
+Atrybut `'self.xml'` jest dziedziczony z klasy `'ElementBase'` i jest to dosłownie `'Element'` z pakietu `'ElementTree'`.
Kiedy odpowiednie gettery i settery są tworzone, można sprawdzić, czy na pewno podany argument spełnia normy pluginu lub konwersję na pożądany typ. Dodatkowo, kod staje się bardziej przejrzysty w standardach programowania obiektowego, jak na poniższym przykładzie:
-
+
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
-
+
def send_example_iq(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get")
@@ -765,7 +764,7 @@ Kiedy odpowiednie gettery i settery są tworzone, można sprawdzić, czy na pewn
iq.send()
Wczytanie ExampleTag ElementBase z pliku XML, łańcucha znaków i innych obiektów
--------------------------
+--------------------------------------------------------------------------------
Jest wiele możliwości na wczytanie wcześniej zdefiniowanego napisu z pliku albo lxml (ElementTree). Poniższy przykład wykorzystuje parsowanie typu tekstowego do lxml (ElementTree) i przekazanie atrybutów.
@@ -780,22 +779,22 @@ Jest wiele możliwości na wczytanie wcześniej zdefiniowanego napisu z pliku al
class ExampleTag(ElementBase):
name = "example_tag" ##~ Nazwa głównego pliku XML tego rozszerzenia.
namespace = "https://example.net/our_extension" ##~ Nazwa obiektu, np. <example_tag xmlns={namespace} (...)</example_tag>. Powinna zostać zmieniona na własną.
-
+
plugin_attrib = "example_tag" ##~ Nazwa, którą można odwołać się do obiektu. W szczególności, do zarejestrowanego obiektu można odwołać się przez: nazwa_obiektu['tag']. gdzie `'tag'` jest nazwą ElementBase extension. Nazwa powinna być taka sama jak "name" wyżej.
-
+
interfaces = {"boolean", "some_string"} ##~ Lista kluczy słownika, które mogą być użyte z obiektem. Na przykład: `stanza_object['example_tag']` zwraca {"another": "some", "data": "some"}, gdzie `'example_tag'` jest nazwą rozszerzenia ElementBase.
-
+
#>>>>>>>>>>>>
def setup_from_string(self, string):
"""Initialize tag element from string"""
et_extension_tag_xml = ET.fromstring(string)
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_file(self, path):
"""Initialize tag element from file containing adjusted data"""
et_extension_tag_xml = ET.parse(path).getroot()
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_lxml(self, lxml):
"""Add ET data to self xml structure."""
self.xml.attrib.update(lxml.attrib)
@@ -806,7 +805,7 @@ Jest wiele możliwości na wczytanie wcześniej zdefiniowanego napisu z pliku al
#<<<<<<<<<<<<
Do przetestowania tej funkcjonalności, potrzebny jest pliku zawierający xml z tagiem, przykładowy napis z xml oraz przykładowy lxml (ET):
-
+
.. code-block:: xml
#File: $WORKDIR/test_example_tag.xml
@@ -820,69 +819,69 @@ Do przetestowania tej funkcjonalności, potrzebny jest pliku zawierający xml z
#...
from slixmpp.xmlstream import ET
#...
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
-
+
def start(self, event):
# Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online
self.send_presence()
self.get_roster()
-
+
#>>>>>>>>>>>>
- self.disconnect_counter = 3 # Ta zmienna służy tylko do rozłączenia klienta po otrzymaniu odpowiedniej ilości odpowiedzi z Iq.
-
+ self.disconnect_counter = 3 # Ta zmienna służy tylko do rozłączenia klienta po otrzymaniu odpowiedniej ilości odpowiedzi z Iq.
+
self.send_example_iq_tag_from_file(self.to, self.path)
# <iq from="SENDER/RESOURCE" xml:lang="en" id="2" type="get" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
string = '<example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag>'
et = ET.fromstring(string)
self.send_example_iq_tag_from_element_tree(self.to, et)
# <iq to="RESPONDER/RESOURCE" id="3" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
+
self.send_example_iq_tag_from_string(self.to, string)
- # <iq to="RESPONDER/RESOURCE" id="5" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
+ # <iq to="RESPONDER/RESOURCE" id="5" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
def example_tag_result_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Przykład rozłączania się aplikacji po uzyskaniu odpowiedniej ilości odpowiedzi.
-
+
def send_example_iq_tag_from_file(self, to, path):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=2)
iq['example_tag'].setup_from_file(path)
-
+
iq.send()
-
+
def send_example_iq_tag_from_element_tree(self, to, et):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=3)
iq['example_tag'].setup_from_lxml(et)
-
+
iq.send()
-
+
def send_example_iq_tag_from_string(self, to, string):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=5)
iq['example_tag'].setup_from_string(string)
-
+
iq.send()
#<<<<<<<<<<<<
Jeśli Responder zwróci wysłane Iq, a Sender wyłączy się po trzech odpowiedziach, wtedy wszystko działa tak, jak powinno.
Łatwość użycia pluginu dla programistów
---------------------------------------
+----------------------------------------
Każdy plugin powinien posiadać pewne obiektowe metody: wczytanie danych, jak w przypadku metod `setup` z poprzedniego rozdziału, gettery, settery, czy wywoływanie odpowiednich eventów.
Potencjalne błędy powinny być przechwytywane z poziomu pluginu i zwracane z odpowiednim opisem błędu w postaci odpowiedzi Iq o tym samym id do wysyłającego. Aby uniknąć sytuacji kiedy plugin nie robi tego co powinien, a wiadomość zwrotna nigdy nie nadchodzi, wysyłający dostaje error z komunikatem timeout.
@@ -896,46 +895,46 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
import logging
from slixmpp.xmlstream import ElementBase, ET, register_stanza_plugin
-
+
from slixmpp import Iq
from slixmpp import Message
-
+
from slixmpp.plugins.base import BasePlugin
-
+
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
-
+
log = logging.getLogger(__name__)
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ Tekst czytelny dla człowieka oraz do znalezienia pluginu przez inny plugin.
self.xep = "ope" ##~ Tekst czytelny dla człowieka oraz do znalezienia pluginu przez inny plugin poprzez dodanie go do `slixmpp/plugins/__init__.py` do funkcji `__all__` z 'xep_OPE'.
-
+
namespace = ExampleTag.namespace
self.xmpp.register_handler(
Callback('ExampleGet Event:example_tag', ##~ Nazwa tego Callbacku
StanzaPath(f"iq@type=get/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'get' oraz example_tag
self.__handle_get_iq)) ##~ Metoda przechwytuje odpowiednie Iq, powinna wywołać event u klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleGet Event:example_tag', ##~ Nazwa tego Callbacku
StanzaPath(f"iq@type=get/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'result' oraz example_tag
self.__handle_get_iq)) ##~ Metoda przechwytuje odpowiednie Iq, powinna wywołać event u klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleGet Event:example_tag', ##~ Nazwa tego Callbacku
StanzaPath(f"iq@type=get/{{{namespace}}}example_tag"), ##~ Obsługuje tylko Iq o typie 'error' oraz example_tag
self.__handle_get_iq)) ##~ Metoda przechwytuje odpowiednie Iq, powinna wywołać event u klienta.
-
+
self.xmpp.register_handler(
Callback('ExampleMessage Event:example_tag',##~ Nazwa tego Callbacku
StanzaPath(f'message/{{{namespace}}}example_tag'), ##~ Obsługuje tylko Message z example_tag
self.__handle_message)) ##~ Metoda przechwytuje odpowiednie Iq, powinna wywołać event u klienta.
-
+
register_stanza_plugin(Iq, ExampleTag) ##~ Zarejestrowane rozszerzenia tagu dla Iq. Bez tego, iq['example_tag'] będzie polem tekstowym, a nie kontenerem i nie będzie można zmieniać w nim pól i tworzyć pod-elementów.
register_stanza_plugin(Message, ExampleTag) ##~ Zarejestrowane rozszerzenia tagu dla Message. Bez tego, message['example_tag'] będzie polem tekstowym, a nie kontenerem i nie będzie można zmieniać w nim pól i tworzyć pod-elementów.
-
+
# Wszystkie możliwe typy iq: get, set, error, result
def __handle_get_iq(self, iq):
if iq.get_some_string is None:
@@ -946,37 +945,37 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
error.send()
# Zrób coś z otrzymanym Iq
self.xmpp.event('example_tag_get_iq', iq) ##~ Wywołanie eventu, który może być przesłany do klienta lub zmieniony po drodze.
-
+
def __handle_result_iq(self, iq):
# Zrób coś z otrzymanym Iq
self.xmpp.event('example_tag_result_iq', iq) ##~ Wywołanie eventu, który może być przesłany do klienta lub zmieniony po drodze.
-
+
def __handle_error_iq(self, iq):
# Zrób coś z otrzymanym Iq
self.xmpp.event('example_tag_error_iq', iq) ##~ Wywołanie eventu, który może być przesłany do klienta lub zmieniony po drodze.
-
+
def __handle_message(self, msg):
# Zrób coś z otrzymanym Message
self.xmpp.event('example_tag_message', msg) ##~ Wywołanie eventu, który może być przesłany do klienta lub zmieniony po drodze.
-
+
class ExampleTag(ElementBase):
name = "example_tag" ##~ Nazwa głównego pliku XML tego rozszerzenia.
namespace = "https://example.net/our_extension" ##~ Nazwa obiektu, np. <example_tag xmlns={namespace} (...)</example_tag>. Powinna zostać zmieniona na własną.
-
+
plugin_attrib = "example_tag" ##~ Nazwa, którą można odwołać się do obiektu. W szczególności, do zarejestrowanego obiektu można odwołać się przez: nazwa_obiektu['tag']. gdzie `'tag'` jest nazwą ElementBase extension. Nazwa powinna być taka sama jak "name" wyżej.
-
+
interfaces = {"boolean", "some_string"} ##~ Lista kluczy słownika, które mogą być użyte z obiektem. Na przykład: `stanza_object['example_tag']` zwraca {"another": "some", "data": "some"}, gdzie `'example_tag'` jest nazwą rozszerzenia ElementBase.
-
+
def setup_from_string(self, string):
"""Initialize tag element from string"""
et_extension_tag_xml = ET.fromstring(string)
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_file(self, path):
"""Initialize tag element from file containing adjusted data"""
et_extension_tag_xml = ET.parse(path).getroot()
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_lxml(self, lxml):
"""Add ET data to self xml structure."""
self.xml.attrib.update(lxml.attrib)
@@ -988,25 +987,25 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
def setup_from_dict(self, data):
#Poprawnośc kluczy słownika powinna być sprawdzona
self.xml.attrib.update(data)
-
+
def get_boolean(self):
return self.xml.attrib.get("boolean", None)
-
+
def get_some_string(self):
return self.xml.attrib.get("some_string", None)
-
+
def get_text(self, text):
return self.xml.text
-
+
def set_boolean(self, boolean):
self.xml.attrib['boolean'] = str(boolean)
-
+
def set_some_string(self, some_string):
self.xml.attrib['some_string'] = some_string
-
+
def set_text(self, text):
self.xml.text = text
-
+
def fill_interfaces(self, boolean, some_string):
#Jakaś walidacja, jeśli jest potrzebna
self.set_boolean(boolean)
@@ -1019,63 +1018,63 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
import logging
from argparse import ArgumentParser
from getpass import getpass
-
+
import slixmpp
import example_plugin
-
+
class Responder(slixmpp.ClientXMPP):
def __init__(self, jid, password):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_get_iq", self.example_tag_get_iq)
self.add_event_handler("example_tag_message", self.example_tag_message)
-
+
def start(self, event):
# Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online
self.send_presence()
self.get_roster()
-
+
def example_tag_get_iq(self, iq): # Iq zawsze powinien odpowiedzieć. Jeżeli użytkownik jest offline, zostanie zwrócony error.
logging.info(iq)
reply = iq.reply()
reply["example_tag"].fill_interfaces(True, "Reply_string")
reply.send()
-
+
def example_tag_message(self, msg):
logging.info(msg) # Na Message można odpowiedzieć, ale nie trzeba.
-
-
+
+
if __name__ == '__main__':
parser = ArgumentParser(description=Responder.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
help="password to use")
parser.add_argument("-t", "--to", dest="to",
help="JID to send the message to")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Responder(args.jid, args.password)
xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPluggin jest nazwa klasy example_plugin
-
+
xmpp.connect()
try:
xmpp.process()
@@ -1093,65 +1092,65 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
from argparse import ArgumentParser
from getpass import getpass
import time
-
+
import slixmpp
from slixmpp.xmlstream import ET
-
+
import example_plugin
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
-
+
def start(self, event):
# Dwie niewymagane metody pozwalające innym użytkownikom zobaczyć dostępność online
self.send_presence()
self.get_roster()
-
+
self.disconnect_counter = 5 # Aplikacja rozłączy się po odebraniu takiej ilości odpowiedzi.
-
+
self.send_example_iq(self.to)
# <iq to=RESPONDER/RESOURCE xml:lang="en" type="get" id="0" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string" boolean="True">Info_inside_tag</example_tag></iq>
-
+
self.send_example_message(self.to)
# <message to="RESPONDER" xml:lang="en" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" some_string="Message string">Info_inside_tag_message</example_tag></message>
-
+
self.send_example_iq_tag_from_file(self.to, self.path)
# <iq from="SENDER/RESOURCE" xml:lang="en" id="2" type="get" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
string = '<example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag>'
et = ET.fromstring(string)
self.send_example_iq_tag_from_element_tree(self.to, et)
# <iq to="RESPONDER/RESOURCE" id="3" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
+
self.send_example_iq_to_get_error(self.to)
# <iq type="get" id="4" from="SENDER/RESOURCE" xml:lang="en" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" /></iq>
# OUR ERROR <iq to="RESPONDER/RESOURCE" id="4" xml:lang="en" from="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel"><feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Without boolean value returns error.</text></error></iq>
# OFFLINE ERROR <iq id="4" from="RESPONDER/RESOURCE" xml:lang="en" to="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel" code="503"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">User session not found</text></error></iq>
-
+
self.send_example_iq_tag_from_string(self.to, string)
# <iq to="RESPONDER/RESOURCE" id="5" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
-
+
+
def example_tag_result_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Przykład rozłączania się aplikacji po uzyskaniu odpowiedniej ilości odpowiedzi.
-
+
def example_tag_error_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Przykład rozłączania się aplikacji po uzyskaniu odpowiedniej ilości odpowiedzi.
-
+
def send_example_iq(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get")
@@ -1159,7 +1158,7 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
iq['example_tag'].set_some_string("Another_string")
iq['example_tag'].set_text("Info_inside_tag")
iq.send()
-
+
def send_example_message(self, to):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
msg = self.make_message(mto=to)
@@ -1167,44 +1166,44 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
msg['example_tag'].set_some_string("Message string")
msg['example_tag'].set_text("Info_inside_tag_message")
msg.send()
-
+
def send_example_iq_tag_from_file(self, to, path):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=2)
iq['example_tag'].setup_from_file(path)
-
+
iq.send()
-
+
def send_example_iq_tag_from_element_tree(self, to, et):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=3)
iq['example_tag'].setup_from_lxml(et)
-
+
iq.send()
-
+
def send_example_iq_to_get_error(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=4)
iq['example_tag'].set_boolean(True) # Kiedy, aby otrzymać odpowiedż z błędem, potrzebny jest example_tag bez wartości bool.
iq.send()
-
+
def send_example_iq_tag_from_string(self, to, string):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=5)
iq['example_tag'].setup_from_string(string)
-
+
iq.send()
-
+
if __name__ == '__main__':
parser = ArgumentParser(description=Sender.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
@@ -1213,20 +1212,20 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
help="JID to send the message/iq to")
parser.add_argument("--path", dest="path",
help="path to load example_tag content")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Sender(args.jid, args.password, args.to, args.path)
xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPlugin jest nazwą klasy z example_plugin.
-
+
xmpp.connect()
try:
xmpp.process()
@@ -1238,7 +1237,7 @@ Poniżej przykład kodu podyktowanego tymi zasadami:
Tagi i atrybuty zagnieżdżone wewnątrz głównego elementu
---------------------------------------
+---------------------------------------------------------
Aby stworzyć zagnieżdżony tag, wewnątrz głównego tagu, rozważmy atrybut `'self.xml'` jako Element z ET (ElementTree). W takim wypadku, aby stworzyć zagnieżdżony element można użyć funkcji 'append'.
@@ -1249,11 +1248,11 @@ Można powtórzyć poprzednie działania inicjalizując nowy element jak główn
#File: $WORKDIR/example/example_plugin.py
#(...)
-
+
class ExampleTag(ElementBase):
-
+
#(...)
-
+
def add_inside_tag(self, tag, attributes, text=""):
#Można rozszerzyć tag o tagi wewnętrzne do tagu, na przykład tak:
itemXML = ET.Element("{{{0:s}}}{1:s}".format(self.namespace, tag)) #~ Inicjalizujemy Element z wewnętrznym tagiem, na przykład: <example_tag (...)> <inside_tag namespace="https://example.net/our_extension"/></example_tag>
@@ -1269,17 +1268,17 @@ Kompletny kod tutorialu
W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angielskim.
.. code-block:: python
-
+
#!/usr/bin/python3
#File: /usr/bin/test_slixmpp & permissions rwx--x--x (711)
-
+
import subprocess
import threading
import time
-
+
def start_shell(shell_string):
subprocess.run(shell_string, shell=True, universal_newlines=True)
-
+
if __name__ == "__main__":
#~ prefix = "x-terminal-emulator -e" # Separate terminal for every client, you can replace xterm with your terminal
#~ prefix = "xterm -e" # Separate terminal for every client, you can replace xterm with your terminal
@@ -1287,24 +1286,24 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
#~ postfix = " -d" # Debug
#~ postfix = " -q" # Quiet
postfix = ""
-
+
sender_path = "./example/sender.py"
sender_jid = "SENDER_JID"
sender_password = "SENDER_PASSWORD"
-
+
example_file = "./test_example_tag.xml"
-
+
responder_path = "./example/responder.py"
responder_jid = "RESPONDER_JID"
responder_password = "RESPONDER_PASSWORD"
-
+
# Remember about rights to run your python files. (`chmod +x ./file.py`)
SENDER_TEST = f"{prefix} {sender_path} -j {sender_jid} -p {sender_password}" + \
" -t {responder_jid} --path {example_file} {postfix}"
-
+
RESPON_TEST = f"{prefix} {responder_path} -j {responder_jid}" + \
" -p {responder_password} {postfix}"
-
+
try:
responder = threading.Thread(target=start_shell, args=(RESPON_TEST, ))
sender = threading.Thread(target=start_shell, args=(SENDER_TEST, ))
@@ -1320,48 +1319,48 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
#File: $WORKDIR/example/example_plugin.py
import logging
-
+
from slixmpp.xmlstream import ElementBase, ET, register_stanza_plugin
-
+
from slixmpp import Iq
from slixmpp import Message
-
+
from slixmpp.plugins.base import BasePlugin
-
+
from slixmpp.xmlstream.handler import Callback
from slixmpp.xmlstream.matcher import StanzaPath
-
+
log = logging.getLogger(__name__)
-
+
class OurPlugin(BasePlugin):
def plugin_init(self):
self.description = "OurPluginExtension" ##~ String data for Human readable and find plugin by another plugin with method.
self.xep = "ope" ##~ String data for Human readable and find plugin by another plugin with adding it into `slixmpp/plugins/__init__.py` to the `__all__` declaration with 'xep_OPE'. Otherwise it's just human readable annotation.
-
+
namespace = ExampleTag.namespace
self.xmpp.register_handler(
Callback('ExampleGet Event:example_tag', ##~ Name of this Callback
StanzaPath(f"iq@type=get/{{{namespace}}}example_tag"), ##~ Handle only Iq with type get and example_tag
self.__handle_get_iq)) ##~ Method which catch proper Iq, should raise proper event for client.
-
+
self.xmpp.register_handler(
Callback('ExampleResult Event:example_tag', ##~ Name of this Callback
StanzaPath(f"iq@type=result/{{{namespace}}}example_tag"), ##~ Handle only Iq with type result and example_tag
self.__handle_result_iq)) ##~ Method which catch proper Iq, should raise proper event for client.
-
+
self.xmpp.register_handler(
Callback('ExampleError Event:example_tag', ##~ Name of this Callback
StanzaPath(f"iq@type=error/{{{namespace}}}example_tag"), ##~ Handle only Iq with type error and example_tag
self.__handle_error_iq)) ##~ Method which catch proper Iq, should raise proper event for client.
-
+
self.xmpp.register_handler(
Callback('ExampleMessage Event:example_tag',##~ Name of this Callback
StanzaPath(f'message/{{{namespace}}}example_tag'), ##~ Handle only Message with example_tag
self.__handle_message)) ##~ Method which catch proper Message, should raise proper event for client.
-
+
register_stanza_plugin(Iq, ExampleTag) ##~ Register tags extension for Iq object, otherwise iq['example_tag'] will be string field instead container where we can manage our fields and create sub elements.
register_stanza_plugin(Message, ExampleTag) ##~ Register tags extension for Message object, otherwise message['example_tag'] will be string field instead container where we can manage our fields and create sub elements.
-
+
# All iq types are: get, set, error, result
def __handle_get_iq(self, iq):
if iq.get_some_string is None:
@@ -1372,37 +1371,37 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
error.send()
# Do something with received iq
self.xmpp.event('example_tag_get_iq', iq) ##~ Call event which can be handled by clients to send or something other what you want.
-
+
def __handle_result_iq(self, iq):
# Do something with received iq
self.xmpp.event('example_tag_result_iq', iq) ##~ Call event which can be handled by clients to send or something other what you want.
-
+
def __handle_error_iq(self, iq):
# Do something with received iq
self.xmpp.event('example_tag_error_iq', iq) ##~ Call event which can be handled by clients to send or something other what you want.
-
+
def __handle_message(self, msg):
# Do something with received message
self.xmpp.event('example_tag_message', msg) ##~ Call event which can be handled by clients to send or something other what you want.
-
+
class ExampleTag(ElementBase):
name = "example_tag" ##~ The name of the root XML element of that extension.
namespace = "https://example.net/our_extension" ##~ The namespace our stanza object lives in, like <example_tag xmlns={namespace} (...)</example_tag>. You should change it for your own namespace
-
+
plugin_attrib = "example_tag" ##~ The name to access this type of stanza. In particular, given a registration stanza, the Registration object can be found using: stanza_object['example_tag'] now `'example_tag'` is name of ours ElementBase extension. And this should be that same as name.
-
+
interfaces = {"boolean", "some_string"} ##~ A list of dictionary-like keys that can be used with the stanza object. For example `stanza_object['example_tag']` gives us {"another": "some", "data": "some"}, whenever `'example_tag'` is name of ours ElementBase extension.
-
+
def setup_from_string(self, string):
"""Initialize tag element from string"""
et_extension_tag_xml = ET.fromstring(string)
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_file(self, path):
"""Initialize tag element from file containing adjusted data"""
et_extension_tag_xml = ET.parse(path).getroot()
self.setup_from_lxml(et_extension_tag_xml)
-
+
def setup_from_lxml(self, lxml):
"""Add ET data to self xml structure."""
self.xml.attrib.update(lxml.attrib)
@@ -1410,34 +1409,34 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
self.xml.tail = lxml.tail
for inner_tag in lxml:
self.xml.append(inner_tag)
-
+
def setup_from_dict(self, data):
#There should keys should be also validated
self.xml.attrib.update(data)
-
+
def get_boolean(self):
return self.xml.attrib.get("boolean", None)
-
+
def get_some_string(self):
return self.xml.attrib.get("some_string", None)
-
+
def get_text(self, text):
return self.xml.text
-
+
def set_boolean(self, boolean):
self.xml.attrib['boolean'] = str(boolean)
-
+
def set_some_string(self, some_string):
self.xml.attrib['some_string'] = some_string
-
+
def set_text(self, text):
self.xml.text = text
-
+
def fill_interfaces(self, boolean, some_string):
#Some validation if it is necessary
self.set_boolean(boolean)
self.set_some_string(some_string)
-
+
def add_inside_tag(self, tag, attributes, text=""):
#If we want to fill with additionaly tags our element, then we can do it that way for example:
itemXML = ET.Element("{{{0:s}}}{1:s}".format(self.namespace, tag)) #~ Initialize ET with our tag, for example: <example_tag (...)> <inside_tag namespace="https://example.net/our_extension"/></example_tag>
@@ -1450,73 +1449,73 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
.. code-block:: python
#File: $WORKDIR/example/sender.py
-
+
import logging
from argparse import ArgumentParser
from getpass import getpass
import time
-
+
import slixmpp
from slixmpp.xmlstream import ET
-
+
import example_plugin
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
-
+
def start(self, event):
# Two, not required methods, but allows another users to see us available, and receive that information.
self.send_presence()
self.get_roster()
-
+
self.disconnect_counter = 6 # This is only for disconnect when we receive all replies for sended Iq
-
+
self.send_example_iq(self.to)
# <iq to=RESPONDER/RESOURCE xml:lang="en" type="get" id="0" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string" boolean="True">Info_inside_tag</example_tag></iq>
-
+
self.send_example_iq_with_inner_tag(self.to)
# <iq from="SENDER/RESOURCE" to="RESPONDER/RESOURCE" id="1" xml:lang="en" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
self.send_example_message(self.to)
# <message to="RESPONDER" xml:lang="en" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" some_string="Message string">Info_inside_tag_message</example_tag></message>
-
+
self.send_example_iq_tag_from_file(self.to, self.path)
# <iq from="SENDER/RESOURCE" xml:lang="en" id="2" type="get" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
string = '<example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag>'
et = ET.fromstring(string)
self.send_example_iq_tag_from_element_tree(self.to, et)
# <iq to="RESPONDER/RESOURCE" id="3" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
+
self.send_example_iq_to_get_error(self.to)
# <iq type="get" id="4" from="SENDER/RESOURCE" xml:lang="en" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" /></iq>
# OUR ERROR <iq to="RESPONDER/RESOURCE" id="4" xml:lang="en" from="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel"><feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Without boolean value returns error.</text></error></iq>
# OFFLINE ERROR <iq id="4" from="RESPONDER/RESOURCE" xml:lang="en" to="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel" code="503"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">User session not found</text></error></iq>
-
+
self.send_example_iq_tag_from_string(self.to, string)
# <iq to="RESPONDER/RESOURCE" id="5" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
-
+
+
def example_tag_result_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Example disconnect after first received iq stanza extended by example_tag with result type.
-
+
def example_tag_error_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Example disconnect after first received iq stanza extended by example_tag with result type.
-
+
def send_example_iq(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get")
@@ -1524,18 +1523,18 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
iq['example_tag'].set_some_string("Another_string")
iq['example_tag'].set_text("Info_inside_tag")
iq.send()
-
+
def send_example_iq_with_inner_tag(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=1)
iq['example_tag'].set_some_string("Another_string")
iq['example_tag'].set_text("Info_inside_tag")
-
+
inner_attributes = {"first_field": "1", "secound_field": "2"}
iq['example_tag'].add_inside_tag(tag="inside_tag", attributes=inner_attributes)
-
+
iq.send()
-
+
def send_example_message(self, to):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
msg = self.make_message(mto=to)
@@ -1543,44 +1542,44 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
msg['example_tag'].set_some_string("Message string")
msg['example_tag'].set_text("Info_inside_tag_message")
msg.send()
-
+
def send_example_iq_tag_from_file(self, to, path):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=2)
iq['example_tag'].setup_from_file(path)
-
+
iq.send()
-
+
def send_example_iq_tag_from_element_tree(self, to, et):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=3)
iq['example_tag'].setup_from_lxml(et)
-
+
iq.send()
-
+
def send_example_iq_to_get_error(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=4)
iq['example_tag'].set_boolean(True) # For example, our condition to receive error respond is example_tag without boolean value.
iq.send()
-
+
def send_example_iq_tag_from_string(self, to, string):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=5)
iq['example_tag'].setup_from_string(string)
-
+
iq.send()
-
+
if __name__ == '__main__':
parser = ArgumentParser(description=Sender.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
@@ -1589,20 +1588,20 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
help="JID to send the message/iq to")
parser.add_argument("--path", dest="path",
help="path to load example_tag content")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Sender(args.jid, args.password, args.to, args.path)
xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPlugin is a class name from example_plugin
-
+
xmpp.connect()
try:
xmpp.process()
@@ -1622,68 +1621,68 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
from argparse import ArgumentParser
from getpass import getpass
import time
-
+
import slixmpp
from slixmpp.xmlstream import ET
-
+
import example_plugin
-
+
class Sender(slixmpp.ClientXMPP):
def __init__(self, jid, password, to, path):
slixmpp.ClientXMPP.__init__(self, jid, password)
-
+
self.to = to
self.path = path
-
+
self.add_event_handler("session_start", self.start)
self.add_event_handler("example_tag_result_iq", self.example_tag_result_iq)
self.add_event_handler("example_tag_error_iq", self.example_tag_error_iq)
-
+
def start(self, event):
# Two, not required methods, but allows another users to see us available, and receive that information.
self.send_presence()
self.get_roster()
-
+
self.disconnect_counter = 6 # This is only for disconnect when we receive all replies for sended Iq
-
+
self.send_example_iq(self.to)
# <iq to=RESPONDER/RESOURCE xml:lang="en" type="get" id="0" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string" boolean="True">Info_inside_tag</example_tag></iq>
-
+
self.send_example_iq_with_inner_tag(self.to)
# <iq from="SENDER/RESOURCE" to="RESPONDER/RESOURCE" id="1" xml:lang="en" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
self.send_example_message(self.to)
# <message to="RESPONDER" xml:lang="en" from="SENDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" some_string="Message string">Info_inside_tag_message</example_tag></message>
-
+
self.send_example_iq_tag_from_file(self.to, self.path)
# <iq from="SENDER/RESOURCE" xml:lang="en" id="2" type="get" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag></iq>
-
+
string = '<example_tag xmlns="https://example.net/our_extension" some_string="Another_string">Info_inside_tag<inside_tag first_field="1" secound_field="2" /></example_tag>'
et = ET.fromstring(string)
self.send_example_iq_tag_from_element_tree(self.to, et)
# <iq to="RESPONDER/RESOURCE" id="3" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
+
self.send_example_iq_to_get_error(self.to)
# <iq type="get" id="4" from="SENDER/RESOURCE" xml:lang="en" to="RESPONDER/RESOURCE"><example_tag xmlns="https://example.net/our_extension" boolean="True" /></iq>
# OUR ERROR <iq to="RESPONDER/RESOURCE" id="4" xml:lang="en" from="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel"><feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas">Without boolean value returns error.</text></error></iq>
# OFFLINE ERROR <iq id="4" from="RESPONDER/RESOURCE" xml:lang="en" to="SENDER/RESOURCE" type="error"><example_tag xmlns="https://example.net/our_extension" boolean="True" /><error type="cancel" code="503"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" /><text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" xml:lang="en">User session not found</text></error></iq>
-
+
self.send_example_iq_tag_from_string(self.to, string)
# <iq to="RESPONDER/RESOURCE" id="5" xml:lang="en" from="SENDER/RESOURCE" type="get"><example_tag xmlns="https://example.net/our_extension" some_string="Reply_string" boolean="True">Info_inside_tag<inside_tag secound_field="2" first_field="1" /></example_tag></iq>
-
-
+
+
def example_tag_result_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Example disconnect after first received iq stanza extended by example_tag with result type.
-
+
def example_tag_error_iq(self, iq):
self.disconnect_counter -= 1
logging.info(str(iq))
if not self.disconnect_counter:
self.disconnect() # Example disconnect after first received iq stanza extended by example_tag with result type.
-
+
def send_example_iq(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get")
@@ -1691,18 +1690,18 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
iq['example_tag'].set_some_string("Another_string")
iq['example_tag'].set_text("Info_inside_tag")
iq.send()
-
+
def send_example_iq_with_inner_tag(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=1)
iq['example_tag'].set_some_string("Another_string")
iq['example_tag'].set_text("Info_inside_tag")
-
+
inner_attributes = {"first_field": "1", "secound_field": "2"}
iq['example_tag'].add_inside_tag(tag="inside_tag", attributes=inner_attributes)
-
+
iq.send()
-
+
def send_example_message(self, to):
#~ make_message(mfrom=None, mto=None, mtype=None, mquery=None)
msg = self.make_message(mto=to)
@@ -1710,44 +1709,44 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
msg['example_tag'].set_some_string("Message string")
msg['example_tag'].set_text("Info_inside_tag_message")
msg.send()
-
+
def send_example_iq_tag_from_file(self, to, path):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=2)
iq['example_tag'].setup_from_file(path)
-
+
iq.send()
-
+
def send_example_iq_tag_from_element_tree(self, to, et):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=3)
iq['example_tag'].setup_from_lxml(et)
-
+
iq.send()
-
+
def send_example_iq_to_get_error(self, to):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=4)
iq['example_tag'].set_boolean(True) # For example, our condition to receive error respond is example_tag without boolean value.
iq.send()
-
+
def send_example_iq_tag_from_string(self, to, string):
#~ make_iq(id=0, ifrom=None, ito=None, itype=None, iquery=None)
iq = self.make_iq(ito=to, itype="get", id=5)
iq['example_tag'].setup_from_string(string)
-
+
iq.send()
-
+
if __name__ == '__main__':
parser = ArgumentParser(description=Sender.__doc__)
-
+
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
action="store_const", dest="loglevel",
const=logging.ERROR, default=logging.INFO)
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
action="store_const", dest="loglevel",
const=logging.DEBUG, default=logging.INFO)
-
+
parser.add_argument("-j", "--jid", dest="jid",
help="JID to use")
parser.add_argument("-p", "--password", dest="password",
@@ -1756,20 +1755,20 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
help="JID to send the message/iq to")
parser.add_argument("--path", dest="path",
help="path to load example_tag content")
-
+
args = parser.parse_args()
-
+
logging.basicConfig(level=args.loglevel,
format=' %(name)s - %(levelname)-8s %(message)s')
-
+
if args.jid is None:
args.jid = input("Username: ")
if args.password is None:
args.password = getpass("Password: ")
-
+
xmpp = Sender(args.jid, args.password, args.to, args.path)
xmpp.register_plugin('OurPlugin', module=example_plugin) # OurPlugin is a class name from example_plugin
-
+
xmpp.connect()
try:
xmpp.process()
@@ -1790,7 +1789,7 @@ W poniższym kodzie zostały pozostawione oryginalne komentarze w języku angiel
<example_tag xmlns="https://example.net/our_extension" some_string="StringFromFile">Info_inside_tag<inside_tag first_field="3" secound_field="4" /></example_tag>
Źródła i bibliogarfia
----------------------
+----------------------
Slixmpp - opis projektu:
@@ -1804,4 +1803,4 @@ Oficjalna dokumentacja PDF:
* https://buildmedia.readthedocs.org/media/pdf/slixmpp/latest/slixmpp.pdf
-Note: Dokumentacje w formie Web i PDF różnią się; pewne szczegóły potrafią być wspomniane tylko w jednej z dwóch.
+Dokumentacje w formie Web i PDF różnią się; pewne szczegóły potrafią być wspomniane tylko w jednej z dwóch.