aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py
diff options
context:
space:
mode:
authorshmel1k <shmel1k@ydb.tech>2023-11-26 18:16:14 +0300
committershmel1k <shmel1k@ydb.tech>2023-11-26 18:43:30 +0300
commitb8cf9e88f4c5c64d9406af533d8948deb050d695 (patch)
tree218eb61fb3c3b96ec08b4d8cdfef383104a87d63 /contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py
parent523f645a83a0ec97a0332dbc3863bb354c92a328 (diff)
downloadydb-b8cf9e88f4c5c64d9406af533d8948deb050d695.tar.gz
add kikimr_configure
Diffstat (limited to 'contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py')
-rw-r--r--contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py274
1 files changed, 274 insertions, 0 deletions
diff --git a/contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py b/contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py
new file mode 100644
index 0000000000..a2b9890939
--- /dev/null
+++ b/contrib/python/Twisted/py3/twisted/words/xish/xmlstream.py
@@ -0,0 +1,274 @@
+# -*- test-case-name: twisted.words.test.test_xmlstream -*-
+#
+# Copyright (c) Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+XML Stream processing.
+
+An XML Stream is defined as a connection over which two XML documents are
+exchanged during the lifetime of the connection, one for each direction. The
+unit of interaction is a direct child element of the root element (stanza).
+
+The most prominent use of XML Streams is Jabber, but this module is generically
+usable. See Twisted Words for Jabber specific protocol support.
+
+Maintainer: Ralph Meijer
+
+@var STREAM_CONNECTED_EVENT: This event signals that the connection has been
+ established.
+@type STREAM_CONNECTED_EVENT: L{str}.
+
+@var STREAM_END_EVENT: This event signals that the connection has been closed.
+@type STREAM_END_EVENT: L{str}.
+
+@var STREAM_ERROR_EVENT: This event signals that a parse error occurred.
+@type STREAM_ERROR_EVENT: L{str}.
+
+@var STREAM_START_EVENT: This event signals that the root element of the XML
+ Stream has been received.
+ For XMPP, this would be the C{<stream:stream ...>} opening tag.
+@type STREAM_START_EVENT: L{str}.
+"""
+
+
+from sys import intern
+from typing import Type
+
+from twisted.internet import protocol
+from twisted.python import failure
+from twisted.words.xish import domish, utility
+
+STREAM_CONNECTED_EVENT = intern("//event/stream/connected")
+STREAM_START_EVENT = intern("//event/stream/start")
+STREAM_END_EVENT = intern("//event/stream/end")
+STREAM_ERROR_EVENT = intern("//event/stream/error")
+
+
+class XmlStream(protocol.Protocol, utility.EventDispatcher):
+ """Generic Streaming XML protocol handler.
+
+ This protocol handler will parse incoming data as XML and dispatch events
+ accordingly. Incoming stanzas can be handled by registering observers using
+ XPath-like expressions that are matched against each stanza. See
+ L{utility.EventDispatcher} for details.
+ """
+
+ def __init__(self):
+ utility.EventDispatcher.__init__(self)
+ self.stream = None
+ self.rawDataOutFn = None
+ self.rawDataInFn = None
+
+ def _initializeStream(self):
+ """Sets up XML Parser."""
+ self.stream = domish.elementStream()
+ self.stream.DocumentStartEvent = self.onDocumentStart
+ self.stream.ElementEvent = self.onElement
+ self.stream.DocumentEndEvent = self.onDocumentEnd
+
+ ### --------------------------------------------------------------
+ ###
+ ### Protocol events
+ ###
+ ### --------------------------------------------------------------
+
+ def connectionMade(self):
+ """Called when a connection is made.
+
+ Sets up the XML parser and dispatches the L{STREAM_CONNECTED_EVENT}
+ event indicating the connection has been established.
+ """
+ self._initializeStream()
+ self.dispatch(self, STREAM_CONNECTED_EVENT)
+
+ def dataReceived(self, data):
+ """Called whenever data is received.
+
+ Passes the data to the XML parser. This can result in calls to the
+ DOM handlers. If a parse error occurs, the L{STREAM_ERROR_EVENT} event
+ is called to allow for cleanup actions, followed by dropping the
+ connection.
+ """
+ try:
+ if self.rawDataInFn:
+ self.rawDataInFn(data)
+ self.stream.parse(data)
+ except domish.ParserError:
+ self.dispatch(failure.Failure(), STREAM_ERROR_EVENT)
+ self.transport.loseConnection()
+
+ def connectionLost(self, reason):
+ """Called when the connection is shut down.
+
+ Dispatches the L{STREAM_END_EVENT}.
+ """
+ self.dispatch(reason, STREAM_END_EVENT)
+ self.stream = None
+
+ ### --------------------------------------------------------------
+ ###
+ ### DOM events
+ ###
+ ### --------------------------------------------------------------
+
+ def onDocumentStart(self, rootElement):
+ """Called whenever the start tag of a root element has been received.
+
+ Dispatches the L{STREAM_START_EVENT}.
+ """
+ self.dispatch(self, STREAM_START_EVENT)
+
+ def onElement(self, element):
+ """Called whenever a direct child element of the root element has
+ been received.
+
+ Dispatches the received element.
+ """
+ self.dispatch(element)
+
+ def onDocumentEnd(self):
+ """Called whenever the end tag of the root element has been received.
+
+ Closes the connection. This causes C{connectionLost} being called.
+ """
+ self.transport.loseConnection()
+
+ def setDispatchFn(self, fn):
+ """Set another function to handle elements."""
+ self.stream.ElementEvent = fn
+
+ def resetDispatchFn(self):
+ """Set the default function (C{onElement}) to handle elements."""
+ self.stream.ElementEvent = self.onElement
+
+ def send(self, obj):
+ """Send data over the stream.
+
+ Sends the given C{obj} over the connection. C{obj} may be instances of
+ L{domish.Element}, C{unicode} and C{str}. The first two will be
+ properly serialized and/or encoded. C{str} objects must be in UTF-8
+ encoding.
+
+ Note: because it is easy to make mistakes in maintaining a properly
+ encoded C{str} object, it is advised to use C{unicode} objects
+ everywhere when dealing with XML Streams.
+
+ @param obj: Object to be sent over the stream.
+ @type obj: L{domish.Element}, L{domish} or C{str}
+
+ """
+ if domish.IElement.providedBy(obj):
+ obj = obj.toXml()
+
+ if isinstance(obj, str):
+ obj = obj.encode("utf-8")
+
+ if self.rawDataOutFn:
+ self.rawDataOutFn(obj)
+
+ self.transport.write(obj)
+
+
+class BootstrapMixin:
+ """
+ XmlStream factory mixin to install bootstrap event observers.
+
+ This mixin is for factories providing
+ L{IProtocolFactory<twisted.internet.interfaces.IProtocolFactory>} to make
+ sure bootstrap event observers are set up on protocols, before incoming
+ data is processed. Such protocols typically derive from
+ L{utility.EventDispatcher}, like L{XmlStream}.
+
+ You can set up bootstrap event observers using C{addBootstrap}. The
+ C{event} and C{fn} parameters correspond with the C{event} and
+ C{observerfn} arguments to L{utility.EventDispatcher.addObserver}.
+
+ @since: 8.2.
+ @ivar bootstraps: The list of registered bootstrap event observers.
+ @type bootstrap: C{list}
+ """
+
+ def __init__(self):
+ self.bootstraps = []
+
+ def installBootstraps(self, dispatcher):
+ """
+ Install registered bootstrap observers.
+
+ @param dispatcher: Event dispatcher to add the observers to.
+ @type dispatcher: L{utility.EventDispatcher}
+ """
+ for event, fn in self.bootstraps:
+ dispatcher.addObserver(event, fn)
+
+ def addBootstrap(self, event, fn):
+ """
+ Add a bootstrap event handler.
+
+ @param event: The event to register an observer for.
+ @type event: C{str} or L{xpath.XPathQuery}
+ @param fn: The observer callable to be registered.
+ """
+ self.bootstraps.append((event, fn))
+
+ def removeBootstrap(self, event, fn):
+ """
+ Remove a bootstrap event handler.
+
+ @param event: The event the observer is registered for.
+ @type event: C{str} or L{xpath.XPathQuery}
+ @param fn: The registered observer callable.
+ """
+ self.bootstraps.remove((event, fn))
+
+
+class XmlStreamFactoryMixin(BootstrapMixin):
+ """
+ XmlStream factory mixin that takes care of event handlers.
+
+ All positional and keyword arguments passed to create this factory are
+ passed on as-is to the protocol.
+
+ @ivar args: Positional arguments passed to the protocol upon instantiation.
+ @type args: C{tuple}.
+ @ivar kwargs: Keyword arguments passed to the protocol upon instantiation.
+ @type kwargs: C{dict}.
+ """
+
+ def __init__(self, *args, **kwargs):
+ BootstrapMixin.__init__(self)
+ self.args = args
+ self.kwargs = kwargs
+
+ def buildProtocol(self, addr):
+ """
+ Create an instance of XmlStream.
+
+ The returned instance will have bootstrap event observers registered
+ and will proceed to handle input on an incoming connection.
+ """
+ xs = self.protocol(*self.args, **self.kwargs)
+ xs.factory = self
+ self.installBootstraps(xs)
+ return xs
+
+
+class XmlStreamFactory(XmlStreamFactoryMixin, protocol.ReconnectingClientFactory):
+ """
+ Factory for XmlStream protocol objects as a reconnection client.
+ """
+
+ protocol: "Type[protocol.Protocol]" = XmlStream
+
+ def buildProtocol(self, addr):
+ """
+ Create a protocol instance.
+
+ Overrides L{XmlStreamFactoryMixin.buildProtocol} to work with
+ a L{ReconnectingClientFactory}. As this is called upon having an
+ connection established, we are resetting the delay for reconnection
+ attempts when the connection is lost again.
+ """
+ self.resetDelay()
+ return XmlStreamFactoryMixin.buildProtocol(self, addr)