def _get_offer(self): return PerMessageDeflateOffer( accept_max_window_bits=True, accept_no_context_takeover=False, request_max_window_bits=0, request_no_context_takeover=False, )
def connect2WS(b_in_main_thread): tokens = get_tokens() pstk = tokens['pstk'] token = tokens['token'] uid = generateUID(token.split('.')[0], tokens['SERVER_TIME']) if not pstk: print('get pstk failed, maybe in maintance') return USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Mobile Safari/537.36" url = 'wss://premws-pt1.bet365.it/zap/?uid={}'.format(uid) global_var.factory = DataSourceClientFactory(url, useragent=USER_AGENT, protocols=['zap-protocol-v1']) global_var.factory.session_id = pstk global_var.factory.token = token def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) global_var.factory.setProtocolOptions(perMessageCompressionAccept=accept) global_var.factory.setProtocolOptions(perMessageCompressionOffers=[ PerMessageDeflateOffer(accept_max_window_bits=True, accept_no_context_takeover=True, request_max_window_bits=0, request_no_context_takeover=True) ]) if global_var.factory.isSecure: contextFactory = ssl.ClientContextFactory() else: contextFactory = None while True: try: if b_in_main_thread: connectWS(global_var.factory, contextFactory, timeout=60) else: reactor.callFromThread(connectWS, global_var.factory, contextFactory, timeout=60) except: print('failed to connect ws server!') time.sleep(5) else: break
def __init__(self, url, agent): self.agent = agent WebSocketClientFactory.__init__(self, url, useragent=agent) self.setProtocolOptions(failByDrop=False) # spec conformance # enable permessage-deflate WebSocket protocol extension offers = [PerMessageDeflateOffer()] self.setProtocolOptions(perMessageCompressionOffers=offers) def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) self.setProtocolOptions(perMessageCompressionAccept=accept)
def __init__(self, factory, url, reactor=None, enableCompression=True, autoFragmentSize=0, subprotocol=None, debug=False): """ Constructor. :param factory: Stream-based factory to be wrapped. :type factory: A subclass of `twisted.internet.protocol.Factory` :param url: WebSocket URL of the server this client factory will connect to. :type url: str """ self._factory = factory self._subprotocols = ['binary', 'base64'] if subprotocol: self._subprotocols.append(subprotocol) WebSocketClientFactory.__init__(self, url=url, reactor=reactor, protocols=self._subprotocols, debug=debug) ## automatically fragment outgoing traffic into WebSocket frames ## of this size self.setProtocolOptions(autoFragmentSize=autoFragmentSize) ## play nice and perform WS closing handshake self.setProtocolOptions(failByDrop=False) if enableCompression: ## Enable WebSocket extension "permessage-deflate". ## ## The extensions offered to the server .. offers = [PerMessageDeflateOffer()] self.setProtocolOptions(perMessageCompressionOffers=offers) ## Function to accept responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) self.setProtocolOptions(perMessageCompressionAccept=accept)
def __init__(self, url): self.agent = autobahn.twisted.__ident__ WebSocketClientFactory.__init__(self, url, useragent=self.agent) self.setProtocolOptions(failByDrop=False) # spec conformance # enable permessage-deflate WebSocket protocol extension offers = [PerMessageDeflateOffer()] self.setProtocolOptions(perMessageCompressionOffers=offers) def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) self.setProtocolOptions(perMessageCompressionAccept=accept) # setup client testee stuff self.endCaseId = None self.currentCaseId = 0 self.updateReports = True self.resource = "/getCaseCount"
def run(self, make, start_loop=True, log_level='info'): """ Run the application component. Under the hood, this runs the event loop (unless `start_loop=False` is passed) so won't return until the program is done. :param make: A factory that produces instances of :class:`autobahn.asyncio.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable :param start_loop: When ``True`` (the default) this method start a new asyncio loop. :type start_loop: bool :returns: None is returned, unless you specify `start_loop=False` in which case the coroutine from calling `loop.create_connection()` is returned. This will yield the (transport, protocol) pair. """ if callable(make): def create(): cfg = ComponentConfig(self.realm, self.extra) try: session = make(cfg) except Exception as e: self.log.error( 'ApplicationSession could not be instantiated: {}'. format(e)) loop = asyncio.get_event_loop() if loop.is_running(): loop.stop() raise else: return session else: create = make if self.url.startswith(u'rs'): # try to parse RawSocket URL .. isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory( create, serializer=serializer) else: # try to parse WebSocket URL .. isSecure, host, port, resource, path, params = parse_ws_url( self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept permessage_delate responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # set WebSocket options for all client connections transport_factory.setProtocolOptions( maxFramePayloadSize=1048576, maxMessagePayloadSize=1048576, autoFragmentSize=65536, failByDrop=False, openHandshakeTimeout=2.5, closeHandshakeTimeout=1., tcpNoDelay=True, autoPingInterval=10., autoPingTimeout=5., autoPingSize=4, perMessageCompressionOffers=offers, perMessageCompressionAccept=accept) # SSL context for client connection if self.ssl is None: ssl = isSecure else: if self.ssl and not isSecure: raise RuntimeError( 'ssl argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) ssl = self.ssl # start the client connection loop = asyncio.get_event_loop() txaio.use_asyncio() txaio.config.loop = loop coro = loop.create_connection(transport_factory, host, port, ssl=ssl) # start a asyncio loop if not start_loop: return coro else: (transport, protocol) = loop.run_until_complete(coro) # start logging txaio.start_logging(level=log_level) try: loop.add_signal_handler(signal.SIGTERM, loop.stop) except NotImplementedError: # signals are not available on Windows pass # 4) now enter the asyncio event loop try: loop.run_forever() except KeyboardInterrupt: # wait until we send Goodbye if user hit ctrl-c # (done outside this except so SIGTERM gets the same handling) pass # give Goodbye message a chance to go through, if we still # have an active session if protocol._session: loop.run_until_complete(protocol._session.leave()) loop.close()
if len(sys.argv) > 2 and sys.argv[2] == 'debug': log.startLogging(sys.stdout) debug = True else: debug = False factory = WebSocketClientFactory(sys.argv[1], debug=debug, debugCodePaths=debug) factory.protocol = EchoClientProtocol # Enable WebSocket extension "permessage-deflate". ## # The extensions offered to the server .. offers = [PerMessageDeflateOffer()] factory.setProtocolOptions(perMessageCompressionOffers=offers) # Function to accept responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) factory.setProtocolOptions(perMessageCompressionAccept=accept) # run client ## connectWS(factory) reactor.run()
factory = WebSocketClientFactory(url, useragent=USER_AGENT, protocols=['zap-protocol-v1']) factory.protocol = MyClientProtocol factory.headers = {} factory.session_id = get_session_id() def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) factory.setProtocolOptions(perMessageCompressionAccept=accept) factory.setProtocolOptions(perMessageCompressionOffers=[ PerMessageDeflateOffer( accept_max_window_bits=True, accept_no_context_takeover=True, request_max_window_bits=0, request_no_context_takeover=True, ) ]) # reactor.callFromThread(connectWS, factory) # reactor.run() if factory.isSecure: contextFactory = ssl.ClientContextFactory() else: contextFactory = None connectWS(factory, contextFactory) reactor.run()
def run(self, make, start_reactor=True, auto_reconnect=False, log_level='info', endpoint=None, reactor=None): """ Run the application component. :param make: A factory that produces instances of :class:`autobahn.twisted.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :type make: callable :param start_reactor: When ``True`` (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :returns: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ self.log.debug('{klass}.run()', klass=self.__class__.__name__) if start_reactor: # only select framework, set loop and start logging when we are asked # start the reactor - otherwise we are running in a program that likely # already tool care of all this. from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor txaio.start_logging(level=log_level) if callable(make): # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra, runner=self) try: session = make(cfg) except Exception: self.log.failure('ApplicationSession could not be instantiated: {log_failure.value}') if start_reactor and reactor.running: reactor.stop() raise else: return session else: create = make if self.url.startswith(u'rs'): # try to parse RawSocket URL .. isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory(create, serializer=serializer) else: # try to parse WebSocket URL .. isSecure, host, port, resource, path, params = parse_ws_url(self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory(create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept permessage_delate responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # set WebSocket options for all client connections transport_factory.setProtocolOptions(maxFramePayloadSize=1048576, maxMessagePayloadSize=1048576, autoFragmentSize=65536, failByDrop=False, openHandshakeTimeout=2.5, closeHandshakeTimeout=1., tcpNoDelay=True, autoPingInterval=10., autoPingTimeout=5., autoPingSize=4, perMessageCompressionOffers=offers, perMessageCompressionAccept=accept) # supress pointless log noise transport_factory.noisy = False if endpoint: client = endpoint else: # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if not isSecure: raise RuntimeError( 'ssl= argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(host) from twisted.internet import reactor if self.proxy is not None: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, self.proxy['host'], self.proxy['port']) transport_factory.contextFactory = context_factory elif isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: if proto._session.is_attached(): return proto._session.leave() elif proto._session.is_connected(): return proto._session.disconnect() # when our proto was created and connected, make sure it's cleaned # up properly later on when the reactor shuts down for whatever reason def init_proto(proto): self._connect_successes += 1 reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto) return proto use_service = False if auto_reconnect: try: # since Twisted 16.1.0 from twisted.application.internet import ClientService from twisted.application.internet import backoffPolicy use_service = True except ImportError: use_service = False if use_service: # this code path is automatically reconnecting .. self.log.debug('using t.a.i.ClientService') if self.max_retries or self.initial_retry_delay or self.max_retry_delay or self.retry_delay_growth or self.retry_delay_jitter: kwargs = {} for key, val in [('initialDelay', self.initial_retry_delay), ('maxDelay', self.max_retry_delay), ('factor', self.retry_delay_growth), ('jitter', lambda: random.random() * self.retry_delay_jitter)]: if val: kwargs[key] = val # retry policy that will only try to reconnect if we connected # successfully at least once before (so it fails on host unreachable etc ..) def retry(failed_attempts): if self._connect_successes > 0 and (self.max_retries == -1 or failed_attempts < self.max_retries): return backoffPolicy(**kwargs)(failed_attempts) else: print('hit stop') self.stop() return 100000000000000 else: retry = backoffPolicy() self._client_service = ClientService(client, transport_factory, retryPolicy=retry) self._client_service.startService() d = self._client_service.whenConnected() else: # this code path is only connecting once! self.log.debug('using t.i.e.connect()') d = client.connect(transport_factory) # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(init_proto) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if we exited due to a connection error, raise that to the # caller if connect_error.exception: raise connect_error.exception else: # let the caller handle any errors return d
def start_main(): global is_valit is_valit = False USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36" url_auto = "wss://pshudws.365pushodds.com/zap/?uid=" + str(random.random())[2:] factory_auto = MyFactory( url_auto, useragent=USER_AGENT, protocols=['zap-protocol-v1']) # factory_auto = MyFactory( # url_auto, useragent=USER_AGENT, protocols=['zap-protocol-v1'], proxy={'host': "127.0.0.1", 'port': 8888}) factory_auto.protocol = SubClientProtocol factory_auto.headers = {} factory_auto.nst_token = get_nst_token() factory_auto.session_id = get_session_id() def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) factory_auto.setProtocolOptions(perMessageCompressionAccept=accept) factory_auto.setProtocolOptions(perMessageCompressionOffers=[PerMessageDeflateOffer( accept_max_window_bits=True, accept_no_context_takeover=True, request_max_window_bits=0, request_no_context_takeover=True, )]) if factory_auto.isSecure: contextFactory_auto = ssl.ClientContextFactory() else: contextFactory_auto = None url = "wss://premws-pt3.365pushodds.com/zap/?uid=" + str(random.random())[2:] factory = MyFactory( url, useragent=USER_AGENT, protocols=['zap-protocol-v1']) # factory = MyFactory( # url, useragent=USER_AGENT, protocols=['zap-protocol-v1'], proxy={'host': "127.0.0.1", 'port': 8888}) factory.protocol = MyClientProtocol factory.headers = {} factory.session_id = factory_auto.session_id factory.nst_token = factory_auto.nst_token # factory.session_id = '44263EAB3A86367F8DF053097CF36FBB000003' factory.setProtocolOptions(perMessageCompressionAccept=accept) factory.setProtocolOptions(perMessageCompressionOffers=[PerMessageDeflateOffer( accept_max_window_bits=True, accept_no_context_takeover=True, request_max_window_bits=0, request_no_context_takeover=True, )]) # reactor.callFromThread(connectWS, factory) # reactor.run() if factory.isSecure: contextFactory = ssl.ClientContextFactory() else: contextFactory = None connectWS(factory, contextFactory) connectWS(factory_auto, contextFactory_auto) reactor.callLater(900, stopReactor) reactor.run()
# -*- coding: utf-8 -*- import pytest from autobahn.websocket.compress import PerMessageDeflateOffer, \ PerMessageDeflateOfferAccept from aiorest_ws.utils.websocket import deflate_offer_accept @pytest.mark.parametrize("offers, expected", [ ([ PerMessageDeflateOffer(), ], PerMessageDeflateOfferAccept), ([ None, ], type(None)), ([], type(None)), ]) def test_deflate_offer_accept(offers, expected): assert type(deflate_offer_accept(offers)) is expected
def test_deflate_lots(reactor, crossbar): """ """ # XXX turning on Deflate seems .. hard # XXX also, why do I have to specify max_... in at least 2 places? # The extensions offered to the server .. offers = [PerMessageDeflateOffer()] # Function to accept responses from the server .. def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response, max_message_size=1500) # we have two components here: one that has a limit on payloads # (component0) and one that doesn't (component1). component0 subscribes # and then component1 sends it one "small enough" and then one "too big" # message (the second should cause component0 to drop its connection). component0 = Component( transports=[ { u"url": u"ws://localhost:6565/ws", u"options": { u"max_frame_payload_size": 1500, u"per_message_compression_offers": offers, u"per_message_compression_accept": accept, } }, ], realm=u"functest_realm1", ) component1 = Component( transports=[ { u"url": u"ws://localhost:6565/ws", u"options": { u"per_message_compression_offers": offers, u"per_message_compression_accept": accept, } }, ], realm=u"functest_realm1", ) listening = Deferred() # component1 waits until component0 subscribes connection_dropped = Deferred() # we want component0 to do this connections = [0] # how many times component0 has connected @component0.on_join @inlineCallbacks def listen(session, details): connections[0] += 1 if connections[0] == 2: print("comp0: re-connected!") elif connections[0] == 1: # we await (potentially) two messages; if we get the second, the # test should fail messages = [Deferred(), Deferred()] yield session.subscribe(lambda x: messages.pop(0).callback(x), u"foo") listening.callback(None) while len(messages): msg = yield messages[0] print("comp0: message: {}".format(msg)) print("comp0: done listening") @component0.on_disconnect def gone(session, was_clean=False): print("comp0: session dropped".format(session, was_clean)) connection_dropped.callback(session) @component1.on_join @inlineCallbacks def send(session, details): yield listening # this one should be small enough to go through yield session.publish(u"foo", u"a" * 20, options=types.PublishOptions(acknowledge=True)) # this will definitely be over 1500 and should fail (due to the other # side's decoder dropping it because the payload is too big). We can't # get an error here because the router accepts it, but the other # *client* will reject... yield session.publish(u"foo", u"a" * 2000, options=types.PublishOptions(acknowledge=True)) # fail-safe if the test doesn't fail for some other reason, it'll fail # after 15s timeout = sleep(15) done = DeferredList([ component0.start(reactor), component1.start(reactor), ]) yield DeferredList([timeout, done, connection_dropped], fireOnOneErrback=True, fireOnOneCallback=True) assert not timeout.called, "shouldn't time out" assert connection_dropped.called, "component0 should have dropped connection"
def run(self, make, start_reactor: bool = True, auto_reconnect: bool = False, log_level: str = 'info', endpoint: Optional[IStreamClientEndpoint] = None, reactor: Optional[IReactorCore] = None ) -> Union[type(None), Deferred]: """ Run the application component. :param make: A factory that produces instances of :class:`autobahn.twisted.wamp.ApplicationSession` when called with an instance of :class:`autobahn.wamp.types.ComponentConfig`. :param start_reactor: When ``True`` (the default) this method starts the Twisted reactor and doesn't return until the reactor stops. If there are any problems starting the reactor or connect()-ing, we stop the reactor and raise the exception back to the caller. :param auto_reconnect: :param log_level: :param endpoint: :param reactor: :return: None is returned, unless you specify ``start_reactor=False`` in which case the Deferred that connect() returns is returned; this will callback() with an IProtocol instance, which will actually be an instance of :class:`WampWebSocketClientProtocol` """ self.log.debug('{klass}.run()', klass=self.__class__.__name__) if start_reactor: # only select framework, set loop and start logging when we are asked # start the reactor - otherwise we are running in a program that likely # already tool care of all this. from twisted.internet import reactor txaio.use_twisted() txaio.config.loop = reactor txaio.start_logging(level=log_level) if callable(make): # factory for use ApplicationSession def create(): cfg = ComponentConfig(self.realm, self.extra, runner=self) try: session = make(cfg) except Exception: self.log.failure( 'ApplicationSession could not be instantiated: {log_failure.value}' ) if start_reactor and reactor.running: reactor.stop() raise else: return session else: create = make if self.url.startswith('rs'): # try to parse RawSocket URL isSecure, host, port = parse_rs_url(self.url) # use the first configured serializer if any (which means, auto-choose "best") serializer = self.serializers[0] if self.serializers else None # create a WAMP-over-RawSocket transport client factory transport_factory = WampRawSocketClientFactory( create, serializer=serializer) else: # try to parse WebSocket URL isSecure, host, port, resource, path, params = parse_ws_url( self.url) # create a WAMP-over-WebSocket transport client factory transport_factory = WampWebSocketClientFactory( create, url=self.url, serializers=self.serializers, proxy=self.proxy, headers=self.headers) # client WebSocket settings - similar to: # - http://crossbar.io/docs/WebSocket-Compression/#production-settings # - http://crossbar.io/docs/WebSocket-Options/#production-settings # The permessage-deflate extensions offered to the server offers = [PerMessageDeflateOffer()] # Function to accept permessage-deflate responses from the server def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) # default WebSocket options for all client connections protocol_options = { 'version': WebSocketProtocol.DEFAULT_SPEC_VERSION, 'utf8validateIncoming': True, 'acceptMaskedServerFrames': False, 'maskClientFrames': True, 'applyMask': True, 'maxFramePayloadSize': 1048576, 'maxMessagePayloadSize': 1048576, 'autoFragmentSize': 65536, 'failByDrop': True, 'echoCloseCodeReason': False, 'serverConnectionDropTimeout': 1., 'openHandshakeTimeout': 2.5, 'closeHandshakeTimeout': 1., 'tcpNoDelay': True, 'perMessageCompressionOffers': offers, 'perMessageCompressionAccept': accept, 'autoPingInterval': 10., 'autoPingTimeout': 5., 'autoPingSize': 12, # see: https://github.com/crossbario/autobahn-python/issues/1327 and # _cancelAutoPingTimeoutCall 'autoPingRestartOnAnyTraffic': True, } # let user override above default options if self.websocket_options: protocol_options.update(self.websocket_options) # set websocket protocol options on Autobahn/Twisted protocol factory, from where it will # be applied for every Autobahn/Twisted protocol instance from the factory transport_factory.setProtocolOptions(**protocol_options) # supress pointless log noise transport_factory.noisy = False if endpoint: client = endpoint else: # if user passed ssl= but isn't using isSecure, we'll never # use the ssl argument which makes no sense. context_factory = None if self.ssl is not None: if not isSecure: raise RuntimeError( 'ssl= argument value passed to %s conflicts with the "ws:" ' 'prefix of the url argument. Did you mean to use "wss:"?' % self.__class__.__name__) context_factory = self.ssl elif isSecure: from twisted.internet.ssl import optionsForClientTLS context_factory = optionsForClientTLS(host) from twisted.internet import reactor if self.proxy is not None: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, self.proxy['host'], self.proxy['port']) transport_factory.contextFactory = context_factory elif isSecure: from twisted.internet.endpoints import SSL4ClientEndpoint assert context_factory is not None client = SSL4ClientEndpoint(reactor, host, port, context_factory) else: from twisted.internet.endpoints import TCP4ClientEndpoint client = TCP4ClientEndpoint(reactor, host, port) # as the reactor shuts down, we wish to wait until we've sent # out our "Goodbye" message; leave() returns a Deferred that # fires when the transport gets to STATE_CLOSED def cleanup(proto): if hasattr(proto, '_session') and proto._session is not None: if proto._session.is_attached(): return proto._session.leave() elif proto._session.is_connected(): return proto._session.disconnect() # when our proto was created and connected, make sure it's cleaned # up properly later on when the reactor shuts down for whatever reason def init_proto(proto): self._connect_successes += 1 reactor.addSystemEventTrigger('before', 'shutdown', cleanup, proto) return proto use_service = False if auto_reconnect: try: # since Twisted 16.1.0 from twisted.application.internet import ClientService from twisted.application.internet import backoffPolicy use_service = True except ImportError: use_service = False if use_service: # this code path is automatically reconnecting .. self.log.debug('using t.a.i.ClientService') if (self.max_retries is not None or self.initial_retry_delay is not None or self.max_retry_delay is not None or self.retry_delay_growth is not None or self.retry_delay_jitter is not None): if self.max_retry_delay > 0: kwargs = {} def _jitter(): j = 1 if self.retry_delay_jitter is None else self.retry_delay_jitter return random.random() * j for key, val in [('initialDelay', self.initial_retry_delay), ('maxDelay', self.max_retry_delay), ('factor', self.retry_delay_growth), ('jitter', _jitter)]: if val is not None: kwargs[key] = val # retry policy that will only try to reconnect if we connected # successfully at least once before (so it fails on host unreachable etc ..) def retry(failed_attempts): if self._connect_successes > 0 and ( self.max_retries == -1 or failed_attempts < self.max_retries): return backoffPolicy(**kwargs)(failed_attempts) else: print('hit stop') self.stop() return 100000000000000 else: # immediately reconnect (zero delay) def retry(_): return 0 else: retry = backoffPolicy() # https://twistedmatrix.com/documents/current/api/twisted.application.internet.ClientService.html self._client_service = ClientService(client, transport_factory, retryPolicy=retry) self._client_service.startService() d = self._client_service.whenConnected() else: # this code path is only connecting once! self.log.debug('using t.i.e.connect()') d = client.connect(transport_factory) # if we connect successfully, the arg is a WampWebSocketClientProtocol d.addCallback(init_proto) # if the user didn't ask us to start the reactor, then they # get to deal with any connect errors themselves. if start_reactor: # if an error happens in the connect(), we save the underlying # exception so that after the event-loop exits we can re-raise # it to the caller. class ErrorCollector(object): exception = None def __call__(self, failure): self.exception = failure.value reactor.stop() connect_error = ErrorCollector() d.addErrback(connect_error) # now enter the Twisted reactor loop reactor.run() # if the ApplicationSession sets an "error" key on the self.config.extra dictionary, which # has been set to the self.extra dictionary, extract the Exception from that and re-raise # it as the very last one (see below) exciting back to the caller of self.run() app_error = self.extra.get('error', None) # if we exited due to a connection error, raise that to the caller if connect_error.exception: raise connect_error.exception elif app_error: raise app_error else: # let the caller handle any errors return d
if __name__ == '__main__': USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.81 Safari/537.36" url = 'wss://premws-pt3.365lpodds.com/zap/' factory = WebSocketClientFactory( url, useragent=USER_AGENT, protocols=['zap-protocol-v1']) factory.protocol = MyClientProtocol factory.headers = {} factory.session_id = get_session_id() def accept(response): if isinstance(response, PerMessageDeflateResponse): return PerMessageDeflateResponseAccept(response) factory.setProtocolOptions(perMessageCompressionAccept=accept) factory.setProtocolOptions(perMessageCompressionOffers=[PerMessageDeflateOffer( accept_max_window_bits=True, accept_no_context_takeover=True, request_max_window_bits=0, request_no_context_takeover=True, )]) # reactor.callFromThread(connectWS, factory) # reactor.run() if factory.isSecure: contextFactory = ssl.ClientContextFactory() else: contextFactory = None connectWS(factory, contextFactory) reactor.run()