Beispiel #1
0
def main():
    print(VERSION)
    data_dir = None
    config = client_config.ClientConfig()
    if getattr(config, 'USE_CUSTOM_DIR', False):
        print("Using custom directory")
        if (sys.platform == 'darwin' and os.path.dirname(sys.executable
                                                         ).endswith('MacOS')):
            data_dir = os.path.join(get_mac_dot_app_dir(os.path.dirname(
                sys.executable)), '.update')
        else:
            data_dir = os.path.join(os.path.dirname(sys.executable), '.update')
    client = Client(config, refresh=True,
                    progress_hooks=[cb], data_dir=data_dir)
    update = client.update_check(APPNAME, VERSION)
    if update is not None:
        print("We have an update")
        retry_count = 0
        while retry_count < 5:
            success = update.download()
            if success is True:
                break
            print("Retry Download. Count {}".format(retry_count + 1))
            retry_count += 1

        if success:
            print('Update download successful')
            print('Restarting')
            update.extract_restart()
        else:
            print('Failed to download update')

    print("Leaving main()")
Beispiel #2
0
def main():
    print(VERSION)
    data_dir = None
    config = client_config.ClientConfig()
    if getattr(config, 'USE_CUSTOM_DIR', False):
        if (sys.platform == 'darwin' and os.path.dirname(sys.executable
                                                         ).endswith('MacOS')):
            data_dir = os.path.join(get_mac_dot_app_dir(os.path.dirname(
                sys.executable)), '.update')
        else:
            data_dir = os.path.join(os.path.dirname(os.path.dirname(
                sys.executable)), '.update')
    client = Client(config,
                    refresh=True, progress_hooks=[cb],
                    data_dir=data_dir)
    update = client.update_check(APPNAME, VERSION)
    if update is not None:
        success = update.download()
        print('')
        if success is True:
            print('Update download successful')
            print('Extracting & overwriting')
            update.extract_overwrite()
        else:
            print('Failed to download update')
    return VERSION
 def test_bad_pub_key(self):
     t_config = TConfig()
     # If changed ensure it's a valid key format
     t_config.PUBLIC_KEY = '25RSdhJ+xCsxxTjY5jffilatipp29tnKp/D5BelSMJM'
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     assert client.update_check(client.app_name, '0.0.0') is None
Beispiel #4
0
 def test_manifest_filesystem(self):
     t_config = TConfig()
     t_config.PUBLIC_KEYS = ['bad key']
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     filesystem_data = client._get_manifest_filesystem()
     filesystem_data = json.loads(filesystem_data)
     del filesystem_data['sigs']
     assert client.json_data == filesystem_data
Beispiel #5
0
 def test_http(self):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.app_name == 'Acme'
     assert update.download() is True
     assert update.is_downloaded() is True
Beispiel #6
0
 def test_http(client):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     t_config.VERIFY_SERVER_CERT = False
     client = Client(t_config, refresh=True, test=True)
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.app_name == 'jms'
     assert update.download() is True
     assert update.is_downloaded() is True
Beispiel #7
0
 def test_manifest_filesystem(self):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     filesystem_data = client._get_manifest_filesystem()
     assert filesystem_data is not None
     if six.PY3:
         filesystem_data = filesystem_data.decode()
     filesystem_data = json.loads(filesystem_data)
     del filesystem_data['signature']
     assert client.json_data == filesystem_data
    def test_callback(self):
        def cb(status):
            print(status)

        def cb2(status):
            raise IndexError

        t_config = TConfig()
        t_config.PUBLIC_KEY = '25RSdhJ+xCsxxTjY5jffilatipp29tnKp/D5BelSMJM'
        t_config.DATA_DIR = os.getcwd()
        client = Client(t_config, refresh=True, test=True, progress_hooks=[cb])
        client.add_progress_hook(cb2)
        assert client.update_check(client.app_name, '0.0.0') is None
Beispiel #9
0
    def test_callback(self):
        def cb(status):
            print(status)

        def cb2(status):
            raise IndexError

        t_config = TConfig()
        t_config.PUBLIC_KEYS = ['bad key']
        t_config.DATA_DIR = os.getcwd()
        client = Client(t_config, refresh=True, test=True, call_back=cb,
                        callbacks=[cb, cb2])
        client.add_call_back(cb2)
        assert client.update_check('jms', '0.0.0') is None
Beispiel #10
0
 def test_async_http(self):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.app_name == 'Acme'
     update.download(async=True)
     count = 0
     while count < 61:
         if update.is_downloaded() is True:
             break
         time.sleep(1)
         count += 1
     assert update.is_downloaded() is True
Beispiel #11
0
 def test_multipule_async_calls(self, client):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     t_config.VERIFY_SERVER_CERT = False
     client = Client(t_config, refresh=True, test=True)
     update = client.update_check(client.app_name, '0.0.1')
     assert update is not None
     assert update.app_name == 'Acme'
     update.download(async=True)
     count = 0
     assert update.download(async=True) is None
     assert update.download() is None
     while count < 61:
         if update.is_downloaded() is True:
             break
         time.sleep(1)
         count += 1
     assert update.is_downloaded() is True
Beispiel #12
0
def main():
    print(VERSION)
    data_dir = None
    config = client_config.ClientConfig()
    if getattr(config, "USE_CUSTOM_DIR", False):
        print("Using custom directory")
        if sys.platform == "darwin" and os.path.dirname(
                sys.executable).endswith("MacOS"):
            data_dir = os.path.join(
                get_mac_dot_app_dir(os.path.dirname(sys.executable)),
                ".update")
        else:
            data_dir = os.path.join(os.path.dirname(sys.executable), ".update")
    client = Client(config,
                    refresh=True,
                    progress_hooks=[cb],
                    data_dir=data_dir)
    update = client.update_check(APPNAME, VERSION)
    if update is not None:
        print("We have an update")
        retry_count = 0
        while retry_count < 5:
            success = update.download()
            if success is True:
                break
            print("Retry Download. Count {}".format(retry_count + 1))
            retry_count += 1

        if success:
            print("Update download successful")
            print("Restarting")
            update.extract_restart()
        else:
            print("Failed to download update")

    print("Leaving main()")
Beispiel #13
0
    def __init__(self,
                 mw=None,
                 test_version=None,
                 channel='stable',
                 dev_channel=False):

        client_config = ClientConfig()
        self.client = Client(client_config,
                             progress_hooks=[self.print_status_info])

        # set dev channel to alpha internally based on bool
        if dev_channel:
            channel = 'alpha'

        warnings.simplefilter(
            'ignore', DeprecationWarning)  # pyupdater turns this on, annoying

        _version = VERSION if test_version is None else test_version
        update_available = False
        app_update = None
        status = 'initialized'
        self.url_changelog = 'https://raw.githubusercontent.com/jaymegordo/SMSEventLog/main/CHANGELOG.md'

        f.set_self(vars())
Beispiel #14
0
def client():
    t_config = TConfig()
    t_config.DATA_DIR = os.getcwd()
    client = Client(t_config, refresh=True, test=True)
    client.FROZEN = True
    return client
Beispiel #15
0
 def test_url_str_attr(self):
     t_config = TConfig()
     t_config.DATA_DIR = os.getcwd()
     t_config.UPDATE_URLS = 'http://acme.com/update'
     client = Client(t_config, test=True)
     assert isinstance(client.update_urls, list)
Beispiel #16
0
 def test_failed_refresh(self, client):
     client = Client(None, refresh=True, test=True)
     client.data_dir = os.getcwd()
     assert client.ready is False
Beispiel #17
0
from pyupdater.client import Client
from client_config import ClientConfig

APP_NAME = 'Super App'
APP_VERSION = '1.1.0'

ASSET_NAME = 'ffmpeg'
ASSET_VERSION = '2.3.2'

def print_status_info(info):
    total = info.get(u'total')
    downloaded = info.get(u'downloaded')
    status = info.get(u'status')
    print(downloaded, total, status)
client = Client(ClientConfig())
client.refresh()

client.add_progress_hook(print_status_info)

Beispiel #18
0
        click.echo(Scenario(p.plan).asyaml())


def print_status_info(info):
    total = info.get(u'total')
    downloaded = info.get(u'downloaded')
    status = info.get(u'status')
    # print("#", downloaded, total, status)
    click.echo("#", downloaded, total, status)


if getattr(sys, 'frozen', False):
    sys.argv[0] = "kubectl-val"
    if "--debug-updater" in sys.argv:
        logging.getLogger("pyupdater").setLevel(logging.DEBUG)
        STDERR_HANDLER = logging.StreamHandler(sys.stderr)
        STDERR_HANDLER.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
        logging.getLogger("pyupdater").addHandler(STDERR_HANDLER)
    else:
        logging.getLogger("pyupdater").setLevel(logging.ERROR)
        import poodle
        poodle.log.setLevel(logging.ERROR)
    client = Client(ClientConfig())
    client.refresh()
    app_update = client.update_check(APP_NAME, APP_VERSION)
    if app_update is not None:
        app_update.download()
        if app_update.is_downloaded():
            app_update.extract_restart()
    run(sys.argv[1:])  # pylint: disable=no-value-for-parameter
Beispiel #19
0
 def test_failed_refresh(self, client):
     client = Client(None, refresh=True, test=True)
     client.data_dir = os.getcwd()
     assert client.ready is False
Beispiel #20
0
class Updater:

    def __init__(self, version):
        self.version = version
        self.cfg = ClientConfig()
        self.cfg.UPDATE_URLS = UPDATE_URLS
        self.cli = Client(self.cfg, headers=AUTHORIZE_HEADER, refresh=True, data_dir=DOWNLOAD_FOLDER)
        self.app_update = None

    def if_latest_version(self):
        try:
            app_update = self.cli.update_check(self.cfg.APP_NAME, self.version)
            return app_update.version
        except AttributeError:
            return self.version

    def download(self, callback):
        self.cli.add_progress_hook(callback)
        self.app_update = self.cli.update_check(self.cfg.APP_NAME, self.version)
        if self.app_update is None:
            return None

        self.app_update.download()
        if self.app_update.is_downloaded():
            return True

    def install(self):
        if not self.app_update:
            return None

        if self.app_update.is_downloaded():
            self.app_update.extract_restart()
        return True

    # asset
    def get_asset_latest_version(self, asset_name, asset_version):
        try:
            lib_update = self.cli.update_check(asset_name, asset_version)
            return lib_update.version
        except AttributeError as e:
            print("check_asset_update_log error ", e)
            return None

    def download_asset(self, asset_name, asset_version):
        """

        :param asset_name:
        :param asset_version:
        :return:
        """
        lib_update = self.cli.update_check(asset_name, asset_version)
        if lib_update is None:
            return None
        lib_update.download()
        if lib_update.is_downloaded():
            lib_update.extract()
        return lib_update.update_folder

    # asset-update log
    def check_asset_update_log(self):
        """
        检查update_log的版本,update_log版本需要和app版本一致
        :return: 版本号
        """
        new_version = self.get_asset_latest_version(ASSET_UPDATE_LOG, self.version)
        return new_version if new_version else self.version

    def download_asset_update_log(self):
        return self.download_asset(ASSET_UPDATE_LOG, self.version)
Beispiel #21
0
    def __init__(self, queue, app_name, app_version):

        # OS
        PLATFORM = platform.system()  # -> 'Windows' / 'Linux' / 'Darwin'

        # SET WORKING DIRECTORY
        # This is required for the PATHS to work properly when app is frozen
        if PLATFORM == 'Windows':
            cwd = os.path.dirname(os.path.abspath(sys.argv[0]))
        elif PLATFORM == 'Linux':
            cwd = os.path.abspath(
                os.path.join(os.path.dirname(__file__), os.pardir))
        else:
            logging.warning(('This app has not been yet '
                             'tested for platform_system={}').format(PLATFORM))
            cwd = os.path.abspath(
                os.path.join(os.path.dirname(__file__), os.pardir))
        os.chdir(cwd)

        #A callback to print download progress.
        def downloadStatus(info):
            total = info.get(u'total')
            downloaded = info.get(u'downloaded')
            progress = str(round(int(downloaded) * 100 / int(total)))
            status = info.get(u'status')

            if status == "finished":
                logging.info("Download finished")
            elif status == "downloading":
                logging.debug("Download progress: %s" % progress + "%")
                queue.put(progress)
            else:
                logging.warning(
                    "Unexpected download status: %s".format(status))

        #Initialize client with ClientConfig & later call refresh to get latest update data.
        #This HTTP key is needed to access to my repository.

        logging.debug("Opening client...")
        #client = Client(ClientConfig(),http = "reuMxY8PxCnrHctZyh29")
        client = Client(ClientConfig())
        client.refresh()

        #A hook to track download information
        client.add_progress_hook(downloadStatus)

        #Update_check returns an AppUpdate object if there is an update available
        logging.debug("Checking for updates...")
        app_update = client.update_check(app_name, app_version)

        #If we get an update object we can proceed to download the update.
        if app_update is not None:
            logging.info("A newer version was found")
            logging.debug("Downloading update...")
            app_update.download()
        else:
            logging.info("No update avalable")
            queue.put("NO_UPDATE")

        #Ensure file downloaded successfully, extract update, overwrite and restart current application
        if app_update is not None and app_update.is_downloaded():
            logging.debug("Overwriting current application...")
            app_update.extract_overwrite()
            logging.info("Succefuly overwrited")
            queue.put("DONE")
Beispiel #22
0
APP_NAME = 'Google Photos Wallpaper'
APP_VERSION = '0.0.1'


# Pyupdater download status callback
def print_status_info(info):
    total = info.get(u'total')
    downloaded = info.get(u'downloaded')
    status = info.get(u'status')
    print(downloaded, total, status)


print('Initializing client')
client = Client(ClientConfig(),
                refresh=True,
                progress_hooks=[print_status_info])
print('Client initialized')

print('Checking for updates')
app_update = client.update_check(APP_NAME, APP_VERSION)

if app_update is not None:
    print('Update available, downloading')
    app_update.download(background=True)

    if app_update.is_downloaded():
        print('Downloaded update, restarting')
        app_update.extract_restart()
else:
    print("No updates")
Beispiel #23
0
APP_NAME = 'p2'
APP_VERSION = '1.1.1'

ASSET_NAME = 'ffmpeg'
ASSET_VERSION = '2.3.2'


def print_status_info(info):
    total = info.get(u'total')
    downloaded = info.get(u'downloaded')
    status = info.get(u'status')
    print(downloaded, total, status)


client = Client(ClientConfig())
client.refresh()

client.add_progress_hook(print_status_info)
client = Client(ClientConfig(),
                refresh=True,
                progress_hooks=[print_status_info])
app_update = client.update_check(APP_NAME, APP_VERSION)
app_update = client.update_check(APP_NAME, APP_VERSION, channel='beta')
if app_update is not None:
    app_update.download()

if app_update is not None:
    app_update.download(background=True)
    if app_update.is_downloaded():
        app_update.extract_overwrite()
Beispiel #24
0
def client():
    t_config = TConfig()
    t_config.DATA_DIR = os.getcwd()
    client = Client(t_config, refresh=True, test=True)
    client.FROZEN = True
    return client
Beispiel #25
0
class Updater(Tk):

    HEIGHT = 600
    WIDTH = 600

    def __init__(self):
        super(Updater, self).__init__()
        self.title("Application updater")
        self.minsize(self.WIDTH, self.HEIGHT)
        self.wm_iconbitmap('./assets/icons/icon.ico')

        self.client = Client(ClientConfig(), progress_hooks=[self.print_status_info])
        self.client.refresh()
        self.pb = None
        self.frame_updater = None
        self.label = None
        self.waiting_image = None
        self.lib_update = self.client.update_check('Application', application.__version__)

    def run(self):
        global_frame = tk.Frame(self, height=self.HEIGHT, width=self.WIDTH, bg="#222222")
        global_frame.place(x=0, y=0, relwidth=1, relheight=1)

        frame_top = tk.Frame(self, bg="#990033")
        frame_top.place(relx=0, rely=0, relwidth=1, relheight=0.2)

        attention_image = tk.PhotoImage(file='./assets/images/attention.png')

        label = tk.Label(frame_top, text=" Programme Updater", bg="#990033", foreground="#ffffff", image=attention_image, compound="left", font=60)
        label.config(font=(None, 21))
        label.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.8)

        self.frame_updater = tk.Frame(self, bg="#555555")
        self.frame_updater.place(relx=0.1, rely=0.4, relwidth=0.8, relheight=0.2)

        self.waiting_image = tk.PhotoImage(file='./assets/images/waiting.png')

        self.label = tk.Label(self.frame_updater, text=" Checking for update", bg="#999999", foreground="#ffffff", image=self.waiting_image, compound="left", font=60)
        self.label.config(font=(None, 12))
        self.label.place(relx=0.1, rely=0.1, relwidth=0.8, relheight=0.4)
        self.pb = ttk.Progressbar(self.frame_updater, orient="horizontal", length=200, mode="determinate", value=0, maximum=100)
        self.pb.place(relx=0.1, rely=0.5, relwidth=0.8, relheight=0.2)

        self.after(500, self.update)

    def update(self):
        if self.lib_update is not None:
            self.lib_update.cleanup()
            self.client.refresh()
            self.label['text'] = ' Downloading update'
            self.after(100, self.download)
            self.lib_update.download()
        else:
            self.pb.destroy()
            self.waiting_image = tk.PhotoImage(file='./assets/images/ok.png')
            self.label['image'] = self.waiting_image
            self.label['text'] = ' No update needed'
            self.after(1000, self.execute_app)

    def download(self):
        if self.lib_update is not None and self.lib_update.is_downloaded():
            self.label['text'] = ' Installing update & restart'
            # self.pb['value'] = 100
            self.after(1000, self.restart)

    def restart(self):
        self.lib_update.extract_restart()

    def print_status_info(self, info):
        total = info.get(u'total')
        percent_complete = info.get(u'percent_complete')
        downloaded = info.get(u'downloaded')
        status = info.get(u'status')
        self.pb['value'] = percent_complete
        print(downloaded, total, status, percent_complete)

    def execute_app(self):
        self.destroy()
        app = Application()
        app.run()
        app.mainloop()
Beispiel #26
0
class VersionHandler(TasksThread):
    """Check for new version and update or notify."""

    newVersion = pyqtSignal(str)
    newData = pyqtSignal(str)
    noNewVersion = pyqtSignal()
    progress = pyqtSignal(dict)
    updated_data = pyqtSignal(str)

    # Constants
    APP_NAME = ClientConfig.APP_NAME
    APP_VERSION = scctool.__version__

    ASSET_NAME = 'SCCT-data'
    ASSET_VERSION = '0.0.0'

    client = Client(ClientConfig())

    app_update = None
    asset_update = None

    def __init__(self, controller):
        """Init the thread."""
        super().__init__()

        self.__controller = controller
        self.setTimeout(10)

        self.addTask('version_check', self.__version_check)
        self.addTask('update_data', self.__update_data)
        self.addTask('update_app', self.__update_app)

        self.updated_data.connect(controller.displayWarning)
        # self.disableCB.connect(controller.uncheckCB)

    def isCompatible(self):
        """Check if data update is needed."""
        return compareVersions(self.asset_update.latest, self.APP_VERSION,
                               3) < 1

    def update_progress(self, data):
        """Process progress updates."""
        self.progress.emit(data)

    def __version_check(self):
        try:
            self.client.add_progress_hook(self.update_progress)
            self.client.refresh()
            self.ASSET_VERSION = getDataVersion()
            channel = getChannel(self.APP_VERSION)
            self.app_update = self.client.update_check(self.APP_NAME,
                                                       self.APP_VERSION,
                                                       channel=channel)
            if self.asset_update is not None:
                self.newData.emit(self.asset_update.latest)
                module_logger.info("Asset: " + self.asset_update.latest)
                if self.isCompatible():
                    self.activateTask("update_data")

            if self.app_update is not None:
                scctool.__latest_version__ = self.app_update.latest
                scctool.__new_version__ = True
                self.newVersion.emit(self.app_update.latest)
                module_logger.info("App: " + self.app_update.latest)
            else:
                self.noNewVersion.emit()
        except Exception:
            module_logger.exception("message")
        finally:
            self.deactivateTask('version_check')

    def __update_data(self):
        try:
            module_logger.info("Start to update data files!")
            if self.asset_update is None:
                self.deactivateTask('update_data')
                return
            self.asset_update.download()
            extractData(self.asset_update)
            module_logger.info("Updated data files!")
            self.updated_data.emit(_("Updated data files!"))
        except Exception:
            module_logger.exception("message")
        finally:
            self.deactivateTask('update_data')

    def __update_app(self):
        try:
            if self.app_update is None:
                self.deactivateTask('update_app')
                return
            if hasattr(sys, "frozen"):
                module_logger.info("Start to update app!")
                self.app_update.download(False)
                if self.app_update.is_downloaded():
                    module_logger.info("Download sucessfull.")
                    self.__controller.cleanUp()
                    setRestartFlag()
                    module_logger.info("Restarting...")
                    self.app_update.extract_restart()
        except Exception:
            module_logger.exception("message")
        finally:
            self.deactivateTask('update_app')
Beispiel #27
0
 def test_bad_pub_key(self, client):
     t_config = TConfig()
     t_config.PUBLIC_KEYS = ['bad key']
     t_config.DATA_DIR = os.getcwd()
     client = Client(t_config, refresh=True, test=True)
     assert client.update_check('jms', '0.0.0') is None
class MidiProjectController:
    def __init__(self, callback=None, options=None):
        self._sendMidiCallback = callback

        self._update_paths = None
        self._client_config = None
        self._isUpdating = False
        if options is not None:
            self._update_paths = options.update_paths
            self._client_config = options.client_config
            self._update_urls = options.update_urls
        # Client for pyupdate
        if self._client_config is None:
            self._client_config = client_config.ClientConfig()
        self.client = Client(self._client_config,
                             downloader=self.createDownloader)
        self.client.add_progress_hook(print_status_info)

    def createDownloader(self, filename, urls, **kwargs):
        logger.debug("Create downloader for {}".format(filename))
        # replace urls from serverconfig
        urls = self._update_urls
        d = PathAndUrlDownloader(filename,
                                 urls,
                                 callback=self.downloadCallback)
        return d

    def downloadCallback(self, file):
        if self._update_paths is not None:
            for updatePath in self._update_paths:
                for p in glob.iglob(updatePath):
                    if os.path.isdir(p):
                        logger.info("Checking directory {}/{}".format(p, file))
                        path = os.path.join(p, file)
                        if os.path.isfile(path):
                            logger.info(
                                "Downloading from path {}".format(path))
                            return open(path, "rb").read()
                logger.debug("{} not found in {}".format(file, updatePath))
        return None

    def handleMidiMsg(self, msg: mido.Message,
                      serverconfig: serverconfiguration.ServerConfiguration,
                      proj: project.Project):
        # of type mido.Message
        # channel	0..15	0
        # frame_type	0..7	0
        # frame_value	0..15	0
        # control	0..127	0
        # note	0..127	0
        # program	0..127	0
        # song	0..127	0
        # value	0..127	0
        # velocity	0..127	64
        # data	(0..127, 0..127, …)	() (empty tuple)
        # pitch	-8192..8191	0
        # pos	0..16383	0
        # time	any integer or float	0

        if msg.type == 'program_change':
            self._handleProgramChange(msg.program, proj)
        elif msg.type == 'control_change':
            self._handleControlChange(msg.control, msg.value, proj)
        elif msg.type == 'sysex':
            self._handleSysex(msg.data, serverconfig, proj)

    def _handleSysex(self, data,
                     serverconfig: serverconfiguration.ServerConfiguration,
                     proj: project.Project):
        if len(data) < 2:
            logger.error("Sysex message too short")
            return

        if data[0] == 0x00 and data[1] == 0x00:
            # Version
            logger.info("MIDI-BLE REQ Version")
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(self._createVersionMsg())
        elif data[0] == 0x00 and data[1] == 0x10:
            # Update
            logger.info("MIDI-BLE REQ Update")
            logger.info("Checking for update, current version is {}".format(
                version.get_version()))
            self._updatePathsAndUrls(serverconfig)
            if not self._isUpdating:
                self._isUpdating = True
                # New Downloaders will be created on request
                self.client.refresh()
                app_update = self.client.update_check('Molecole',
                                                      version.get_version())
                if app_update is not None:
                    logger.info("Update {} available".format(
                        app_update.current_version))
                    threading.Thread(target=self._updateApp,
                                     args=[app_update]).start()
                else:
                    self._isUpdating = False
                    logger.info("Update check returned no update")
                    if self._sendMidiCallback is not None:
                        self._sendMidiCallback(
                            self._createUpdateNotAvailableMsg())
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._createUpdateBusyMsg())
        elif data[0] == 0x00 and data[1] == 0x11:
            # Update check
            logger.info("MIDI-BLE REQ Update check")
            logger.info("Checking for update, current version is {}".format(
                version.get_version()))
            self._updatePathsAndUrls(serverconfig)

            if not self._isUpdating:
                self._isUpdating = True
                try:
                    # Move version.gz to force a reload
                    oldFile = os.path.join(self.client.data_dir,
                                           self.client.version_file)
                    if os.path.exists(oldFile):
                        shutil.move(oldFile, oldFile.replace('.gz', '.gz.bak'))

                    oldFile = os.path.join(self.client.data_dir,
                                           self.client.version_file_compat)
                    if os.path.exists(oldFile):
                        shutil.move(oldFile, oldFile.replace('.gz', '.gz.bak'))

                    self.client.refresh()
                    app_update = self.client.update_check(
                        'Molecole', version.get_version())
                    self._isUpdating = False
                    if app_update is not None:
                        logger.info("Update {} available".format(
                            app_update.version))
                        if self._sendMidiCallback is not None:
                            self._sendMidiCallback(
                                self._createUpdateVersionAvailableMsg(
                                    app_update.version))
                    else:
                        logger.info("Update check returned no update")
                        if self._sendMidiCallback is not None:
                            self._sendMidiCallback(
                                self._createUpdateNotAvailableMsg())
                except Exception as e:
                    logger.error("Error trying to update: {}".format(e))
                    self._isUpdating = False
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._createUpdateBusyMsg())
        elif data[0] == 0x00 and data[1] == 0x20:
            # Active project metadata
            if self._sendMidiCallback is not None:
                metadata = serverconfig.getProjectMetadata(proj.id)
                self._sendMidiCallback(self._createActiveProjectMsg(metadata))
        elif data[0] == 0x00 and data[1] == 0x30:
            # Get projects
            if self._sendMidiCallback is not None:
                metadata = serverconfig.getProjectsMetadata()
                self._sendMidiCallback(self._createProjectsMsg(metadata))
        elif data[0] == 0x00 and data[1] == 0x40:
            # Activate project
            projUid = str(bytes(sysex_data.decode(data[2:])), encoding='utf8')
            logger.info("MIDI-BLE REQ Activate project {}".format(projUid))
            proj = serverconfig.getProject(projUid)
            if proj is not None:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createActivateProjSuccessfulMsg())
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createActivateProjNotFoundMsg())
        elif data[0] == 0x00 and data[1] == 0x50:
            # Import project
            logger.info("MIDI-BLE REQ Import project")
            dec = sysex_data.decode(data[2:])
            projGzip = zlib.decompress(bytes(dec))
            projJson = str(projGzip, encoding='utf8')
            try:
                serverconfig.importProject(projJson)
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createImportProjSuccessfulMsg())
            except Exception:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._createImportProjErrorMsg())
        elif data[0] == 0x00 and data[1] == 0x60:
            # Export project
            byteArr = bytes(sysex_data.decode(data[2:]))
            logger.debug("Decoded {} to {}".format([hex(c) for c in data[2:]],
                                                   byteArr))
            projUid = str(byteArr, encoding='utf8')
            logger.info("MIDI-BLE REQ Export project {}".format(projUid))
            proj = serverconfig.getProject(projUid)
            if proj is not None:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createExportProjSuccessfulMsg(proj))
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._createExportProjNotFoundMsg())
        elif data[0] == 0x00 and data[1] == 0x70:
            # Activate project
            projUid = str(bytes(sysex_data.decode(data[2:])), encoding='utf8')
            logger.info("MIDI-BLE REQ Delete project {}".format(projUid))
            proj = serverconfig.getProject(projUid)
            if proj is not None:
                serverconfig.deleteProject(projUid)
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._deleteProjSuccessfulMsg())
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._deleteProjNotFoundMsg())
        elif data[0] == 0x01 and data[1] == 0x00:
            # Get active scene ID
            logger.info("MIDI-BLE REQ Active scene index")
            sceneId = serverconfig.getActiveProjectOrDefault().activeSceneId
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(
                    self._createGetActiveSceneIdMsg(sceneId))
        elif data[0] == 0x01 and data[1] == 0x10:
            # Get active scene metadata
            logger.info("MIDI-BLE REQ Get active scene metadata")
            proj = serverconfig.getActiveProjectOrDefault()
            metadata = proj.getSceneMetadata(proj.activeSceneId)
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(
                    self._createActiveSceneMetadataMsg(metadata))
        elif data[0] == 0x01 and data[1] == 0x20:
            # Get scenes metadata
            logger.info("MIDI-BLE REQ Get scenes")
            proj = serverconfig.getActiveProjectOrDefault()
            metadata = proj.sceneMetadata
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(self._createScenesMetadataMsg(metadata))
        elif data[0] == 0x01 and data[1] == 0x30:
            # Get enabled controllers for active scene
            logger.info("MIDI-BLE REQ Get controller enabled for active scene")
            proj = serverconfig.getActiveProjectOrDefault()
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(self._createEnabledControllersMsg(proj))
        elif data[0] == 0x01 and data[1] == 0x40:
            # Request controller values for active project
            logger.info("MIDI-BLE REQ Get controller values for active scene")
            proj = serverconfig.getActiveProjectOrDefault()
            self._sendControllerStatus(proj)
        elif data[0] == 0x01 and data[1] == 0x50:
            # Reset controller values for active project
            logger.info("MIDI-BLE REQ Reset controller for active scene")
            proj = serverconfig.getActiveProjectOrDefault()
            proj.resetControllerModulation()
            self._sendControllerStatus(proj)
        elif data[0] == 0x02 and data[1] == 0x00:
            # Get server configuration
            logger.info("MIDI-BLE REQ Get server configuration")
            config = serverconfig.getFullConfiguration()
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(self._createGetServerConfigMsg(config))
        elif data[0] == 0x02 and data[1] == 0x10:
            # Update server configuration
            logger.info("MIDI-BLE REQ Update server configuration")
            dec = sysex_data.decode(data[2:])
            configGzip = zlib.decompress(bytes(dec))
            configJson = str(configGzip, encoding='utf8')
            config = json.loads(configJson)
            try:
                serverconfig.setConfiguration(config)
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createUpdateServerConfigSuccessfulMsg())
            except Exception:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(
                        self._createUpdateServerConfigErrorMsg())
        elif data[0] == 0x02 and data[1] == 0x20:
            logger.info("MIDI-BLE REQ Audio rms")
            rms = {"0": "NO_BUFFER"}
            if audio.GlobalAudio.buffer is not None:
                if isinstance(audio.GlobalAudio.buffer, Iterable):
                    numChannels = len(audio.GlobalAudio.buffer)

                    for i in range(numChannels):
                        rmsFromChannel = dsp.rms(audio.GlobalAudio.buffer[i])
                        rms[str(i)] = rmsFromChannel
                else:
                    logger.debug("audio.GlobalAudio.buffer not iterateable")
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(self._createAudioRMSMsg(
                    json.dumps(rms)))
        else:
            logger.error("MIDI-BLE Unknown sysex {} {}".format(
                hex(data[0]), hex(data[1])))

    def _createAudioRMSMsg(self, rms):
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x02, 0x20] + sysex_data.encode("{}".format(rms))
        return sendMsg

    def _createGetServerConfigMsg(self, config: dict):
        logger.debug("MIDI-BLE RESPONSE Get server config - Successful")
        json = jsonpickle.dumps(config)
        gzip = zlib.compress(bytes(json, encoding='utf8'))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x02, 0x00] + sysex_data.encode(gzip)
        return sendMsg

    def _createUpdateServerConfigSuccessfulMsg(self):
        logger.debug("MIDI-BLE RESPONSE Update server config - Successful")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x02, 0x10]
        return sendMsg

    def _createUpdateServerConfigErrorMsg(self):
        logger.debug("MIDI-BLE RESPONSE Update server config - Successful")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x02, 0x1F]
        return sendMsg

    def _updateApp(self, app_update):
        try:
            logger.debug("Starting download in background")
            threading.current_thread().name = 'UpdateThread'
            app_update.download()

            if app_update.is_downloaded():
                logger.info("Update downloaded")
                if not getattr(sys, 'frozen', False):
                    logger.info("Not running from executable. Extract only")
                    logger.debug("Extracting update")
                    if app_update.extract():
                        logger.debug("Extract succeeded")
                    else:
                        logger.debug("Extract not successful")
                    logger.debug("Extract done")
                else:
                    logger.info("Extracting and restarting...")
                    app_update.extract_overwrite()
                    logger.info("Extracting done. Killing server")
                    os.kill(os.getpid(), signal.SIGUSR1)
            else:
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(self._createUpdateNotAvailableMsg())
            logger.debug("End of update")
        finally:
            self._isUpdating = False

    def _createEnabledControllersMsg(self, proj):
        status = proj.getController()
        controllerEnabled = {}
        for controller in modulation.allController:
            if controller in inverseControllerMap:
                controllerEnabled[inverseControllerMap[controller]] = False

        logger.debug("Status: {}".format(status.keys()))
        for controller in status.keys():
            if controller in inverseControllerMap:
                controllerEnabled[inverseControllerMap[controller]] = True

        logger.debug(
            "MIDI-BLE RESPONSE Enabled controllers for active scene: {}".
            format(controllerEnabled))

        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x01, 0x30] + sysex_data.encode(
            json.dumps(controllerEnabled))
        return sendMsg

    def _createScenesMetadataMsg(self, metadata):
        logger.debug(
            "MIDI-BLE RESPONSE Get scenes metadata {}".format(metadata))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x01, 0x20] + sysex_data.encode(json.dumps(metadata))
        return sendMsg

    def _createActiveSceneMetadataMsg(self, metadata):
        logger.debug(
            "MIDI-BLE RESPONSE Get active scene metadata {}".format(metadata))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x01, 0x10] + sysex_data.encode(json.dumps(metadata))
        return sendMsg

    def _createGetActiveSceneIdMsg(self, sceneId: int):
        logger.debug(
            "MIDI-BLE RESPONSE Get active scene id {}".format(sceneId))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x01, 0x00] + sysex_data.encode("{}".format(sceneId))
        return sendMsg

    def _createExportProjSuccessfulMsg(self, proj):
        logger.debug("MIDI-BLE RESPONSE Export project - Successful")
        projJson = jsonpickle.dumps(proj)
        projGzip = zlib.compress(bytes(projJson, encoding='utf8'))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x60] + sysex_data.encode(projGzip)
        return sendMsg

    def _createExportProjNotFoundMsg(self):
        logger.debug("MIDI-BLE RESPONSE Export project - Not found")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x6F]
        return sendMsg

    def _deleteProjSuccessfulMsg(self):
        logger.debug("MIDI-BLE RESPONSE Delete project - Successful")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x70]
        return sendMsg

    def _deleteProjNotFoundMsg(self):
        logger.debug("MIDI-BLE RESPONSE Delete project - Not found")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x7F]
        return sendMsg

    def _createImportProjSuccessfulMsg(self):
        logger.debug("MIDI-BLE RESPONSE Import project - Successful")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x50]
        return sendMsg

    def _createImportProjErrorMsg(self):
        logger.debug("MIDI-BLE RESPONSE Import project - Error")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x5F]
        return sendMsg

    def _createActivateProjSuccessfulMsg(self):
        logger.debug("MIDI-BLE RESPONSE Activate project - Successful")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x40]
        return sendMsg

    def _createActivateProjNotFoundMsg(self):
        logger.debug("MIDI-BLE RESPONSE Activate project - Project not found")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x4F]
        return sendMsg

    def _createUpdateVersionAvailableMsg(self, version):
        logger.debug(
            "MIDI-BLE RESPONSE Update to version {} available".format(version))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x11] + sysex_data.encode(version)
        return sendMsg

    def _createUpdateNotAvailableMsg(self):
        logger.debug("MIDI-BLE RESPONSE No update available")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x1F]
        return sendMsg

    def _createUpdateBusyMsg(self):
        logger.debug(
            "MIDI-BLE RESPONSE Update or update check running. I'm busy.")
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x1E]
        return sendMsg

    def _createActiveProjectMsg(self, metadata):
        data = json.dumps(metadata)
        logger.debug("MIDI-BLE RESPONSE Active project {}".format(data))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x20] + sysex_data.encode(data)
        return sendMsg

    def _createProjectsMsg(self, metadata):
        data = json.dumps(metadata)
        logger.debug("MIDI-BLE RESPONSE project metadata: {}".format(data))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x30] + sysex_data.encode(data)
        return sendMsg

    def _createVersionMsg(self):
        v = version.get_version()
        logger.debug("MIDI-BLE RESPONSE Current Version {}".format(v))
        sendMsg = mido.Message('sysex')
        sendMsg.data = [0x00, 0x00] + sysex_data.encode(v)
        return sendMsg

    def _sendControllerStatus(self, proj):
        # Send current midi controller status
        status = proj.getControllerModulations()
        for controller, v in status.items():
            logger.debug(
                "Sending modulation controller value {} for controller {}".
                format(v, controller))
            sendMsg = mido.Message('control_change')
            if controller in inverseControllerMap:
                sendMsg.channel = 1
                sendMsg.control = inverseControllerMap[controller]
                if sendMsg.control >= 30:
                    # scale color data
                    sendMsg.value = int(v / 255 * 127)
                else:
                    sendMsg.value = int(v * 127)
                if self._sendMidiCallback is not None:
                    self._sendMidiCallback(sendMsg)
        # Send current brightness value
        brightness = proj.getBrightnessActiveScene()
        if brightness is not None:
            sendMsg = mido.Message('control_change')
            sendMsg.channel = 1
            sendMsg.control = 7
            sendMsg.value = int(brightness * 127)
            if self._sendMidiCallback is not None:
                self._sendMidiCallback(sendMsg)

    def _getUpdatePaths(self, paths: str):
        if ',' in paths:
            paths = paths.split(',')
        else:
            paths = [paths]
        return paths

    def _handleProgramChange(self, program, proj):
        proj.activateScene(program)

        self._sendControllerStatus(proj)

        # Send enabled controllers via sysex
        if self._sendMidiCallback is not None:
            self._sendMidiCallback(self._createEnabledControllersMsg(proj))

    def _handleControlChange(self, ctrl, value, proj):
        if ctrl in controllerMap:
            controlMsg = controllerMap[ctrl]
            controlVal = _ctrlToValue(controlMsg, value / 127)
            logger.debug("Propagating control change message")
            if controlMsg == modulation.CTRL_BRIGHTNESS:
                # Handle brightness globally
                proj.setBrightnessForActiveScene(value / 127)
            else:
                proj.updateModulationSourceValue(0xFFF, controlMsg, controlVal)
        else:
            logger.warn("Unknown controller {}".format(ctrl))

    def _updatePathsAndUrls(self, serverconfig):
        updatePath = serverconfig.getConfiguration(
            serverconfiguration.CONFIG_UPDATER_AUTOCHECK_PATH)
        logger.info("Scanning configuration for local directories {}".format(
            updatePath))
        updateUrls = serverconfig.getConfiguration(
            serverconfiguration.CONFIG_UPDATER_URL)
        self._update_paths = self._getUpdatePaths(updatePath)
        if updateUrls is not None and isinstance(updateUrls, str):
            self._update_urls = updateUrls.split(",")
        logger.info("Scanning local directories {} and urls {}".format(
            self._update_paths, self._update_urls))
Beispiel #29
0
 def __init__(self, version):
     self.version = version
     self.cfg = ClientConfig()
     self.cfg.UPDATE_URLS = UPDATE_URLS
     self.cli = Client(self.cfg, headers=AUTHORIZE_HEADER, refresh=True, data_dir=DOWNLOAD_FOLDER)
     self.app_update = None