Beispiel #1
0
    def __init__(self,
                 host,
                 user,
                 keyfile,
                 python_executable='~/anaconda3/bin/python'):

        self.remote_machine = _get_machine(host, user, keyfile)
        self._kill_py()
        self.py = self.remote_machine[python_executable]

        self.proc = self.py.popen(['-m', 'bnb.remote.server'],
                                  new_session=True)
        self.local_port = None

        line = ""
        try:
            logger.debug(f'Waiting for the line')

            line = self.proc.stdout.readline()
            self.remote_port = int(line.strip())

        except Exception:
            stdout, stderr = self.proc.communicate()
            self.close()

            raise ProcessExecutionError(self.proc.argv, self.proc.returncode,
                                        BYTES_LITERAL(line) + stdout, stderr)
Beispiel #2
0
    def __init__(self,
                 remote_machine,
                 server_class="rpyc.utils.server.ThreadedServer",
                 extra_setup="",
                 python_executable=None):
        self.proc = None
        self.tun = None
        self.remote_machine = remote_machine
        self._tmpdir_ctx = None

        rpyc_root = local.path(rpyc.__file__).up()
        self._tmpdir_ctx = remote_machine.tempdir()
        tmp = self._tmpdir_ctx.__enter__()
        copy(rpyc_root, tmp / "rpyc")

        script = (tmp / "deployed-rpyc.py")
        modname, clsname = server_class.rsplit(".", 1)
        script.write(
            SERVER_SCRIPT.replace("$MODULE$", modname).replace(
                "$SERVER$", clsname).replace("$EXTRA_SETUP$", extra_setup))
        if python_executable:
            cmd = remote_machine[python_executable]
        else:
            major = sys.version_info[0]
            minor = sys.version_info[1]
            cmd = None
            for opt in [
                    "python%s.%s" % (major, minor),
                    "python%s" % (major, )
            ]:
                try:
                    cmd = remote_machine[opt]
                except CommandNotFound:
                    pass
                else:
                    break
            if not cmd:
                cmd = remote_machine.python

        self.proc = cmd.popen(script, new_session=True)

        line = ""
        try:
            line = self.proc.stdout.readline()
            self.remote_port = int(line.strip())
        except Exception:
            try:
                self.proc.terminate()
            except Exception:
                pass
            stdout, stderr = self.proc.communicate()
            raise ProcessExecutionError(self.proc.argv, self.proc.returncode,
                                        BYTES_LITERAL(line) + stdout, stderr)

        if hasattr(remote_machine, "connect_sock"):
            # Paramiko: use connect_sock() instead of tunnels
            self.local_port = None
        else:
            self.local_port = rpyc.utils.factory._get_free_port()
            self.tun = remote_machine.tunnel(self.local_port, self.remote_port)
Beispiel #3
0
    def __init__(self, remote_machine, server_class="ThreadedServer"):
        self.proc = None
        self.tun = None
        self._tmpdir_ctx = None

        rpyc_root = local.path(rpyc.__file__).dirname
        self._tmpdir_ctx = remote_machine.tempdir()
        tmp = self._tmpdir_ctx.__enter__()
        copy(rpyc_root, tmp)

        script = (tmp / "deployed-rpyc.py")
        script.write(SERVER_SCRIPT.replace("$SERVER$", server_class))
        self.proc = remote_machine.python.popen(script, new_session=True)

        line = ""
        try:
            line = self.proc.stdout.readline()
            remote_port = int(line.strip())
        except Exception:
            try:
                self.proc.terminate()
            except Exception:
                pass
            stdout, stderr = self.proc.communicate()
            raise ProcessExecutionError(self.proc.argv, self.proc.returncode,
                                        line + stdout, stderr)

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("localhost", 0))
        self.local_port = s.getsockname()[1]
        s.close()
        self.tun = remote_machine.tunnel(self.local_port, remote_port)
Beispiel #4
0
    def __init__(self,
                 remote_machine,
                 server_class="rpyc.utils.server.ThreadedServer",
                 extra_setup=""):
        self.proc = None
        self.tun = None
        self.remote_machine = remote_machine
        self._tmpdir_ctx = None

        rpyc_root = local.path(rpyc.__file__).up(2)
        self._tmpdir_ctx = remote_machine.tempdir()
        tmp = self._tmpdir_ctx.__enter__()
        copy(rpyc_root, tmp)

        script = (tmp / "deployed-rpyc.py")
        modname, clsname = server_class.rsplit(".", 1)
        script.write(
            SERVER_SCRIPT.replace("$MODULE$", modname).replace(
                "$SERVER$", clsname).replace("$EXTRA_SETUP$", extra_setup))
        self.proc = remote_machine.python.popen(script, new_session=True)

        line = ""
        try:
            line = self.proc.stdout.readline()
            self.remote_port = int(line.strip())
        except Exception:
            try:
                self.proc.terminate()
            except Exception:
                pass
            stdout, stderr = self.proc.communicate()
            raise ProcessExecutionError(self.proc.argv, self.proc.returncode,
                                        line + stdout, stderr)

        if hasattr(remote_machine, "connect_sock"):
            # Paramiko: use connect_sock() instead of tunnels
            self.local_port = None
        else:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.bind(("localhost", 0))
            self.local_port = s.getsockname()[1]
            s.close()
            self.tun = remote_machine.tunnel(self.local_port, self.remote_port)
Beispiel #5
0
def deployment(remote_machine, code=SERVER_SCRIPT):
    with remote_machine.tempdir() as tmp:
        copy(RPYC_ROOT, tmp)
        delete(tmp // ".pyc", tmp // "*/.pyc")
        with remote_machine.cwd(tmp):
            with remote_machine.env(
                    PYTHONPATH=remote_machine.env.get("PYTHONPATH", "") +
                    ":%s" % (tmp, )):
                proc = (remote_machine.python << code).popen()

        line = ""
        try:
            line = proc.stdout.readline()
            remote_port = int(line.strip())
        except Exception:
            try:
                proc.kill()
            except Exception:
                pass
            stdout, stderr = proc.communicate()
            raise ProcessExecutionError(proc.argv, proc.returncode,
                                        line + stdout, stderr)

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.bind(("localhost", 0))
        local_port = s.getsockname()[1]
        s.close()

        with remote_machine.tunnel(local_port, remote_port) as tun:
            try:
                yield DeployedServer(local_port)
            finally:
                try:
                    proc.kill()
                except Exception:
                    pass
Beispiel #6
0
    def download_url_and_send(self,
                              bot,
                              url,
                              direct_urls,
                              chat_id,
                              reply_to_message_id=None,
                              wait_message_id=None):
        bot.send_chat_action(chat_id=chat_id, action=ChatAction.RECORD_AUDIO)
        download_dir = os.path.join(self.DL_DIR, str(uuid4()))
        shutil.rmtree(download_dir, ignore_errors=True)
        os.makedirs(download_dir)

        status = 0
        if direct_urls == "direct":
            status = -3
        elif direct_urls == "country":
            status = -4
        elif direct_urls == "live":
            status = -5
        else:
            if (self.SITES["sc"] in url
                    and self.SITES["scapi"] not in url) or (self.SITES["bc"]
                                                            in url):
                cmd_name = "scdl"
                cmd_args = []
                cmd = None
                cmd_input = None
                if self.SITES["sc"] in url and self.SITES["scapi"] not in url:
                    cmd_name = "scdl"
                    cmd_args = (
                        "-l",
                        url,  # URL of track/playlist/user
                        "-c",  # Continue if a music already exist
                        "--path",
                        download_dir,  # Download the music to a custom path
                        "--onlymp3",  # Download only the mp3 file even if the track is Downloadable
                        "--addtofile",  # Add the artist name to the filename if it isn't in the filename already
                        "--addtimestamp",  # Adds the timestamp of the creation of the track to the title (useful to sort chronologically)
                        "--no-playlist-folder",
                        # Download playlist tracks into directory, instead of making a playlist subfolder
                    )
                    cmd = scdl_bin
                    cmd_input = None
                elif self.SITES["bc"] in url:
                    cmd_name = "bandcamp-dl"
                    cmd_args = (
                        "--base-dir",
                        download_dir,  # Base location of which all files are downloaded
                        "--template",
                        "%{track} - %{artist} - %{title} [%{album}]",  # Output filename template
                        "--overwrite",  # Overwrite tracks that already exist
                        "--group",  # Use album/track Label as iTunes grouping
                        "--embed-art",  # Embed album art (if available)
                        "--no-slugify",  # Disable slugification of track, album, and artist names
                        url,  # URL of album/track
                    )
                    cmd = bandcamp_dl_bin
                    cmd_input = "yes"

                logger.info("%s starts: %s", cmd_name, url)
                cmd_proc = cmd[cmd_args].popen(stdin=PIPE,
                                               stdout=PIPE,
                                               stderr=PIPE,
                                               universal_newlines=True)
                try:
                    cmd_stdout, cmd_stderr = cmd_proc.communicate(
                        input=cmd_input, timeout=self.DL_TIMEOUT)
                    cmd_retcode = cmd_proc.returncode
                    if cmd_retcode or "Error resolving url" in cmd_stderr:
                        raise ProcessExecutionError(cmd_args, cmd_retcode,
                                                    cmd_stdout, cmd_stderr)
                    logger.info("%s succeeded: %s", cmd_name, url)
                    status = 1
                except TimeoutExpired:
                    cmd_proc.kill()
                    logger.info("%s took too much time and dropped: %s", url)
                    status = -1
                except ProcessExecutionError:
                    logger.exception("%s failed: %s" % (cmd_name, url))

        if status == 0:
            cmd_name = "youtube-dl"
            cmd = youtube_dl_func
            # TODO: set different ydl_opts for different sites
            ydl_opts = {
                'format':
                'bestaudio/best',
                'outtmpl':
                os.path.join(download_dir, '%(title)s.%(ext)s'),
                # default: %(autonumber)s - %(title)s-%(id)s.%(ext)s
                'postprocessors': [
                    {
                        'key': 'FFmpegExtractAudio',
                        'preferredcodec': 'mp3',
                        'preferredquality': '128',
                    },
                    # {'key': 'EmbedThumbnail',}, {'key': 'FFmpegMetadata',},
                ],
            }
            queue = Queue()
            cmd_args = (
                url,
                ydl_opts,
                queue,
            )

            logger.info("%s starts: %s", cmd_name, url)
            cmd_proc = Process(target=cmd, args=cmd_args)
            cmd_proc.start()
            try:
                cmd_retcode, cmd_stderr = queue.get(block=True,
                                                    timeout=self.DL_TIMEOUT)
                cmd_stdout = ""
                cmd_proc.join()
                if cmd_retcode:
                    raise ProcessExecutionError(cmd_args, cmd_retcode,
                                                cmd_stdout, cmd_stderr)
                    # raise cmd_status  #TODO: pass and re-raise original Exception?
                logger.info("%s succeeded: %s", cmd_name, url)
                status = 1
            except Empty:
                cmd_proc.join(1)
                if cmd_proc.is_alive():
                    cmd_proc.terminate()
                logger.info("%s took too much time and dropped: %s", cmd_name,
                            url)
                status = -1
            except ProcessExecutionError:
                logger.exception("%s failed: %s" % (cmd_name, url))
                status = -2
            gc.collect()

        if status == -1:
            bot.send_message(chat_id=chat_id,
                             reply_to_message_id=reply_to_message_id,
                             text=self.DL_TIMEOUT_TEXT,
                             parse_mode='Markdown')
        elif status == -2:
            bot.send_message(chat_id=chat_id,
                             reply_to_message_id=reply_to_message_id,
                             text=self.NO_AUDIO_TEXT,
                             parse_mode='Markdown')
        elif status == -3:
            bot.send_message(chat_id=chat_id,
                             reply_to_message_id=reply_to_message_id,
                             text=self.DIRECT_RESTRICTION_TEXT,
                             parse_mode='Markdown')
        elif status == -4:
            bot.send_message(chat_id=chat_id,
                             reply_to_message_id=reply_to_message_id,
                             text=self.REGION_RESTRICTION_TEXT,
                             parse_mode='Markdown')
        elif status == -5:
            bot.send_message(chat_id=chat_id,
                             reply_to_message_id=reply_to_message_id,
                             text=self.LIVE_RESTRICTION_TEXT,
                             parse_mode='Markdown')
        elif status == 1:
            file_list = []
            for d, dirs, files in os.walk(download_dir):
                for file in files:
                    file_list.append(os.path.join(d, file))
            for file in sorted(file_list):
                file_name = os.path.split(file)[-1]
                file_parts = []
                try:
                    file_parts = self.split_audio_file(file)
                except FileNotSupportedError as exc:
                    if not (exc.file_format in ["m3u", "jpg", "jpeg", "png"]):
                        logger.warning("Unsupported file format: %s",
                                       file_name)
                        bot.send_message(
                            chat_id=chat_id,
                            reply_to_message_id=reply_to_message_id,
                            text=
                            "*Sorry*, downloaded file `{}` is in format I could not yet convert or send"
                            .format(file_name),
                            parse_mode='Markdown')
                except FileTooLargeError as exc:
                    logger.info("Large file for convert: %s", file_name)
                    bot.send_message(
                        chat_id=chat_id,
                        reply_to_message_id=reply_to_message_id,
                        text=
                        "*Sorry*, downloaded file `{}` is `{}` MB and it is larger than I could convert (`{} MB`)"
                        .format(file_name, exc.file_size // 1000000,
                                self.MAX_CONVERT_FILE_SIZE // 1000000),
                        parse_mode='Markdown')
                except FileConvertedPartiallyError as exc:
                    file_parts = exc.file_parts
                    logger.exception("Pydub failed: %s" % file_name)
                    bot.send_message(
                        chat_id=chat_id,
                        reply_to_message_id=reply_to_message_id,
                        text="*Sorry*, not enough memory to convert file `{}`.."
                        .format(file_name),
                        parse_mode='Markdown')
                except FileNotConvertedError as exc:
                    logger.exception("Pydub failed: %s" % file_name)
                    bot.send_message(
                        chat_id=chat_id,
                        reply_to_message_id=reply_to_message_id,
                        text="*Sorry*, not enough memory to convert file `{}`.."
                        .format(file_name),
                        parse_mode='Markdown')
                try:
                    caption = "Downloaded from {} with @{}\n".format(
                        URL(url).host, self.bot_username)
                    if "qP303vxTLS8" in url:
                        caption += "\n" + random.choice([
                            "Скачал музла, машина эмпэтри дала!",
                            "У тебя талант, братан! Ка-какой? Качать онлайн!",
                            "Слушаю и не плачУ, то, что скачал вчера",
                            "Всё по чесноку, если скачал, отгружу музла!",
                            "Дёрнул за канат, и телега поймала трэкан!",
                            "Сегодня я качаю, и трэки не влазят мне в RAM!",
                        ])
                    flood = self.chat_storage[str(
                        chat_id)]["settings"]["flood"]
                    sent_audio_ids = self.send_audio_file_parts(
                        bot, chat_id, file_parts,
                        reply_to_message_id if flood == "yes" else None,
                        caption if flood == "yes" else None)
                except FileSentPartiallyError as exc:
                    sent_audio_ids = exc.sent_audio_ids
                    bot.send_message(
                        chat_id=chat_id,
                        reply_to_message_id=reply_to_message_id,
                        text=
                        "*Sorry*, could not send file `{}` or some of it's parts.."
                        .format(file_name),
                        parse_mode='Markdown')
                    logger.warning("Sending some parts failed: %s" % file_name)

        if not self.SERVE_AUDIO:
            shutil.rmtree(download_dir, ignore_errors=True)
        if wait_message_id:  # TODO: delete only once
            try:
                bot.delete_message(chat_id=chat_id, message_id=wait_message_id)
            except:
                pass
 def __call__(self):
     raise ProcessExecutionError([], 1, "", "")