예제 #1
0
    def __init__(self, session):
        '''Expects a ftrack_api.Session instance'''
        self.log = Logger().get_logger(self.__class__.__name__)
        if not (isinstance(session, ftrack_api.session.Session)
                or isinstance(session, ftrack_server.lib.SocketSession)):
            raise Exception(
                ("Session object entered with args is instance of \"{}\""
                 " but expected instances are \"{}\" and \"{}\"").format(
                     str(type(session)), str(ftrack_api.session.Session),
                     str(ftrack_server.lib.SocketSession)))

        self._session = session

        # Using decorator
        self.register = self.register_decorator(self.register)
        self.launch = self.launch_log(self.launch)
예제 #2
0
    def __init__(self, name, port, filepath, additional_args=[]):
        super(SocketThread, self).__init__()
        self.log = Logger().get_logger(self.__class__.__name__)
        self.setName(name)
        self.name = name
        self.port = port
        self.filepath = filepath
        self.additional_args = additional_args

        self.sock = None
        self.subproc = None
        self.connection = None
        self._is_running = False
        self.finished = False

        self.mongo_error = False

        self._temp_data = {}
예제 #3
0
파일: pype_tray.py 프로젝트: 3dzayn/pype
    def __init__(self, tray_widget, main_window):
        self.tray_widget = tray_widget
        self.main_window = main_window

        self.pype_info_widget = None

        self.log = Logger.get_logger(self.__class__.__name__)

        self.module_settings = get_system_settings()["modules"]

        self.modules_manager = TrayModulesManager()

        self.errors = []
예제 #4
0
    def publish(paths):
        """Start headless publishing.

        Publish use json from passed paths argument.

        Args:
            paths (list): Paths to jsons.

        Raises:
            RuntimeError: When there is no pathto process.
        """
        if not any(paths):
            raise RuntimeError("No publish paths specified")

        from openpype import install, uninstall
        from openpype.api import Logger

        # Register target and host
        import pyblish.api
        import pyblish.util

        env = get_app_environments_for_context(os.environ["AVALON_PROJECT"],
                                               os.environ["AVALON_ASSET"],
                                               os.environ["AVALON_TASK"],
                                               os.environ["AVALON_APP_NAME"])
        os.environ.update(env)

        log = Logger.get_logger()

        install()

        pyblish.api.register_target("filesequence")
        pyblish.api.register_host("shell")

        os.environ["OPENPYPE_PUBLISH_DATA"] = os.pathsep.join(paths)

        log.info("Running publish ...")

        # Error exit as soon as any error occurs.
        error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}"

        for result in pyblish.util.publish_iter():
            if result["error"]:
                log.error(error_format.format(**result))
                uninstall()
                sys.exit(1)

        log.info("Publish finished.")
        uninstall()
예제 #5
0
import os
import json
import tempfile
import random
import string

from Qt import QtWidgets, QtCore
from . import DropDataFrame
from .constants import HOST_NAME
from avalon import io
from openpype.api import execute, Logger
from openpype.lib import (get_pype_execute_args,
                          apply_project_environments_value)

log = Logger().get_logger("standalonepublisher")


class ComponentsWidget(QtWidgets.QWidget):
    def __init__(self, parent):
        super().__init__()
        self.initialized = False
        self.valid_components = False
        self.valid_family = False
        self.valid_repre_names = False

        body = QtWidgets.QWidget()
        self.parent_widget = parent
        self.drop_frame = DropDataFrame(self)

        buttons = QtWidgets.QWidget()
예제 #6
0
파일: utils.py 프로젝트: 3dzayn/pype
import time
from openpype.api import Logger
log = Logger().get_logger("SyncServer")


def time_function(method):
    """ Decorator to print how much time function took.
        For debugging.
        Depends on presence of 'log' object
    """
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        if 'log_time' in kw:
            name = kw.get('log_name', method.__name__.upper())
            kw['log_time'][name] = int((te - ts) * 1000)
        else:
            log.debug('%r  %2.2f ms' % (method.__name__, (te - ts) * 1000))
            print('%r  %2.2f ms' % (method.__name__, (te - ts) * 1000))
        return result

    return timed
예제 #7
0
import sys
import signal
import socket

from openpype.modules.ftrack.ftrack_server.ftrack_server import FtrackServer
from openpype.modules.ftrack.ftrack_server.lib import (SocketSession,
                                                       SocketBaseEventHub)
from openpype.modules import ModulesManager

from openpype.api import Logger

log = Logger().get_logger("FtrackUserServer")


def main(args):
    port = int(args[-1])

    # Create a TCP/IP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Connect the socket to the port where the server is listening
    server_address = ("localhost", port)
    log.debug(
        "User Ftrack Server connected to {} port {}".format(*server_address))
    sock.connect(server_address)
    sock.sendall(b"CreatedUser")

    try:
        session = SocketSession(auto_connect_event_hub=True,
                                sock=sock,
                                Eventhub=SocketBaseEventHub)
예제 #8
0
from aiohttp.web_response import Response
from openpype.api import Logger

log = Logger().get_logger("Event processor")


class TimersManagerModuleRestApi:
    """
        REST API endpoint used for calling from hosts when context change
        happens in Workfile app.
    """
    def __init__(self, user_module, server_manager):
        self.module = user_module
        self.server_manager = server_manager

        self.prefix = "/timers_manager"

        self.register()

    def register(self):
        self.server_manager.add_route("POST", self.prefix + "/start_timer",
                                      self.start_timer)

    async def start_timer(self, request):
        data = await request.json()
        try:
            project_name = data['project_name']
            asset_name = data['asset_name']
            task_name = data['task_name']
            hierarchy = data['hierarchy']
        except KeyError:
예제 #9
0
 def log(self):
     if self._log is None:
         self._log = Logger().get_logger(self.__class__.__name__)
     return self._log
예제 #10
0
import sys
import datetime
import signal
import socket
import pymongo

import ftrack_api
from openpype.modules.ftrack.ftrack_server.ftrack_server import FtrackServer
from openpype.modules.ftrack.ftrack_server.lib import (
    SocketSession, StorerEventHub, TOPIC_STATUS_SERVER,
    TOPIC_STATUS_SERVER_RESULT)
from openpype.modules.ftrack.lib import get_ftrack_event_mongo_info
from openpype.lib import OpenPypeMongoConnection
from openpype.api import Logger

log = Logger.get_logger("Event storer")
subprocess_started = datetime.datetime.now()


class SessionFactory:
    session = None


database_name, collection_name = get_ftrack_event_mongo_info()
dbcon = None

# ignore_topics = ["ftrack.meta.connected"]
ignore_topics = []


def install_db():
예제 #11
0
#!/usr/bin/env python
import time
from openpype.hosts.resolve.utils import get_resolve_module
from openpype.api import Logger

log = Logger().get_logger(__name__)

wait_delay = 2.5
wait = 0.00
ready = None
while True:
    try:
        # Create project and set parameters:
        resolve = get_resolve_module()
        pm = resolve.GetProjectManager()
        if pm:
            ready = None
        else:
            ready = True
    except AttributeError:
        pass

    if ready is None:
        time.sleep(wait_delay)
        log.info(f"Waiting {wait}s for Resolve to have opened Project Manager")
        wait += wait_delay
    else:
        print(f"Preloaded variables: \n\n\tResolve module: "
              f"`resolve` > {type(resolve)} \n\tProject manager: "
              f"`pm` > {type(pm)}")
        break
예제 #12
0
class SocketThread(threading.Thread):
    """Thread that checks suprocess of storer of processor of events"""

    MAX_TIMEOUT = int(os.environ.get("OPENPYPE_FTRACK_SOCKET_TIMEOUT", 45))

    def __init__(self, name, port, filepath, additional_args=[]):
        super(SocketThread, self).__init__()
        self.log = Logger().get_logger(self.__class__.__name__)
        self.setName(name)
        self.name = name
        self.port = port
        self.filepath = filepath
        self.additional_args = additional_args

        self.sock = None
        self.subproc = None
        self.connection = None
        self._is_running = False
        self.finished = False

        self.mongo_error = False

        self._temp_data = {}

    def stop(self):
        self._is_running = False

    def run(self):
        self._is_running = True
        time_socket = time.time()
        # Create a TCP/IP socket
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock = sock

        # Bind the socket to the port - skip already used ports
        while True:
            try:
                server_address = ("localhost", self.port)
                sock.bind(server_address)
                break
            except OSError:
                self.port += 1

        self.log.debug(
            "Running Socked thread on {}:{}".format(*server_address))

        env = os.environ.copy()
        env["OPENPYPE_PROCESS_MONGO_ID"] = str(Logger.mongo_process_id)
        # OpenPype executable (with path to start script if not build)
        args = get_pype_execute_args(
            # Add `run` command
            "run",
            self.filepath,
            *self.additional_args,
            str(self.port))
        self.subproc = subprocess.Popen(args, env=env, stdin=subprocess.PIPE)

        # Listen for incoming connections
        sock.listen(1)
        sock.settimeout(1.0)
        while True:
            if not self._is_running:
                break
            try:
                connection, client_address = sock.accept()
                time_socket = time.time()
                connection.settimeout(1.0)
                self.connection = connection

            except socket.timeout:
                if (time.time() - time_socket) > self.MAX_TIMEOUT:
                    self.log.error("Connection timeout passed. Terminating.")
                    self._is_running = False
                    self.subproc.terminate()
                    break
                continue

            try:
                time_con = time.time()
                # Receive the data in small chunks and retransmit it
                while True:
                    try:
                        if not self._is_running:
                            break
                        data = None
                        try:
                            data = self.get_data_from_con(connection)
                            time_con = time.time()

                        except socket.timeout:
                            if (time.time() - time_con) > self.MAX_TIMEOUT:
                                self.log.error(
                                    "Connection timeout passed. Terminating.")
                                self._is_running = False
                                self.subproc.terminate()
                                break
                            continue

                        except ConnectionResetError:
                            self._is_running = False
                            break

                        self._handle_data(connection, data)

                    except Exception as exc:
                        self.log.error("Event server process failed",
                                       exc_info=True)

            finally:
                # Clean up the connection
                connection.close()
                if self.subproc.poll() is None:
                    self.subproc.terminate()

                self.finished = True

    def get_data_from_con(self, connection):
        return connection.recv(16)

    def _handle_data(self, connection, data):
        if not data:
            return

        if data == b"MongoError":
            self.mongo_error = True
        connection.sendall(data)
예제 #13
0
파일: menu.py 프로젝트: 3dzayn/pype
from openpype.hosts.nuke.api.lib import (on_script_load,
                                         check_inventory_versions)

import nuke
from openpype.api import Logger

log = Logger().get_logger(__name__)

nuke.addOnScriptSave(on_script_load)
nuke.addOnScriptLoad(check_inventory_versions)
nuke.addOnScriptSave(check_inventory_versions)

log.info('Automatic syncing of write file knob to script version')
예제 #14
0
class ProcessEventHub(SocketBaseEventHub):
    hearbeat_msg = b"processor"

    is_collection_created = False
    pypelog = Logger().get_logger("Session Processor")

    def __init__(self, *args, **kwargs):
        self.mongo_url = None
        self.dbcon = None

        super(ProcessEventHub, self).__init__(*args, **kwargs)

    def prepare_dbcon(self):
        try:
            database_name, collection_name = get_ftrack_event_mongo_info()
            mongo_client = OpenPypeMongoConnection.get_mongo_client()
            self.dbcon = mongo_client[database_name][collection_name]
            self.mongo_client = mongo_client

        except pymongo.errors.AutoReconnect:
            self.pypelog.error((
                "Mongo server \"{}\" is not responding, exiting."
            ).format(OpenPypeMongoConnection.get_default_mongo_url()))
            sys.exit(0)

        except pymongo.errors.OperationFailure:
            self.pypelog.error((
                "Error with Mongo access, probably permissions."
                "Check if exist database with name \"{}\""
                " and collection \"{}\" inside."
            ).format(self.database, self.collection_name))
            self.sock.sendall(b"MongoError")
            sys.exit(0)

    def wait(self, duration=None):
        """Overriden wait
        Event are loaded from Mongo DB when queue is empty. Handled event is
        set as processed in Mongo DB.
        """
        started = time.time()
        self.prepare_dbcon()
        while True:
            try:
                event = self._event_queue.get(timeout=0.1)
            except queue.Empty:
                if not self.load_events():
                    time.sleep(0.5)
            else:
                try:
                    self._handle(event)

                    mongo_id = event["data"].get("_event_mongo_id")
                    if mongo_id is None:
                        continue

                    self.dbcon.update_one(
                        {"_id": mongo_id},
                        {"$set": {"pype_data.is_processed": True}}
                    )

                except pymongo.errors.AutoReconnect:
                    self.pypelog.error((
                        "Mongo server \"{}\" is not responding, exiting."
                    ).format(os.environ["AVALON_MONGO"]))
                    sys.exit(0)
                # Additional special processing of events.
                if event['topic'] == 'ftrack.meta.disconnected':
                    break

            if duration is not None:
                if (time.time() - started) > duration:
                    break

    def load_events(self):
        """Load not processed events sorted by stored date"""
        ago_date = datetime.datetime.now() - datetime.timedelta(days=3)
        self.dbcon.delete_many({
            "pype_data.stored": {"$lte": ago_date},
            "pype_data.is_processed": True
        })

        not_processed_events = self.dbcon.find(
            {"pype_data.is_processed": False}
        ).sort(
            [("pype_data.stored", pymongo.ASCENDING)]
        )

        found = False
        for event_data in not_processed_events:
            new_event_data = {
                k: v for k, v in event_data.items()
                if k not in ["_id", "pype_data"]
            }
            try:
                event = ftrack_api.event.base.Event(**new_event_data)
                event["data"]["_event_mongo_id"] = event_data["_id"]
            except Exception:
                self.logger.exception(L(
                    'Failed to convert payload into event: {0}',
                    event_data
                ))
                continue
            found = True
            self._event_queue.put(event)

        return found

    def _handle_packet(self, code, packet_identifier, path, data):
        """Override `_handle_packet` which skip events and extend heartbeat"""
        code_name = self._code_name_mapping[code]
        if code_name == "event":
            return

        return super()._handle_packet(code, packet_identifier, path, data)
예제 #15
0
파일: ftrack_tray.py 프로젝트: 3dzayn/pype
import os
import time
import datetime
import threading
from Qt import QtCore, QtWidgets, QtGui

import ftrack_api
from ..ftrack_server.lib import check_ftrack_url
from ..ftrack_server import socket_thread
from ..lib import credentials
from ..ftrack_module import FTRACK_MODULE_DIR
from . import login_dialog

from openpype.api import Logger, resources

log = Logger().get_logger("FtrackModule")


class FtrackTrayWrapper:
    def __init__(self, module):
        self.module = module

        self.thread_action_server = None
        self.thread_socket_server = None
        self.thread_timer = None

        self.bool_logged = False
        self.bool_action_server_running = False
        self.bool_action_thread_running = False
        self.bool_timer_event = False
예제 #16
0
import os
import sys
import avalon.api as avalon
import openpype

from openpype.api import Logger

log = Logger().get_logger(__name__)


def main(env):
    import openpype.hosts.resolve as bmdvr
    # Registers openpype's Global pyblish plugins
    openpype.install()

    # activate resolve from openpype
    avalon.install(bmdvr)

    log.info(f"Avalon registred hosts: {avalon.registered_host()}")

    bmdvr.launch_pype_menu()


if __name__ == "__main__":
    result = main(os.environ)
    sys.exit(not bool(result))
예제 #17
0
class BaseHandler(object):
    '''Custom Action base class

    <label> - a descriptive string identifing your action.
    <varaint>   - To group actions together, give them the same
                  label and specify a unique variant per action.
    <identifier>  - a unique identifier for app.
    <description>   - a verbose descriptive text for you action
    <icon>  - icon in ftrack
    '''
    # Default priority is 100
    priority = 100
    # Type is just for logging purpose (e.g.: Action, Event, Application,...)
    type = 'No-type'
    ignore_me = False
    preactions = []

    @staticmethod
    def join_query_keys(keys):
        """Helper to join keys to query."""
        return ",".join(["\"{}\"".format(key) for key in keys])

    def __init__(self, session):
        '''Expects a ftrack_api.Session instance'''
        self.log = Logger().get_logger(self.__class__.__name__)
        if not (isinstance(session, ftrack_api.session.Session)
                or isinstance(session, ftrack_server.lib.SocketSession)):
            raise Exception(
                ("Session object entered with args is instance of \"{}\""
                 " but expected instances are \"{}\" and \"{}\"").format(
                     str(type(session)), str(ftrack_api.session.Session),
                     str(ftrack_server.lib.SocketSession)))

        self._session = session

        # Using decorator
        self.register = self.register_decorator(self.register)
        self.launch = self.launch_log(self.launch)

    # Decorator
    def register_decorator(self, func):
        @functools.wraps(func)
        def wrapper_register(*args, **kwargs):
            if self.ignore_me:
                return

            label = getattr(self, "label", self.__class__.__name__)
            variant = getattr(self, "variant", None)
            if variant:
                label = "{} {}".format(label, variant)

            try:
                self._preregister()

                start_time = time.perf_counter()
                func(*args, **kwargs)
                end_time = time.perf_counter()
                run_time = end_time - start_time
                self.log.info(
                    ('{} "{}" - Registered successfully ({:.4f}sec)').format(
                        self.type, label, run_time))
            except MissingPermision as MPE:
                self.log.info(
                    ('!{} "{}" - You\'re missing required {} permissions'
                     ).format(self.type, label, str(MPE)))
            except AssertionError as ae:
                self.log.warning(
                    ('!{} "{}" - {}').format(self.type, label, str(ae)))
            except NotImplementedError:
                self.log.error(
                    ('{} "{}" - Register method is not implemented').format(
                        self.type, label))
            except PreregisterException as exc:
                self.log.warning(
                    ('{} "{}" - {}').format(self.type, label, str(exc)))
            except Exception as e:
                self.log.error('{} "{}" - Registration failed ({})'.format(
                    self.type, label, str(e)))

        return wrapper_register

    # Decorator
    def launch_log(self, func):
        @functools.wraps(func)
        def wrapper_launch(*args, **kwargs):
            label = getattr(self, "label", self.__class__.__name__)
            variant = getattr(self, "variant", None)
            if variant:
                label = "{} {}".format(label, variant)

            self.log.info(('{} "{}": Launched').format(self.type, label))
            try:
                return func(*args, **kwargs)
            except Exception as exc:
                self.session.rollback()
                msg = '{} "{}": Failed ({})'.format(self.type, label, str(exc))
                self.log.error(msg, exc_info=True)
                return {'success': False, 'message': msg}
            finally:
                self.log.info(('{} "{}": Finished').format(self.type, label))

        return wrapper_launch

    @property
    def session(self):
        '''Return current session.'''
        return self._session

    def reset_session(self):
        self.session.reset()

    def _preregister(self):
        # Custom validations
        result = self.preregister()
        if result is None:
            self.log.debug(
                ("\"{}\" 'preregister' method returned 'None'. Expected it"
                 " didn't fail and continue as preregister returned True."
                 ).format(self.__class__.__name__))
            return

        if result is not True:
            msg = None
            if isinstance(result, str):
                msg = result
            raise PreregisterException(msg)

    def preregister(self):
        '''
        Preregister conditions.
        Registration continues if returns True.
        '''
        return True

    def register(self):
        '''
        Registers the action, subscribing the discover and launch topics.
        Is decorated by register_log
        '''

        raise NotImplementedError()

    def _translate_event(self, event, session=None):
        '''Return *event* translated structure to be used with the API.'''
        if session is None:
            session = self.session

        _entities = event['data'].get('entities_object', None)
        if (_entities is None or _entities[0].get('link', None)
                == ftrack_api.symbol.NOT_SET):
            _entities = self._get_entities(event)
            event['data']['entities_object'] = _entities

        return _entities

    def _get_entities(self, event, session=None, ignore=None):
        entities = []
        selection = event['data'].get('selection')
        if not selection:
            return entities

        if ignore is None:
            ignore = []
        elif isinstance(ignore, str):
            ignore = [ignore]

        filtered_selection = []
        for entity in selection:
            if entity['entityType'] not in ignore:
                filtered_selection.append(entity)

        if not filtered_selection:
            return entities

        if session is None:
            session = self.session
            session._local_cache.clear()

        for entity in filtered_selection:
            entities.append(
                session.get(self._get_entity_type(entity, session),
                            entity.get('entityId')))

        return entities

    def _get_entity_type(self, entity, session=None):
        '''Return translated entity type tht can be used with API.'''
        # Get entity type and make sure it is lower cased. Most places except
        # the component tab in the Sidebar will use lower case notation.
        entity_type = entity.get('entityType').replace('_', '').lower()

        if session is None:
            session = self.session

        for schema in self.session.schemas:
            alias_for = schema.get('alias_for')

            if (alias_for and isinstance(alias_for, str)
                    and alias_for.lower() == entity_type):
                return schema['id']

        for schema in self.session.schemas:
            if schema['id'].lower() == entity_type:
                return schema['id']

        raise ValueError(
            'Unable to translate entity type: {0}.'.format(entity_type))

    def _launch(self, event):
        self.session.rollback()
        self.session._local_cache.clear()

        self.launch(self.session, event)

    def launch(self, session, event):
        '''Callback method for the custom action.

        return either a bool ( True if successful or False if the action failed )
        or a dictionary with they keys `message` and `success`, the message should be a
        string and will be displayed as feedback to the user, success should be a bool,
        True if successful or False if the action failed.

        *session* is a `ftrack_api.Session` instance

        *entities* is a list of tuples each containing the entity type and the entity id.
        If the entity is a hierarchical you will always get the entity
        type TypedContext, once retrieved through a get operation you
        will have the "real" entity type ie. example Shot, Sequence
        or Asset Build.

        *event* the unmodified original event

        '''
        raise NotImplementedError()

    def _handle_preactions(self, session, event):
        # If preactions are not set
        if len(self.preactions) == 0:
            return True
        # If no selection
        selection = event.get('data', {}).get('selection', None)
        if (selection is None):
            return False
        # If preactions were already started
        if event['data'].get('preactions_launched', None) is True:
            return True

        # Launch preactions
        for preaction in self.preactions:
            self.trigger_action(preaction, event)

        # Relaunch this action
        additional_data = {"preactions_launched": True}
        self.trigger_action(self.identifier,
                            event,
                            additional_event_data=additional_data)

        return False

    def _handle_result(self, result):
        '''Validate the returned result from the action callback'''
        if isinstance(result, bool):
            if result is True:
                result = {
                    'success': result,
                    'message':
                    ('{0} launched successfully.'.format(self.label))
                }
            else:
                result = {
                    'success': result,
                    'message': ('{0} launch failed.'.format(self.label))
                }

        elif isinstance(result, dict):
            items = 'items' in result
            if items is False:
                for key in ('success', 'message'):
                    if key in result:
                        continue

                    raise KeyError('Missing required key: {0}.'.format(key))

        return result

    def show_message(self, event, input_message, result=False):
        """
        Shows message to user who triggered event
        - event - just source of user id
        - input_message - message that is shown to user
        - result - changes color of message (based on ftrack settings)
            - True = Violet
            - False = Red
        """
        if not isinstance(result, bool):
            result = False

        try:
            message = str(input_message)
        except Exception:
            return

        user_id = event['source']['user']['id']
        target = ('applicationId=ftrack.client.web and user.id="{0}"'
                  ).format(user_id)
        self.session.event_hub.publish(ftrack_api.event.base.Event(
            topic='ftrack.action.trigger-user-interface',
            data=dict(type='message', success=result, message=message),
            target=target),
                                       on_error='ignore')

    def show_interface(self,
                       items,
                       title='',
                       event=None,
                       user=None,
                       username=None,
                       user_id=None):
        """
        Shows interface to user
        - to identify user must be entered one of args:
            event, user, username, user_id
        - 'items' must be list containing Ftrack interface items
        """
        if not any([event, user, username, user_id]):
            raise TypeError(
                ('Missing argument `show_interface` requires one of args:'
                 ' event (ftrack_api Event object),'
                 ' user (ftrack_api User object)'
                 ' username (string) or user_id (string)'))

        if event:
            user_id = event['source']['user']['id']
        elif user:
            user_id = user['id']
        else:
            if user_id:
                key = 'id'
                value = user_id
            else:
                key = 'username'
                value = username

            user = self.session.query('User where {} is "{}"'.format(
                key, value)).first()

            if not user:
                raise TypeError(
                    ('Ftrack user with {} "{}" was not found!').format(
                        key, value))

            user_id = user['id']

        target = ('applicationId=ftrack.client.web and user.id="{0}"'
                  ).format(user_id)

        self.session.event_hub.publish(ftrack_api.event.base.Event(
            topic='ftrack.action.trigger-user-interface',
            data=dict(type='widget', items=items, title=title),
            target=target),
                                       on_error='ignore')

    def show_interface_from_dict(self,
                                 messages,
                                 title="",
                                 event=None,
                                 user=None,
                                 username=None,
                                 user_id=None):
        if not messages:
            self.log.debug("No messages to show! (messages dict is empty)")
            return
        items = []
        splitter = {'type': 'label', 'value': '---'}
        first = True
        for key, value in messages.items():
            if not first:
                items.append(splitter)
            else:
                first = False

            subtitle = {'type': 'label', 'value': '<h3>{}</h3>'.format(key)}
            items.append(subtitle)
            if isinstance(value, list):
                for item in value:
                    message = {
                        'type': 'label',
                        'value': '<p>{}</p>'.format(item)
                    }
                    items.append(message)
            else:
                message = {'type': 'label', 'value': '<p>{}</p>'.format(value)}
                items.append(message)

        self.show_interface(items, title, event, user, username, user_id)

    def trigger_action(self,
                       action_name,
                       event=None,
                       session=None,
                       selection=None,
                       user_data=None,
                       topic="ftrack.action.launch",
                       additional_event_data={},
                       on_error="ignore"):
        self.log.debug("Triggering action \"{}\" Begins".format(action_name))

        if not session:
            session = self.session

        # Getting selection and user data
        _selection = None
        _user_data = None

        if event:
            _selection = event.get("data", {}).get("selection")
            _user_data = event.get("source", {}).get("user")

        if selection is not None:
            _selection = selection

        if user_data is not None:
            _user_data = user_data

        # Without selection and user data skip triggering
        msg = "Can't trigger \"{}\" action without {}."
        if _selection is None:
            self.log.error(msg.format(action_name, "selection"))
            return

        if _user_data is None:
            self.log.error(msg.format(action_name, "user data"))
            return

        _event_data = {
            "actionIdentifier": action_name,
            "selection": _selection
        }

        # Add additional data
        if additional_event_data:
            _event_data.update(additional_event_data)

        # Create and trigger event
        session.event_hub.publish(ftrack_api.event.base.Event(
            topic=topic, data=_event_data, source=dict(user=_user_data)),
                                  on_error=on_error)
        self.log.debug(
            "Action \"{}\" Triggered successfully".format(action_name))

    def trigger_event(self,
                      topic,
                      event_data={},
                      session=None,
                      source=None,
                      event=None,
                      on_error="ignore"):
        if session is None:
            session = self.session

        if not source and event:
            source = event.get("source")
        # Create and trigger event
        event = ftrack_api.event.base.Event(topic=topic,
                                            data=event_data,
                                            source=source)
        session.event_hub.publish(event, on_error=on_error)

        self.log.debug(("Publishing event: {}").format(str(event.__dict__)))

    def get_project_from_entity(self, entity, session=None):
        low_entity_type = entity.entity_type.lower()
        if low_entity_type == "project":
            return entity

        if "project" in entity:
            # reviewsession, task(Task, Shot, Sequence,...)
            return entity["project"]

        if low_entity_type == "filecomponent":
            entity = entity["version"]
            low_entity_type = entity.entity_type.lower()

        if low_entity_type == "assetversion":
            asset = entity["asset"]
            if asset:
                parent = asset["parent"]
                if parent:
                    return parent["project"]

        project_data = entity["link"][0]

        if session is None:
            session = self.session
        return session.query("Project where id is {}".format(
            project_data["id"])).one()

    def get_project_settings_from_event(self, event, project_name):
        """Load or fill OpenPype's project settings from event data.

        Project data are stored by ftrack id because in most cases it is
        easier to access project id than project name.

        Args:
            event (ftrack_api.Event): Processed event by session.
            project_entity (ftrack_api.Entity): Project entity.
        """
        project_settings_by_id = event["data"].get("project_settings")
        if not project_settings_by_id:
            project_settings_by_id = {}
            event["data"]["project_settings"] = project_settings_by_id

        project_settings = project_settings_by_id.get(project_name)
        if not project_settings:
            project_settings = get_project_settings(project_name)
            event["data"]["project_settings"][project_name] = project_settings
        return project_settings

    @staticmethod
    def get_entity_path(entity):
        """Return full hierarchical path to entity."""
        return "/".join([ent["name"] for ent in entity["link"]])
예제 #18
0
import sys
import time
import datetime
import signal
import threading

import ftrack_api
from openpype.api import Logger
from openpype.modules import ModulesManager
from openpype.modules.ftrack.ftrack_server.ftrack_server import FtrackServer

log = Logger().get_logger("Event Server Legacy")


class TimerChecker(threading.Thread):
    max_time_out = 35

    def __init__(self, server, session):
        self.server = server
        self.session = session
        self.is_running = False
        self.failed = False
        super().__init__()

    def stop(self):
        self.is_running = False

    def run(self):
        start = datetime.datetime.now()
        self.is_running = True
        connected = False