Example #1
0
def io_loop(event_loop, request):
    """Same as pytest-tornado.io_loop, but re-scoped to module-level"""
    ioloop.IOLoop.configure(AsyncIOMainLoop)
    io_loop = AsyncIOMainLoop()
    io_loop.make_current()
    assert asyncio.get_event_loop() is event_loop
    assert io_loop.asyncio_loop is event_loop

    def _close():
        io_loop.clear_current()
        io_loop.close(all_fds=True)

    request.addfinalizer(_close)
    return io_loop
Example #2
0
def io_loop(event_loop, request):
    """Same as pytest-tornado.io_loop, but re-scoped to module-level"""
    ioloop.IOLoop.configure(AsyncIOMainLoop)
    io_loop = AsyncIOMainLoop()
    io_loop.make_current()
    assert asyncio.get_event_loop() is event_loop
    assert io_loop.asyncio_loop is event_loop

    def _close():
        io_loop.clear_current()
        io_loop.close(all_fds=True)

    request.addfinalizer(_close)
    return io_loop
def io_loop(event_loop, request):
    """Make sure tornado io_loop is run on asyncio"""
    ioloop.IOLoop.configure(AsyncIOMainLoop)
    io_loop = AsyncIOMainLoop()
    io_loop.make_current()
    assert asyncio.get_event_loop() is event_loop
    assert io_loop.asyncio_loop is event_loop

    def _close():
        io_loop.clear_current()
        io_loop.close(all_fds=True)

    request.addfinalizer(_close)
    return io_loop
Example #4
0
    def start_tornado(self):
            """
            Starts a Tornado server with specific endpoints specified in the dictionary endpoints.
            Each endpoint should have a respective Handler Class implemented in tge tornado_endpoints module.
            To initialize the members of the Handler Classes you pass a dictionary after the Class Argument.

            :return: Tornado application that was created
            """


            urls = [
                ("/api/query", AnalyzeQuery, dict(
                    handlers={"report": MessageManagerWebsocketFromServices.report_to_connections})),
                ("/api/csrf" , CSRF, dict(
                    handlers={"report": MessageManagerWebsocketFromServices.report_to_connections})),
                ('/api/viralurls', ViralUrls,dict(
                    handlers={"report": MessageManagerWebsocketFromServices.report_to_connections})),
                ('/api/intrusion' , IntrusionDetection, dict(
                    handlers={"report": MessageManagerWebsocketFromServices.report_to_connections}))
            ]

            print("Started Tornado")
            AsyncIOMainLoop().install()  # Allows to use Asyncio main event loop ; https://www.tornadoweb.org/en/branch4.5/asyncio.html
            app = Application(urls, debug=TORNADO_DEBUG)
            app.listen(TORNADO_PORT)
            IOLoop.current().start()
            return app
Example #5
0
    def start(self):
        self.sockets = tornado.netutil.bind_sockets(
            *self.naumanni_app.config.listen)
        children = self.fork(0)

        # こっからはMasterの世界
        # use asyncio for ioloop
        AsyncIOMainLoop().install()
        self.children = [
            ChildProc(
                proc,
                iostream.PipeIOStream(fdr),
                iostream.PipeIOStream(fdw),
            ) for proc, fdr, fdw in children
        ]

        # run self.naumanni_app.setup(None) synchronusly
        io_loop = ioloop.IOLoop.current()
        io_loop.run_sync(functools.partial(self.naumanni_app.setup, None))

        # master run loop
        io_loop.start()

        for task_id, child in enumerate(self.children):
            child.proc.join()
Example #6
0
    def current(instance=True):
        """Returns the current thread's `IOLoop`.

        If an `IOLoop` is currently running or has been marked as
        current by `make_current`, returns that instance.  If there is
        no current `IOLoop` and ``instance`` is true, creates one.

        .. versionchanged:: 4.1
           Added ``instance`` argument to control the fallback to
           `IOLoop.instance()`.
        .. versionchanged:: 5.0
           The ``instance`` argument now controls whether an `IOLoop`
           is created automatically when there is none, instead of
           whether we fall back to `IOLoop.instance()` (which is now
           an alias for this method)
        """
        current = getattr(IOLoop._current, "instance", None)
        if current is None and instance:
            current = None
            if asyncio is not None:
                from tornado.platform.asyncio import AsyncIOLoop, AsyncIOMainLoop
                if IOLoop.configured_class() is AsyncIOLoop:
                    current = AsyncIOMainLoop()
            if current is None:
                current = IOLoop()
            if IOLoop._current.instance is not current:
                raise RuntimeError("new IOLoop did not become current")
        return current
Example #7
0
def main():
    import tornado.httpserver
    from tornado.options import define, options

    from tornado.platform.asyncio import AsyncIOMainLoop
    import asyncio
    AsyncIOMainLoop().install()

    define("port",
           default=config.DEFAULT_PORT,
           help="run on the given port",
           type=int)
    define("address", default='', help="run on the given address", type=str)
    define("datadir",
           default=config.DEFAULT_DATA_DIR,
           help="the directory to put uploaded data",
           type=str)
    define("fork", default=False, help="fork after startup", type=bool)
    define("cloudflare",
           default=config.CLOUDFLARE,
           help="check for Cloudflare IPs",
           type=bool)
    define("password",
           default=config.UPLOAD_PASSWORD,
           help="optional password",
           type=str)

    tornado.options.parse_command_line()
    if options.fork:
        if os.fork():
            sys.exit()

    if options.cloudflare:
        import cloudflare
        cloudflare.install()
        loop = asyncio.get_event_loop()
        loop.create_task(cloudflare.updater())

    application = tornado.web.Application(
        [
            (r"/", IndexHandler),
            (r"/" + SCRIPT_PATH, ToolHandler),
            (r"/([a-fA-F0-9]{2}/[a-fA-F0-9]{38})(?:\.\w*)?",
             tornado.web.StaticFileHandler, {
                 'path': options.datadir,
             }),
            (r"/([a-fA-F0-9/]+(?:\.\w*)?)", HashHandler),
        ],
        datadir=options.datadir,
        debug=config.DEBUG,
        template_path=os.path.join(os.path.dirname(__file__), "templates"),
        password=config.UPLOAD_PASSWORD,
    )
    http_server = tornado.httpserver.HTTPServer(
        application,
        xheaders=config.XHEADERS,
    )
    http_server.listen(options.port, address=options.address)

    asyncio.get_event_loop().run_forever()
Example #8
0
def start_service(service, infos):
    AsyncIOMainLoop().install()
    loop = tornado.ioloop.IOLoop.current()
    loop.spawn_callback(service.start)
    loop.spawn_callback(service.on_control_msg)
    loop.spawn_callback(service.heartbeat, infos)
    loop.start()
Example #9
0
    def run(self):  # pragma: no cover
        AsyncIOMainLoop().install()

        iol = tornado.ioloop.IOLoop.instance()

        http_server = tornado.httpserver.HTTPServer(self.app)
        http_server.listen(self.options.web_port, self.options.web_iface)

        iol.add_callback(self.start)

        web_url = "http://{}:{}/".format(self.options.web_iface, self.options.web_port)
        self.add_log(
            "Web   server listening at {}".format(web_url),
            "info"
        )

        if self.options.web_open_browser:
            success = open_browser(web_url)
            if not success:
                self.add_log(
                    "No web browser found. Please open a browser and point it to {}".format(web_url),
                    "info"
                )
        try:
            iol.start()
        except KeyboardInterrupt:
            self.shutdown()
Example #10
0
async def serve_development_app(
    app: Application,
    host: str,
    port: int,
    started: asyncio.Event | None = None,
) -> None:
    enable_pretty_logging()

    # setup up tornado to use asyncio
    AsyncIOMainLoop().install()

    server = HTTPServer(app)
    server.listen(port, host)

    if started:
        # at this point the server is accepting connection
        started.set()

    try:
        # block forever - tornado has already set up its own background tasks
        await asyncio.get_event_loop().create_future()
    finally:
        # stop accepting new connections
        server.stop()
        # wait for existing connections to complete
        await server.close_all_connections()
Example #11
0
def main():
    settings = config.server
    settings["static_path"] = config.static_path
    settings["template_path"] = config.template_path
    port = settings.pop("port")
    address = settings.pop("host")
    sockets = bind_sockets(port, address=address)

    if sys.platform != "win32":
        import uvloop

        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

    fork_processes(0 if config.env != "dev" else 1)

    AsyncIOMainLoop().install()
    loop = asyncio.get_event_loop()
    ThreadPool.init_thread_pool(workers=config.server["thread_worker"])

    app = application.Application(
        settings=settings,
        loop=loop,
        model_routers=MODEL_ROUTERS,
        before_hooks=BEFORE_HOOKS,
        after_hooks=AFTER_HOOKS,
        delay_tasks=DELAY_TASKS,
        periodic_tasks=PERIODIC_TASKS,
    )

    app.start_periodic_tasks()
    app.start_delay_tasks()
    server = httpserver.HTTPServer(app)
    server.add_sockets(sockets)
    logging.debug(f"🚀 Server ready at http://{address}:{port}")
    loop.run_forever()
    def current(instance=True):
        """Returns the current thread's `IOLoop`.

        If an `IOLoop` is currently running or has been marked as
        current by `make_current`, returns that instance.  If there is
        no current `IOLoop` and ``instance`` is true, creates one.

        .. versionchanged:: 4.1
           Added ``instance`` argument to control the fallback to
           `IOLoop.instance()`.
        .. versionchanged:: 5.0
           On Python 3, control of the current `IOLoop` is delegated
           to `asyncio`, with this and other methods as pass-through accessors.
           The ``instance`` argument now controls whether an `IOLoop`
           is created automatically when there is none, instead of
           whether we fall back to `IOLoop.instance()` (which is now
           an alias for this method). ``instance=False`` is deprecated,
           since even if we do not create an `IOLoop`, this method
           may initialize the asyncio loop.
        """
        try:
            loop = asyncio.get_event_loop()
        except (RuntimeError, AssertionError):
            if not instance:
                return None
            raise
        try:
            return IOLoop._ioloop_for_asyncio[loop]
        except KeyError:
            if instance:
                from tornado.platform.asyncio import AsyncIOMainLoop
                current = AsyncIOMainLoop(make_current=True)
            else:
                current = None
        return current
Example #13
0
    def __init__(self):

        self._is_linux = (platform.system() == r'Linux')  # 判定当前平台

        self._process_id = 0
        self._process_num = cpu_count()  # cup数

        self._sockets = bind_sockets(Config.Port)  # 创建socket对象,绑定端口

        if self._is_linux:  # 如果是linux系统

            self._process_id = fork_processes(self._process_num)  #

        self._init_options()

        AsyncIOMainLoop().install()

        self._event_loop = asyncio.get_event_loop()
        self._server = HTTPServer(Application(**self._settings))

        signal.signal(signal.SIGINT, self.stop)
        signal.signal(signal.SIGTERM, self.stop)

        from model.base import initialize as model_initialize

        IOLoop.instance().run_sync(model_initialize)
Example #14
0
def main():
    """
    Tornado AsyncIO integration needs to fork processes before asyncio event loop gets initiated per process
    http://www.tornadoweb.org/en/stable/asyncio.html
    https://stackoverflow.com/questions/42767635
    """
    sockets = tornado.netutil.bind_sockets(8888)
    tornado.process.fork_processes(1)
    AsyncIOMainLoop().install()

    app = Application(handlers=[
        (r"/", MainHandler),
        (r"/sleep", BackGroundSleepHandler),
        (r"/sleep2", AwaitedSleepHandler),
    ])

    server = HTTPServer(app)

    server.add_sockets(sockets)
    print('Server Started')

    event_loop = asyncio.get_event_loop()
    try:
        event_loop.run_forever()
    except KeyboardInterrupt:
        print("Shutting down server")
    finally:
        event_loop.run_until_complete(event_loop.shutdown_asyncgens())
        event_loop.close()
Example #15
0
def start() -> None:
    version_check.check_pyopenssl_version()

    AsyncIOMainLoop().install()
    loop = asyncio.get_event_loop()

    intercepts = Intercepts()
    proxy = Proxy(loop, UpdatesHandler.broadcast)

    web_options, server = configuration()
    master = Master(web_options, loop, proxy, server)

    web_application = Application(master, intercepts)
    http_server = tornado.httpserver.HTTPServer(web_application)
    http_server.listen(5000, "127.0.0.1")

    tornado_loop = tornado.ioloop.IOLoop.instance()
    tornado_loop.add_callback(master.start)
    tornado.ioloop.PeriodicCallback(lambda: master.tick(timeout=0), 5).start()

    try:
        print("Starting proxy server")
        tornado_loop.start()
    except (KeyboardInterrupt, RuntimeError):
        pass
Example #16
0
def tornado_main(args):
    from tornado.platform.asyncio import AsyncIOMainLoop
    AsyncIOMainLoop().install()

    loop = tornado.ioloop.IOLoop.instance()
    loop.add_callback(lambda: run())
    loop.start()
Example #17
0
    def __init__(self, protocol, port, **kwargs):

        self._initialize(**kwargs)

        if not issubclass(protocol, Protocol):
            raise TypeError(r'Dot Implemented Protocol Interface')

        self._settings = {
            r'ssl_options': kwargs.get(r'ssl_options', None),
            r'max_buffer_size': kwargs.get(r'max_buffer_size', None),
            r'read_chunk_size': kwargs.get(r'read_chunk_size', None),
        }

        self._sockets = bind_sockets(port)

        if self._process_num > 1:
            self._process_id = fork_processes(self._process_num)

        AsyncIOMainLoop().install()

        self._event_loop = asyncio.get_event_loop()

        self._server = _TCPServer(protocol, **self._settings)

        signal.signal(signal.SIGINT, self.stop)
        signal.signal(signal.SIGTERM, self.stop)

        if self._async_initialize:
            self._event_loop.run_until_complete(self._async_initialize())
Example #18
0
    def activate(self):
        WebHandler.web_manager = self
        WebHandler.factory = self.factory
        WebHandler.player_manager = self.plugins.player_manager

        AsyncIOMainLoop().install()
        application.listen(8888)
Example #19
0
 def shutdown():
     """Force server and ioloop shutdown."""
     logging.info('Shutting down server')
     app.stop()
     AsyncIOMainLoop().stop()
     server.stop()
     _ioloop.stop()
Example #20
0
File: bot.py Project: quvide/helbot
    def connect_to_mongo(self):
        mongo_config = self.config.get('mongo', {})
        database = mongo_config.get('database', 'helbot')

        AsyncIOMainLoop().install()
        io_loop = tornado.ioloop.IOLoop.instance()
        me.connection.connect(database, io_loop=io_loop)
Example #21
0
def main():
    tornado.options.parse_command_line()
    AsyncIOMainLoop().install()
    loop = asyncio.get_event_loop()
    app = Application()
    app.listen(options.port)
    loop.run_forever()
Example #22
0
def main():
    AsyncIOMainLoop().install()
    loop = asyncio.get_event_loop()

    async_twitch = AsyncTwitchWrapper(
        loop,
        Twitch(
            config['RING_BUFFER_SIZE'] * 1024 * 1024,
            config['STREAM_RESOLUTION'],
            config['TWITCH_OAUTH'],
            config['TWITCH_CHANNEL']
        )
    )
    async_twitch.initialize()

    asyncio.Task(pereodic_stream_updates(async_twitch, 10))

    uploader = AsyncUploaderWrapper(
        loop,
        uploader=resolve_uploader()
    )

    app = application(async_twitch, uploader)
    app.listen(config['PORT'])

    print('Listening port {port}...'.format(port=config['PORT']))
    loop.run_forever()
Example #23
0
def main():
    enable_pretty_logging()
    AsyncIOMainLoop().install()
    app = make_app()
    server = tornado.httpserver.HTTPServer(app)
    server.bind(1234, '127.0.0.1')
    server.start()
    asyncio.get_event_loop().run_forever()
Example #24
0
 def __init__(self):
     self.db = DatabaseClient()
     self.connections = {}
     self.callback = PeriodicCallback(self.execute_withdraws, WITHDRAW_DELAY)
     self.callback.start()
     AsyncIOMainLoop().install()
     ioloop = IOLoop.current()
     ioloop.start()
Example #25
0
 def get_new_ioloop(self):
     try:
         import asyncio
         from tornado.platform.asyncio import AsyncIOMainLoop
         AsyncIOMainLoop().install()
         return IOLoop.current()
     except:
         return IOLoop.current()
Example #26
0
def run_app(args):
    from tornado.platform.asyncio import AsyncIOMainLoop
    AsyncIOMainLoop().install()
    signal.signal(signal.SIGINT, sig_exit)
    app = make_app(args)
    app.listen(8888)
    logging.info("Federator is now ready for requests")
    tornado.ioloop.IOLoop.current().start()
Example #27
0
    def __init__(self, main_loop, notrealy=False):
        super().__init__(loop=main_loop)
        ioloop = AsyncIOMainLoop()
        ioloop.asyncio_loop = main_loop
        ioloop.install()
        self.notrealy = notrealy
        self.tornado_loop = ioloop
        self.config = config.Config()
        self.admins = self.config.get('discord.admins', [])
        self._next_restart = 0
        self.disconnect = False
        self.tasks = []
        self.http_client = http.init(self)
        if not self.http_client:
            raise EnvironmentError('Can not start without http lib.')
        self.scheduler = scheduler.Scheduler(self)
        self.sqlcon = sql.init(self)
        self.modules = BotModules(self)
        token = self.config.get('discord.token', None)
        self.user_token = None
        if token:
            self.user_token = token
        else:
            self.user_login = self.config.get('discord.login')
            self.user_password = self.config.get('discord.password')
        self.unflip = self.config.get('discord.unflip', False)
        self.ifnfo_line = ifnfo_line % self.config.get('version')

        @self.event
        async def on_message(message):
            logger.debug('New message %s', message)
            await self.msg_proc(message)

        @self.event
        async def on_message_edit(old_message, message):
            logger.debug('Message edited ftom %s to %s', old_message, message)
            await self.msg_proc(message)

        @self.event
        async def on_ready():
            logger.debug('Logged in as %s (%s)', self.user.name, self.user.id)
            waiters = []
            for upd in self.modules.updates:
                waiters.append(upd.ready(self))
            for one_wait in waiters:
                await one_wait
Example #28
0
 def run(self):  # pragma: no cover
     AsyncIOMainLoop().install()
     iol = tornado.ioloop.IOLoop.instance()
     http_server = tornado.httpserver.HTTPServer(self.app)
     http_server.listen(self.options.web_port, self.options.web_host)
     web_url = f"http://{self.options.web_host}:{self.options.web_port}/"
     self.log.info(f"Web server listening at {web_url}", )
     self.run_loop(iol.start)
def run_proc(port):
    AsyncIOMainLoop().install()
    app = tornado.web.Application([
        (r"/cf/(?P<protocol>[^\/]+)/?(?P<proxy>[^\/]+)", CfHandler),
    ])
    app.listen(port)
    logging.info(f'DestroyerIgnaleoAP@localhost:{port}')
    worker_loop.run_forever()
Example #30
0
def run_proc(port):
    AsyncIOMainLoop().install()
    app = tornado.web.Application([
        (r'/', MainHandler),
    ])
    app.listen(port)
    print('DestroyerIgnaleoG@localhost:%d' % (port))
    worker_loop.run_forever()
Example #31
0
def install_asyncio() -> None:
    """Install tornado's loop to asyncio."""
    try:
        from tornado.ioloop import IOLoop
        from tornado.platform.asyncio import AsyncIOMainLoop
        if not IOLoop.initialized():
            AsyncIOMainLoop().install()
    except ImportError:
        pass
Example #32
0
 def run(self):  # pragma: no cover
     AsyncIOMainLoop().install()
     iol = tornado.ioloop.IOLoop.instance()
     http_server = tornado.httpserver.HTTPServer(self.app)
     http_server.listen(self.options.web_port, self.options.web_iface)
     web_url = "http://{}:{}/".format(self.options.web_iface,
                                      self.options.web_port)
     self.log.info("Web server listening at {}".format(web_url), )
     self.run_loop(iol.start)
Example #33
0
def main():
    application = make_app(debug=options.debug)

    with open(options.logging_config, 'r') as conf:
        conf_dictionary = json.load(conf)
        logging.config.dictConfig(conf_dictionary)

    if options.prometheus_port:
        start_http_server(options.prometheus_port)

    if options.debug:
        application.listen(address=options.address, port=options.port)
    else:
        server = tornado.httpserver.HTTPServer(application,
                                               xheaders=True,
                                               max_body_size=options.max_body_size)
        server.bind(options.port)
        server.start()
    logger.info('Using asyncio')
    from tornado.platform.asyncio import AsyncIOMainLoop
    AsyncIOMainLoop.current().start()
Example #34
0
def main():
    application = make_app(debug=options.debug)

    with open(options.logging_config, 'r') as conf:
        conf_dictionary = json.load(conf)
        logging.config.dictConfig(conf_dictionary)

    if options.prometheus_port:
        start_http_server(options.prometheus_port)

    if options.debug:
        application.listen(options.port)
    else:
        server = tornado.httpserver.HTTPServer(application)
        server.bind(options.port)
        server.start()
    if options.asyncio:
        logger.info('Using asyncio')
        from tornado.platform.asyncio import AsyncIOMainLoop
        AsyncIOMainLoop.current().start()
    else:
        logger.info('Using IOLoop')
        from tornado.ioloop import IOLoop
        IOLoop.current().start()
Example #35
0
    def _open(self, host, port, **kwargs):
        # Note: does not get called if host is False. That way we can
        # run Flexx in e.g. JLab's application.

        # Hook Tornado up with asyncio. Flexx' BaseServer makes sure
        # that the correct asyncio event loop is current (for this thread).
        # http://www.tornadoweb.org/en/stable/asyncio.html
        # todo: Since Tornado v5.0 asyncio is autom used, deprecating AsyncIOMainLoop
        self._io_loop = AsyncIOMainLoop()
        # I am sorry for this hack, but Tornado wont work otherwise :(
        # I wonder how long it will take before this will bite me back. I guess
        # we will be alright as long as there is no other Tornado stuff going on.
        if hasattr(IOLoop, "_current"):
            IOLoop._current.instance = None
        else:
            IOLoop.current().instance = None
        self._io_loop.make_current()

        # handle ssl, wether from configuration or given args
        if config.ssl_certfile:
            if 'ssl_options' not in kwargs:
                kwargs['ssl_options'] = {}
            if 'certfile' not in kwargs['ssl_options']:
                kwargs['ssl_options']['certfile'] = config.ssl_certfile

        if config.ssl_keyfile:
            if 'ssl_options' not in kwargs:
                kwargs['ssl_options'] = {}
            if 'keyfile' not in kwargs['ssl_options']:
                kwargs['ssl_options']['keyfile'] = config.ssl_keyfile

        if config.tornado_debug:
            app_kwargs = dict(debug=True)
        else:
            app_kwargs = dict()
        # Create tornado application
        self._app = Application([(r"/flexx/ws/(.*)", WSHandler),
                                 (r"/flexx/(.*)", MainHandler),
                                 (r"/(.*)", AppHandler), ], **app_kwargs)
        self._app._io_loop = self._io_loop
        # Create tornado server, bound to our own ioloop
        if tornado.version_info < (5, ):
            kwargs['io_loop'] = self._io_loop
        self._server = HTTPServer(self._app, **kwargs)

        # Start server (find free port number if port not given)
        if port:
            # Turn port into int, use hashed port number if a string was given
            try:
                port = int(port)
            except ValueError:
                port = port_hash(port)
            self._server.listen(port, host)
        else:
            # Try N ports in a repeatable range (easier, browser history, etc.)
            prefered_port = port_hash('Flexx')
            for i in range(8):
                port = prefered_port + i
                try:
                    self._server.listen(port, host)
                    break
                except (OSError, IOError):
                    pass  # address already in use
            else:
                # Ok, let Tornado figure out a port
                [sock] = netutil.bind_sockets(None, host, family=socket.AF_INET)
                self._server.add_sockets([sock])
                port = sock.getsockname()[1]

        # Notify address, so its easy to e.g. copy and paste in the browser
        self._serving = self._app._flexx_serving = host, port
        proto = 'http'
        if 'ssl_options' in kwargs:
            proto = 'https'
        # This string 'Serving apps at' is our 'ready' signal and is tested for.
        logger.info('Serving apps at %s://%s:%i/' % (proto, host, port))
Example #36
0
def sigint_handler(sig, frame):
    asyncio_loop = AsyncIOMainLoop.current()
    asyncio_loop.add_callback_from_signal(asyncio_loop.stop)
    io_loop = IOLoop.current()
    io_loop.add_callback_from_signal(io_loop.stop)
Example #37
0
def _get_event_loop():
    from tornado.platform.asyncio import AsyncIOMainLoop
    loop = AsyncIOMainLoop()
    loop.install()
    return loop