if (obj != -1): self.channelarr.remove(obj) else: return -1 async def pruneUsers(self): for user in self.userarr: if((int(time.time() - user.systemtime)) > 10): await user.__destructor__() self.removeUser(user) def onMainCtlEvent(self, *command): if(command[0] == "NICK" and (self.findUser(command[1])) == -1): user = User(command[1], 'com.audioctl.' + command[1], 'com.audiodata.' + command[1], self,command[2]) self.userarr.append(user) user.subscription = yield from self.subscribe(user.ctlCallback, user.ctlchan) async def onJoin(self, details): self.initialize() await self.subscribe(self.onMainCtlEvent, u"com.audioctl.main") await self.pruneLoop() def initialize(self): self.userarr = [] self.channelarr = [] (self.serverpubkey, self.serverprivkey) = rsa.newkeys(1536) runner = ApplicationRunner(u"ws://127.0.0.1:8080/ws", u"realm1") runner.run(Server)
print("Arglen 1: {}".format(arglengths)) arglengths = await self.call(u'com.arguments.arglen', 1, 2, 3) print("Arglen 1: {}".format(arglengths)) arglengths = await self.call(u'com.arguments.arglen', a=1, b=2, c=3) print("Arglen 2: {}".format(arglengths)) arglengths = await self.call(u'com.arguments.arglen', 1, 2, 3, a=1, b=2, c=3) print("Arglen 3: {}".format(arglengths)) self.leave() def onDisconnect(self): asyncio.get_event_loop().stop() if __name__ == '__main__': import six url = environ.get("AUTOBAHN_DEMO_ROUTER", u"ws://localhost:8000/ws") if six.PY2 and type(url) == six.binary_type: url = url.decode('utf8') realm = u"crossbardemo" runner = ApplicationRunner(url, realm) runner.run(Component)
self.controllers[controller] = controller_mods[ controller].Controller(controllers[controller], cbs=callback_collection, rpc_target=self) self.register(self.describe, '{}.describe'.format(self.namespace)) self.register(self.get_telemetry, '{}.get_telemetry'.format(self.namespace)) self.subscribe(self.http_register, self.namespace + '.describe') print(self.controllers) executor = ThreadPoolExecutor(len([self.controllers.values()])) loop = asyncio.get_event_loop() for controller in self.controllers.values(): print(controller) boo = asyncio.ensure_future(controller.start_status_loop(), loop=loop) while True: # for controller in self.controllers.values(): # for sub in controller.controllers.values(): # sub.notifyStatus() # all(map(lambda x: x.notifyStatus(), controller.controllers.values())) await asyncio.sleep(1) if __name__ == '__main__': runner = ApplicationRunner( environ.get("AUTOBAHN_ROUTER", u"ws://localhost:8080/ws"), u"controlroom") runner.run(ControlroomAPI)
''' if __name__ == '__main__': import sys import logging import inject sys.path.insert(0, '../python') logging.basicConfig(level=logging.DEBUG) from autobahn.asyncio.wamp import ApplicationRunner from model.config import Config from actions.systems.assistance.firmware import WampFirmware def config_injector(binder): binder.bind(Config, Config('server-config.cfg')) inject.configure(config_injector) config = inject.instance(Config) url = config.configs['server_url'] realm = config.configs['server_realm'] debug = config.configs['server_debug'] runner = ApplicationRunner(url=url, realm=realm, debug=debug, debug_wamp=debug, debug_app=debug) runner.run(WampFirmware)
raise ApplicationError("com.myapp.error.mixed_case", name.lower(), name.upper()) if len(name) < 3 or len(name) > 10: # forward keyword arguments in exceptions raise ApplicationError("com.myapp.error.invalid_length", min=3, max=10) self.register(checkname, 'com.myapp.checkname') # defining and automapping WAMP application exceptions ## self.define(AppError1) def compare(a, b): if a < b: raise AppError1(b - a) self.register(compare, 'com.myapp.compare') if __name__ == '__main__': runner = ApplicationRunner( environ.get("AUTOBAHN_DEMO_ROUTER", "ws://localhost:8080/ws"), u"crossbardemo", debug_wamp=False, # optional; log many WAMP details debug=False, # optional; log even more details ) runner.run(Component)
class DiscordComponent(ApplicationSession): def __init__(self, bot: Red, component_config: dict, *args, **kwargs): super().__init__(*args, **kwargs) self.bot = bot self.config = component_config print(component_config) print(self.bot.guilds) def onConnect(self): self.join(self.config["realm"], ["wampcra"], self.config["user"]) def onChallenge(self, challenge): assert challenge.method == "wampcra", "don't know how to handle authmethod {}".format( challenge.method) signature = auth.compute_wcs( self.config["secret"].encode("utf8"), challenge.extra["challenge"].encode("utf8")) return signature.decode("ascii") def onJoin(self, details): print("hello darkness") if __name__ == '__main__': runner = ApplicationRunner(url="ws://crosku.herokuapp.com/ws", realm="realm1") runner.run(DiscordComponent)
# create and store collection collectionName = self.exchange + "_" + pair collection = mongoClient[collectionName] except Exception as e: logger.info("could not subscribe to {} on {}: {}".format(pair, exchange, e)) sys.exit(1) class PoloniexClient(TradeClient): exchange = "poloniex" # set up logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.CRITICAL) logger.setLevel(logging.DEBUG) handler = logging.FileHandler('stockdaemon.log') handler.setLevel(logging.DEBUG) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) logger.addHandler(handler) # initialise mongo client & open database mongoClient = MongoClient() db = mongoClient['autotrader'] # run poloniex WAMP client poloniex_URL = "wss://api.poloniex.com" poloniex_runner = ApplicationRunner(url = poloniex_URL, realm = "realm1") poloniex_runner.run(PoloniexClient)
def launch_wamp(engine): runner = ApplicationRunner(url='ws://localhost:8080/ws', realm='realm1') with SessionSet(engine) as sessions: runner.run(lambda *args, **kwargs: DoorstepComponent( engine, sessions, *args, **kwargs))
foleyParent + fbase + "\\" + fname, stateParent + fbase + "\\" + fname ] args = EventCreateArgs(eventParent+fbase+"\\",fname,eventTargets) yield from createWwiseObject(args) print("done!") endUndoGroup() saveWwiseProject() exit() def onDisconnect(self): print("The client was disconnected.") asyncio.get_event_loop().stop() if __name__ == '__main__': runner = ApplicationRunner(url=u"ws://127.0.0.1:8095/waapi", realm=u"realm1") try: runner.run(MyComponent) except Exception as e: print(type(e).__name__ + ": Is Wwise running and Wwise Authoring API enabled?")
def main(): runner = ApplicationRunner("wss://api.poloniex.com:443", "realm1") runner.run(PoloniexComponent)
def release_place(self, name, details=None): print(details) try: place = self.places[name] except KeyError: return False if not place.acquired: return False place.acquired = None place.acquired_resources = [] place.touch() self.publish('org.labgrid.coordinator.place_changed', name, place.asdict()) yield from self.save() return True def _get_places(self): return {k: v.asdict() for k, v in self.places.items()} @asyncio.coroutine def get_places(self, details=None): return self._get_places() if __name__ == '__main__': runner = ApplicationRunner( url=environ.get("WS", u"ws://127.0.0.1:20408/ws"), realm="realm1", ) runner.run(CoordinatorComponent)
def main_function(): sp.call('cls', shell=True) runner = ApplicationRunner(url="wss://overwatch.johnelgin.me:8080/ws", realm="com.voxter.teambuilder") runner.run(AppController)
import os import logging from autobahn.asyncio.wamp import ApplicationRunner from issues.api.wamp import Issues import txaio txaio.use_asyncio() txaio.start_logging(level='debug') if __name__ == '__main__': logging.info('Ejecuando loop') runner = ApplicationRunner(url=os.environ['CROSSBAR_URL'], realm=os.environ['CROSSBAR_REALM']) runner.run(Issues)
import ssl class Component(ApplicationSession): """ An application component that publishes an event every second. """ @asyncio.coroutine def onJoin(self, details): counter = 0 while True: print("publish: com.myapp.topic1", counter) self.publish(u'com.myapp.topic1', counter) counter += 1 yield from asyncio.sleep(1) if __name__ == '__main__': # see README; this way everything accesses same cert-files cert_path = '../../../../twisted/wamp/pubsub/tls/server.crt' print(cert_path) # create an ssl.Context using just our self-signed cert as the CA certificates options = ssl.create_default_context(cadata=open(cert_path, 'r').read()) # ...which we pass as "ssl=" to ApplicationRunner (passed to loop.create_connection) runner = ApplicationRunner( environ.get("AUTOBAHN_DEMO_ROUTER", u"wss://127.0.0.1:8083/ws"), u"crossbardemo", ssl=options, # try removing this, but still use self-signed cert ) runner.run(Component)
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug output.') parser.add_argument( '--url', dest='url', type=six.text_type, default=url, help='The router URL (default: "ws://localhost:8080/ws").') parser.add_argument('--realm', dest='realm', type=six.text_type, default=realm, help='The realm to join (default: "realm1").') args = parser.parse_args() # start logging if args.debug: txaio.start_logging(level='debug') else: txaio.start_logging(level='info') # any extra info we want to forward to our ClientSession (in self.config.extra) extra = {u'foobar': u'A custom value'} # now actually run a WAMP client using our session class ClientSession runner = ApplicationRunner(url=args.url, realm=args.realm, extra=extra) runner.run(ClientSession)
def main(): parser = argparse.ArgumentParser() parser.add_argument('-x', '--crossbar', metavar='URL', type=str, default=os.environ.get("LG_CROSSBAR", "ws://127.0.0.1:20408/ws"), help="crossbar websocket URL") parser.add_argument( '-n', '--name', dest='name', type=str, default=None, help='public name of this exporter (defaults to the system hostname)') parser.add_argument( '--hostname', dest='hostname', type=str, default=None, help= 'hostname (or IP) published for accessing resources (defaults to the system hostname)' ) parser.add_argument('-d', '--debug', action='store_true', default=False, help="enable debug mode") parser.add_argument( '-i', '--isolated', action='store_true', default=False, help="enable isolated mode (always request SSH forwards)") parser.add_argument('resources', metavar='RESOURCES', type=str, help='resource config file name') args = parser.parse_args() level = 'debug' if args.debug else 'info' extra = { 'name': args.name or gethostname(), 'hostname': args.hostname or gethostname(), 'resources': args.resources, 'isolated': args.isolated } crossbar_url = args.crossbar crossbar_realm = os.environ.get("LG_CROSSBAR_REALM", "realm1") print(f"crossbar URL: {crossbar_url}") print(f"crossbar realm: {crossbar_realm}") print(f"exporter name: {extra['name']}") print(f"exporter hostname: {extra['hostname']}") print(f"resource config file: {extra['resources']}") extra['loop'] = loop = asyncio.get_event_loop() if args.debug: loop.set_debug(True) runner = ApplicationRunner(url=crossbar_url, realm=crossbar_realm, extra=extra) runner.run(ExporterSession, log_level=level) if reexec: exit(100)
@asyncio.coroutine def onJoin(self, details): self.received = 0 def on_heartbeat(details=None): print("Got heartbeat (publication ID {})".format( details.publication)) yield from self.subscribe( on_heartbeat, u'com.myapp.heartbeat', options=SubscribeOptions(details_arg='details')) def on_topic2(a, b, c=None, d=None): print("Got event: {} {} {} {}".format(a, b, c, d)) yield from self.subscribe(on_topic2, u'com.myapp.topic2') asyncio.get_event_loop().call_later(5, self.leave) def onDisconnect(self): asyncio.get_event_loop().stop() if __name__ == '__main__': runner = ApplicationRunner( environ.get("AUTOBAHN_DEMO_ROUTER", u"ws://127.0.0.1:8080/ws"), u"crossbardemo", debug=False, # optional; log even more details ) runner.run(Component)
await self.register(self.set_station, 'game.h2ops.set_station') await self.game_register() def onDisconnect(self): """ Called when the WAMP connection is disconnected :return: None """ asyncio.get_event_loop().stop() if __name__ == '__main__': if GAME_ID == 'demo_game': print("Please change GAME_ID to something else!") exit(1) global settings try: with open('h2ops.conf') as f: SETTINGS = json.load(f) except: print("Error! Could not find 'h2ops.conf'") exit(1) runner = ApplicationRunner( WAMP_URL, WAMP_REALM, ) runner.run(GameComponent, log_level='info')
def main(): runner = ApplicationRunner(url="ws://localhost:8080/ws", realm="realm1") runner.run(ClientSession)
class Component(ApplicationSession): """ An application component that publishes an event every second. """ @asyncio.coroutine def onJoin(self, details): counter = 0 while True: print("publish: com.myapp.topic1", counter) self.publish(u'com.myapp.topic1', counter) counter += 1 yield from asyncio.sleep(1) if __name__ == '__main__': # see README; this way everything accesses same cert-files cert_path = '../../../../twisted/wamp/pubsub/tls/server.crt' print(cert_path) # create an ssl.Context using just our self-signed cert as the CA certificates options = ssl.create_default_context(cadata=open(cert_path, 'r').read()) # ...which we pass as "ssl=" to ApplicationRunner (passed to loop.create_connection) runner = ApplicationRunner( environ.get("AUTOBAHN_DEMO_ROUTER", u"wss://127.0.0.1:8083/ws"), u"crossbardemo", ssl=options, # try removing this, but still use self-signed cert debug_wamp=False, # optional; log many WAMP details debug=False, # optional; log even more details ) runner.run(Component)
'address': '33 Nº 3333', 'genre': 'Masculino', 'birthdate': datetime.datetime(1980, 7, 20), 'residence_city': 'La Plata', 'version': 0 } userId = yield from self.call('users.persistUser', user) logging.info("********** ID DEL USUARIO PERSISTIDO **********") logging.info(userId) if __name__ == '__main__': from autobahn.asyncio.wamp import ApplicationRunner from autobahn.wamp.serializer import JsonSerializer url = config.configs['server_url'] realm = config.configs['server_realm'] debug = config.configs['server_debug'] json = JsonSerializer() runner = ApplicationRunner(url=url, realm=realm, debug=debug, debug_wamp=debug, debug_app=debug, serializers=[json]) runner.run(WampMain)
if self.IsConnect: self.publish(topic, event, c=topic) else: print("lost connect") except Exception as e: print("can't connect to wamp server") @coroutine def onJoin(self, details): print("session ready") while True: try: block_info = client.request("get_info", []).json()["result"] height = int(block_info["blockchain_head_block_num"]) self.mypublish(u'btsbots.demo.height', height) except Exception as e: print(e) yield from sleep(10) def onLeave(self, details): print("onLeave: {}".format(details)) self.disconnect() def onDisconnect(self): self.IsConnect = False print("onDisconnect: {}".format(details)) runner = ApplicationRunner(url = config_wamp["url"], realm = config_wamp["realm"]) runner.run(MyComponent)
2, "19223201", "BootNotification", { "chargePointVendor": "VendorX", "chargePointModel": "SingleSocketCharger" } ] auth_packet = [2, "18521553", "Authorize", { "idTag": "123456789" }] class MyComponent(ApplicationSession): async def onJoin(self, details): print("session ready") try: res = await self.call(u'com.myapp.auth', auth_packet[0], auth_packet[1], auth_packet[2], auth_packet[3]) print("call result: {}".format(res)) except Exception as e: print("call error: {0}".format(e)) self.leave() def onDisconnect(self): print("End") asyncio.get_event_loop().stop() runner = ApplicationRunner(url=u"ws://localhost:8080/ocpp", realm=u"realm1") runner.run(MyComponent)
from autobahn.asyncio.wamp import ApplicationSession, ApplicationRunner WAMP = { 'router': 'ws://127.0.0.1:8080/ws', 'realm': 'market', } class Stub(ApplicationSession): def onJoin(self, details): self.publish('has.been.stored', "COUCOU") r = ApplicationRunner(WAMP['router'], WAMP['realm']) r.run(Stub)
counter = 0 while True: print("publish: com.myapp.topic", counter) self.publish('com.myapp.topic', counter) counter += 1 await asyncio.sleep(1) if __name__ == '__main__': ssl.match_hostname = lambda cert, hostname: True ca_cert_path = '../client-cert/ca-cert.pem' print(ca_cert_path) client_cert_path = '../client-cert/client-cert.pem' print(client_cert_path) client_key_path = '../client-cert/client-priv.pem' print(client_key_path) # context = ssl.create_default_context(capath='../client-cert/') context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.verify_mode = ssl.CERT_REQUIRED # load a set of CA files context.load_verify_locations(ca_cert_path) # load a client's cert and private key context.load_cert_chain(certfile=client_cert_path, keyfile=client_key_path) # url = "ws://127.0.0.1:8080/ws" url = "wss://127.0.0.1:9000" realm = "crossbardemo" runner = ApplicationRunner(url, realm, ssl=context) runner.run(Component)
#!/usr/bin/env python import argparse from autobahn.asyncio.wamp import ApplicationRunner from light.autobahn.database import DatabaseComponent from light.database import DatabaseSpecifier if __name__ == '__main__': parser = argparse.ArgumentParser( description='Start a WAMP-based distributed light-matter database.') databaseSpecifier = DatabaseSpecifier(allowInMemory=False) databaseSpecifier.addArgsToParser(parser) args = parser.parse_args() # We're always using WAMP for distributed databases. args.wampServer = True database = databaseSpecifier.getDatabaseFromArgs(args) runner = ApplicationRunner(args.wampUrl, args.realm, extra=dict(database=database)) runner.run(DatabaseComponent)
r_pipe.set(":".join([mname,cur,'book']),str(time.time())) r_pipe.zunionstore(":".join([mname,cur,'ask']), [ ":".join([mname,cur,'ask','back']) ] ) r_pipe.zunionstore(":".join([mname,cur,'bid']), [ ":".join([mname,cur,'bid','back']) ] ) r_pipe.execute() url = "wss://api.poloniex.com" runner = ApplicationRunner(url = url, realm = "realm1") print("after runner") initialob('ltc') initialob('usd') initialob('lsd') runner.run(MyComponent)
def run_context(self, ctx): if False: click.echo('Logging started ..') txaio.start_logging(level='debug', out=sys.stdout) # cfg contains the command lines options and arguments that # click collected for us cfg = ctx.obj cmd = ctx.command.name if cmd not in [u'auth', u'shell']: raise click.ClickException( '"{}" command can only be run in shell'.format(cmd)) click.echo('Crossbar.io Fabric Shell: {}'.format( style_ok('v{}'.format(__version__)))) # load user profile and key for given profile name key, profile = self._load_profile(profile=cfg.profile) # set the Fabric URL to connect to from the profile or default url = profile.url or u'wss://fabric.crossbario.com' # users always authenticate with the user_id from the key, which # filled from the email the user provided authid = key.user_id # the realm can be set from command line, env var, the profile # or can be None, which means the user will be joined to the global # Crossbar.io Fabric users realm (u'com.crossbario.fabric') realm = cfg.realm or profile.realm or None # the authrole can be set from command line, env var, the profile # or can be None, in which case the role is chosen automatically # from the list of roles the user us authorized for authrole = cfg.role or profile.role or None # this will be fired when the ShellClient below actually has joined # the respective realm on Crossbar.io Fabric (either the global users # realm, or a management realm the user has a role on) ready = asyncio.Future() extra = { # these are forward on the actual client connection u'authid': authid, u'authrole': authrole, # these are native Python object and only used client-side u'key': key, u'done': ready } # for the "auth" command, forward additional command line options if ctx.command.name == u'auth': # user provides authentication code to verify extra[u'activation_code'] = cfg.code # user requests sending of a new authentication code (while an old one is still pending) extra[u'request_new_activation_code'] = cfg.new_code # this is the WAMP ApplicationSession that connects the CLI to Crossbar.io Fabric self.session = client.ShellClient(ComponentConfig(realm, extra)) loop = asyncio.get_event_loop() runner = ApplicationRunner(url, realm) # this might fail eg when the transport connection cannot be established try: click.echo('Connecting to {} ..'.format(url)) _res = runner.run(self.session, start_loop=False) except socket.gaierror as e: click.echo( style_error('Could not connect to {}: {}'.format(url, e))) loop.close() sys.exit(1) exit_code = 0 try: # "connected" will complete when the WAMP session to Fabric # has been established and is ready click.echo('Entering event loop ..') transport, protocol = loop.run_until_complete(_res) #click.echo('transport, protocol: {} {}'.format(transport, protocol)) #loop.run_forever() session_details = loop.run_until_complete(ready) #click.echo('SessionDetails: {}'.format(session_details)) except ApplicationError as e: # some ApplicationErrors are actually signaling progress # in the authentication flow, some are real errors if e.error.startswith(u'fabric.auth-failed.'): error = e.error.split(u'.')[2] message = e.args[0] if error == u'new-user-auth-code-sent': click.echo('\nThanks for registering! {}'.format(message)) click.echo( style_ok( 'Please check your inbox and run "cbsh auth --code <THE CODE YOU GOT BY EMAIL>.\n' )) elif error == u'registered-user-auth-code-sent': click.echo('\nWelcome back! {}'.format(message)) click.echo( style_ok( 'Please check your inbox and run "cbsh auth --code <THE CODE YOU GOT BY EMAIL>.\n' )) elif error == u'pending-activation': click.echo() click.echo(style_ok(message)) click.echo() click.echo( 'Tip: to activate, run "cbsh auth --code <THE CODE YOU GOT BY EMAIL>"' ) click.echo( 'Tip: you can request sending a new code with "cbsh auth --new-code"' ) click.echo() elif error == u'no-pending-activation': exit_code = 1 click.echo() click.echo(style_error('{} [{}]'.format(message, e.error))) click.echo() elif error == u'email-failure': exit_code = 1 click.echo() click.echo(style_error('{} [{}]'.format(message, e.error))) click.echo() elif error == u'invalid-activation-code': exit_code = 1 click.echo() click.echo(style_error('{} [{}]'.format(message, e.error))) click.echo() else: # we should not arrive here! otherwise, add a new clause above and handle the situation exit_code = 1 click.echo( style_error( 'Internal error: unprocessed error type {}:'. format(error))) click.echo(style_error(message)) elif e.error.startswith(u'crossbar.error.'): error = e.error.split(u'.')[2] message = e.args[0] if error == u'invalid_configuration': click.echo() click.echo(style_error('{} [{}]'.format(message, e.error))) click.echo() else: # we should not arrive here! otherwise, add a new clause above and handle the situation exit_code = 1 click.echo( style_error( 'Internal error: unprocessed error type {}:'. format(error))) click.echo(style_error(message)) else: click.echo(style_error('{}'.format(e))) exit_code = 1 raise else: if cmd == u'auth': self._print_welcome(url, session_details) elif cmd == 'shell': click.clear() try: self._print_welcome(url, session_details) except Exception as e: click.echo('err: {}'.format(e)) prompt_kwargs = { 'history': self._history, } shell_task = loop.create_task( repl.repl( ctx, get_bottom_toolbar_tokens=self. _get_bottom_toolbar_tokens, #get_prompt_tokens=self._get_prompt_tokens, style=self._style, prompt_kwargs=prompt_kwargs)) loop.run_until_complete(shell_task) else: # should not arrive here, as we checked cmd in the beginning raise Exception('logic error') finally: loop.close() sys.exit(exit_code)
# res is an Registration instance print( "Ok, registered procedure with registration ID {}".format( res.id)) else: # res is an Failure instance print("Failed to register procedure: {}".format(res)) @wamp.register(u'com.mathservice.add2') def add2(self, x, y): return x + y @wamp.register(u'com.mathservice.mul2') def mul2(self, x, y): return x * y @wamp.register(u'com.mathservice.div2') def square(self, x, y): if y: return float(x) / float(y) else: return 0 if __name__ == '__main__': runner = ApplicationRunner( environ.get("AUTOBAHN_DEMO_ROUTER", u"ws://127.0.0.1:8080/ws"), u"crossbardemo", ) runner.run(Component)
options = parser.parse_args() # forward requested authid and key filename to ClientSession extra = { u'authid': options.authid, u'key': options.key } print("Connecting to {}: realm={}, authid={}".format(options.url, options.realm, options.authid)) tls_config = { "hostname": "localhost", "certificate": "client.crt", "key": "client.key", "ca_certificates": [ "intermediate.cert.pem", "ca.cert.pem" ] } from crossbar.common.twisted.endpoint import _create_tls_client_context from txaio import make_logger log = make_logger() cert_options = _create_tls_client_context(tls_config, '.crossbar', log) # connect to router and run ClientSession runner = ApplicationRunner(url=options.url, realm=options.realm, extra=extra, ssl=cert_options) runner.run(ClientSession)