def stop_cli(self): """ Stop the telegram process. :return: (int) returncode of the cli process. :rtype int: """ logger.info("Closing Connections.") logger.debug("Closing sender.") if self.sender: self.sender.terminate() # not let the cli end close first -> avoid bind: port already in use. logger.debug("Closing sender.") if self.receiver: self.receiver.stop() logger.info("Asking to CLI to stop.") if self._proc is not None: if self.sender.do_quit: logger.debug("Sender already stopped. Unable to issue safe_quit or quit to exit via socket.") else: try: self.sender.safe_quit() except (NoResponse, IllegalResponseException, AssertionError): logger.debug("safe_quit Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("safe_quit did not terminate.") try: self.sender.quit() except (NoResponse, IllegalResponseException, AssertionError): logger.debug("quit Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("quit did not terminate.") self.sender.stop() # quit and safe quit are done, we don't need the sender any longer. # end if-else: self.sender._do_quit if self._check_stopped(): return self._proc.returncode # has not terminated yet. self._proc.communicate(b('quit\n')) # report this error in the bugtracker! if self._check_stopped(): return self._proc.returncode try: self._proc.terminate() except Exception as e: # todo: ProcessLookupError does not exist before python 3 logger.debug("terminate Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("terminate did not terminate.") try: self._proc.kill() except Exception as e: # todo: ProcessLookupError does not exist before python 3 logger.debug("kill Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("kill did not terminate.") logger.warn("CLI kinda didn't die... Will wait (block) for termination.") self._proc.wait() self._check_stopped() return self._proc.returncode else: logger.warn("No CLI running.") raise AssertionError("No CLI running.")
def process_request(self, path, request_headers): """ Intercept the HTTP request and return an HTTP response if needed. ``request_headers`` are a :class:`~http.client.HTTPMessage`. If this coroutine returns ``None``, the WebSocket handshake continues. If it returns a status code, headers and a optionally a response body, that HTTP response is sent and the connection is closed. The HTTP status must be a :class:`~http.HTTPStatus`. HTTP headers must be an iterable of ``(name, value)`` pairs. If provided, the HTTP response body must be :class:`bytes`. (:class:`~http.HTTPStatus` was added in Python 3.5. Use a compatible object on earlier versions. Look at ``SWITCHING_PROTOCOLS`` in ``websockets.compatibility`` for an example.) This method may be overridden to check the request headers and set a different status, for example to authenticate the request and return ``HTTPStatus.UNAUTHORIZED`` or ``HTTPStatus.FORBIDDEN``. It is declared as a coroutine because such authentication checks are likely to require network requests. """ status_code = HTTPStatus(200) headers = get_headers() body = b'' if path == '/s': # socket return None # end if if path in PATHS.HTML: # main page headers['Content-type'] = 'text/html; charset=utf-8' body = read_file(PATHS.html(path)) elif path in PATHS.JS: # prettyprint.js headers['Content-type'] = 'text/javascript; charset=utf-8' body = read_file(PATHS.js(path)) elif path in PATHS.CSS: # prettyprint.js headers['Content-type'] = 'text/css; charset=utf-8' body = read_file(PATHS.css(path)) else: # 404, not found status_code = HTTPStatus(404) headers['Content-type'] = 'text/plain; charset=utf-8' body = "`" + get_quote('en') + "`\n\n" \ "The requested page was not found. Probably somebody broke something." return status_code, headers.items(), b(body)
def iterm_show_file(filename, data=None, inline=True, width="auto", height="auto", preserve_aspect_ratio=True): """ https://iterm2.com/documentation-images.html :param filename: :param data: :param inline: :param width: :param height: :param preserve_aspect_ratio: Size: - N (Number only): N character cells. - Npx (Number + px): N pixels. - N% (Number + %): N percent of the session's width or height. - auto: The image's inherent size will be used to determine an appropriate dimension. :return: """ width = str(width) if width is not None else "auto" height = str(height) if height is not None else "auto" if data is None: data = read_file_to_buffer(filename) # end if data_bytes = data.getvalue() output = "\033]1337;File=" \ "name={filename};size={size};inline={inline};" \ "preserveAspectRatio={preserve};width={width};height={height}:{data}\a\n".format( filename=n(b64encode(b(filename))), size=len(data_bytes), inline=1 if inline else 0, width=width, height=height, preserve=1 if preserve_aspect_ratio else 0, data=n(b64encode(data_bytes)), ) #sys.stdout.write(output) return output
# "view_photo": ("view_photo", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action # "view_user_photo": ("view_user_photo", [ca_user, ca_none,"<user>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action # "view_video": ("view_video", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action # "view_video_thumb": ("view_video_thumb", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action # "view": ("view", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Tries to view message contents # regex to transform the C function list of the CLI to the one for pytg (in Python, obviously) # # ^\s*(?://)?\s*\{"(.*?)", \{\s*((?:ca_(?:[a-z_A-Z]+)(?:(?:,|\s+\|)\s+)?)+)\},\s+[a-z_A-Z]+,\s+"(?:(?:\1\s*(.*?)\\t)?)(.+?)",\s+NULL}(,?)$## # replace with: # # \t"$1": ("$1", [$2,"$3"], res.success_fail, None)$5 # $4## # then # # "([_a-z]+)":\s+\("([_a-z]+)",\s+\[([a-zA-Z\.\(\)=", _]+)\],\s+(res\.\w+),\s+(None|\d+\.\d+)\),(?:\s*#\s*(.*))?## # with # # \tfunctions["$1"] = ("$2", [$3], $4, $5, "$6"## _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Sender(object): """ Provides wrappers for the CLI commands. The functions are generated dynamically. They can be inspected with the help() command. If you need to see their resulting cli command syntax, you can have a look in the `.cli_command` string of the function. """ _do_quit = False default_answer_timeout = 1.0 # how long it should wait for a answer. DANGER: if set to None it will block! def __init__(self, host, port): """
def png_intensities(filename): return lib.png_intensities(b(filename))
def jpeg_intensities(filename): return lib.jpeg_intensities(b(filename))
from DictObject import DictObject from .utils import coroutine from . import fix_plain_output from .exceptions import ConnectionError from .fix_msg_array import fix_message import logging logger = logging.getLogger(__name__) SOCKET_SIZE = 1 << 25 BLOCK_SIZE = 256 EMPTY_UNICODE_STRING = u( "") # So we don't call it every time in the if header. EMPTY_RAW_BYTE = b("") # So we don't call it every time in the if header. _REGISTER_SESSION = b("main_session\n") _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Receiver(object): """ Start telegram client somewhere. $ ./bin/telegram-cli -P 4458 -W --json Get a telegram >>> tg = Receiver() >>> tg.start() """ _do_quit = False
def stop_cli(self): """ Stop the telegram process. :return: (int) returncode of the cli process. :rtype int: """ logger.info("Closing Connections.") logger.debug("Closing sender.") if self.sender: self.sender.terminate( ) # not let the cli end close first -> avoid bind: port already in use. logger.debug("Closing sender.") if self.receiver: self.receiver.stop() logger.info("Asking to CLI to stop.") if self._proc is not None: if self.sender.do_quit: logger.debug( "Sender already stopped. Unable to issue safe_quit or quit to exit via socket." ) else: try: self.sender.safe_quit() except (NoResponse, IllegalResponseException, AssertionError): logger.debug("safe_quit Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("safe_quit did not terminate.") try: self.sender.quit() except (NoResponse, IllegalResponseException, AssertionError): logger.debug("quit Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("quit did not terminate.") self.sender.stop( ) # quit and safe quit are done, we don't need the sender any longer. # end if-else: self.sender._do_quit if self._check_stopped(): return self._proc.returncode # has not terminated yet. self._proc.communicate( b('quit\n')) # report this error in the bugtracker! if self._check_stopped(): return self._proc.returncode try: self._proc.terminate() except Exception as e: # todo: ProcessLookupError does not exist before python 3 logger.debug("terminate Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("terminate did not terminate.") try: self._proc.kill() except Exception as e: # todo: ProcessLookupError does not exist before python 3 logger.debug("kill Exception", exc_info=True) if self._check_stopped(): return self._proc.returncode logger.debug("kill did not terminate.") logger.warn( "CLI kinda didn't die... Will wait (block) for termination.") self._proc.wait() self._check_stopped() return self._proc.returncode else: logger.warn("No CLI running.") raise AssertionError("No CLI running.")
def download_song(self, song_id, requested_type="mp3", cover_as_file=False): ### Prepare/Get Meta ### requested_type = u(requested_type) if self and isinstance(self, PonyFM) and self.session: json = get_json(API_URL.format(songid=song_id), cookies=self.session.cookies, verify=False) else: json = get_json(API_URL.format(songid=song_id), verify=False) ### FILE Download ### download_src = None if "formats" in json.track: for download_format in json.track.formats: logger.debug("Found {extension} download.".format( extension=download_format.extension)) if u(download_format.extension) == requested_type: download_src = download_format.url logger.debug("Got what we need. Skipping rest.") break #end if #end for #end if if download_src is None: # not found > try streams if int(json.track.is_downloadable) != 1: logger.warn( "Song is marked as 'not downloadable'! The downloaded stream might be bad quality!" ) else: logger.warn( "Did not found the requested download type, searching in the stream formats. They might be bad quality!" ) #end if for extension, url in json.track.streams.items( ): # for python 2 this should use iteritems() ... but meh. logger.debug( "Found {extension} stream.".format(extension=extension)) if u(extension) == requested_type: logger.debug("Got what we need. Skipping rest.") download_src = url break else: # neither dl, nor streams > ERROR! logger.error( "Did not (at all) found requested type ({requested_type})!" .format(requested_type=requested_type)) raise AssertionError( "Could not find download.") # TODO: custom DL Exception #end for-else #end if assert (download_src is not None) # Got download link. # Now Download song. if self and isinstance(self, PonyFM) and self.session: file_path, file_mime = download_file(download_src, temp_folder_name=SHORT_NAME, return_mime=True, progress_bar=True, cookies=self.session.cookies, verify=False) else: file_path, file_mime = download_file(download_src, temp_folder_name=SHORT_NAME, return_mime=True, progress_bar=True, verify=False) logger.info("Downloaded mp3 from '{url}' to '{path}'".format( url=download_src, path=file_path)) if u(file_mime) not in [u("audio/mp3"), u("audio/mpeg")]: raise AssertionError("mp3 is not mp3..") # TODO: custom exception else: extension = "mp3" # very dynamic, such future-prove! ### META ### audiofile = eyed3.load(file_path) if audiofile.tag is None: audiofile.initTag() artist = u(json.track.user.name) logger.debug("") if not audiofile.tag.title: logger.debug("Title was empty.") audiofile.tag.title = u(json.track.title) overwrite_if_not(audiofile.tag, "artist", artist) overwrite_if_not(audiofile.tag, "audio_file_url", u("https://github.com/luckydonald/pon3downloader/")) overwrite_if_not(audiofile.tag, "artist_url", u(json.track.user.url)) overwrite_if_not(audiofile.tag, "genre", u(json.track.genre.name)) overwrite_if_not(audiofile.tag, "lyrics", [u(json.track.lyrics)]) overwrite_if_not(audiofile.tag, "audio_source_url", u(json.track.url)) #if audiofile.tag.comments.get(u""): # text = audiofile.tag.comments.get(u"").text # text += u("\n-----\nDownloaded from https://pony.fm/ with Pon3Downloader (https://github.com/luckydonald/pon3downloader/).") # audiofile.tag.comments.set(text) #else: audiofile.tag.comments.set( u("Downloaded from {track_url} with Pon3Downloader (https://github.com/luckydonald/pon3downloader/)" .format(track_url=json.track.url))) audiofile.tag.comments.set( u("https://github.com/luckydonald/pon3downloader"), u("Downloader")) audiofile.tag.save() ### COVER ART ### if self and isinstance(self, PonyFM) and self.session: imageData, imageMine = download_file(json.track.covers.normal, return_mime=True, return_buffer=True, progress_bar=True, cookies=self.session.cookies, verify=False) else: imageData, imageMine = download_file(json.track.covers.normal, return_mime=True, return_buffer=True, progress_bar=True, verify=False) imageType = eyed3.id3.frames.ImageFrame.FRONT_COVER audiofile.tag.images.set(imageType, imageData, b(imageMine), description=u(" ")) ### SAVE ### audiofile.tag.save() logger.debug("wrote file meta.") new_file_name = "{artist} - {title}".format(artist=artist, title=json.track.title) new_file_name = do_a_filename(new_file_name) music_file_name = new_file_name + "." + extension logger.info( "Renaming to '{filename}'".format(filename=music_file_name)) file_folder = os.path.dirname(file_path) music_file_path = os.path.join(file_folder, music_file_name) logger.debug( "Full new path will be '{path}'.".format(path=music_file_path)) os.rename(file_path, music_file_path) if cover_as_file: logger.debug("Trying also writing the cover file.") cover_file_name = new_file_name + guess_extension(imageMine) cover_file_path = os.path.join(file_folder, cover_file_name) with open(cover_file_path, mode="wb+") as cover_file: cover_file.write(imageData) ### FAVE ### if json.track.user_data: if json.track.user_data.is_favourited == 0: if self and isinstance(self, PonyFM) and self.session and self.token: logger.debug("Favouriting it now.") self.toggle_fave(json.track.id) else: logger.debug("User is not logged in.") else: logger.info("Song already is favorite.") return music_file_path
#"view_photo": ("view_photo", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action #"view_user_photo": ("view_user_photo", [ca_user, ca_none,"<user>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action #"view_video": ("view_video", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action #"view_video_thumb": ("view_video_thumb", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Downloads file to downloads dirs. Then tries to open it with system default action #"view": ("view", [ca_number, ca_none,"<msg-id>"], res.success_fail, None), # Tries to view message contents # regex to transform the C function list of the CLI to the one for pytg (in Python, obviously) ##^\s*(?://)?\s*\{"(.*?)", \{\s*((?:ca_(?:[a-z_A-Z]+)(?:(?:,|\s+\|)\s+)?)+)\},\s+[a-z_A-Z]+,\s+"(?:(?:\1\s*(.*?)\\t)?)(.+?)",\s+NULL}(,?)$## # replace with: ##\t"$1": ("$1", [$2,"$3"], res.success_fail, None)$5 # $4## # then ##"([_a-z]+)":\s+\("([_a-z]+)",\s+\[([a-zA-Z\.\(\)=", _]+)\],\s+(res\.\w+),\s+(None|\d+\.\d+)\),(?:\s*#\s*(.*))?## # with ##\tfunctions["$1"] = ("$2", [$3], $4, $5, "$6"## _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Sender(object): """ Provides wrappers for the CLI commands. The functions are generated dynamically. They can be inspected with the help() command. If you need to see their resulting cli command syntax, you can have a look in the `.cli_command` string of the function. """ _do_quit = False default_answer_timeout = 1.0 # how long it should wait for a answer. DANGER: if set to None it will block! def __init__(self, host, port): """
def create_automatic_documentation(filename="DOCUMENTATION.md"): import os with open(filename, mode="w") as docu_file: print("Writing to {path}".format(path=os.path.abspath(docu_file.name))) docu_file.write(b(_create_markdown_documentation()))
def download_song(self, song_id, requested_type="mp3", cover_as_file=False): ### Prepare/Get Meta ### requested_type = u(requested_type) if self and isinstance(self, PonyFM) and self.session: json = get_json(API_URL.format(songid=song_id), cookies=self.session.cookies, verify=False) else: json = get_json(API_URL.format(songid=song_id), verify=False) ### FILE Download ### download_src = None if "formats" in json.track: for download_format in json.track.formats: logger.debug("Found {extension} download.".format(extension=download_format.extension)) if u(download_format.extension) == requested_type: download_src = download_format.url logger.debug("Got what we need. Skipping rest.") break #end if #end for #end if if download_src is None: # not found > try streams if int(json.track.is_downloadable) != 1: logger.warn("Song is marked as 'not downloadable'! The downloaded stream might be bad quality!") else: logger.warn("Did not found the requested download type, searching in the stream formats. They might be bad quality!") #end if for extension, url in json.track.streams.items(): # for python 2 this should use iteritems() ... but meh. logger.debug("Found {extension} stream.".format(extension=extension)) if u(extension) == requested_type: logger.debug("Got what we need. Skipping rest.") download_src = url break else: # neither dl, nor streams > ERROR! logger.error("Did not (at all) found requested type ({requested_type})!".format(requested_type=requested_type)) raise AssertionError("Could not find download.") # TODO: custom DL Exception #end for-else #end if assert(download_src is not None) # Got download link. # Now Download song. if self and isinstance(self, PonyFM) and self.session: file_path, file_mime = download_file(download_src, temp_folder_name=SHORT_NAME, return_mime=True, progress_bar=True, cookies=self.session.cookies, verify=False) else: file_path, file_mime = download_file(download_src, temp_folder_name=SHORT_NAME, return_mime=True, progress_bar=True, verify=False) logger.info("Downloaded mp3 from '{url}' to '{path}'".format(url=download_src, path=file_path)) if u(file_mime) not in [u("audio/mp3"),u("audio/mpeg")]: raise AssertionError("mp3 is not mp3..") # TODO: custom exception else: extension = "mp3" # very dynamic, such future-prove! ### META ### audiofile = eyed3.load(file_path) if audiofile.tag is None: audiofile.initTag() artist = u(json.track.user.name) logger.debug("") if not audiofile.tag.title: logger.debug("Title was empty.") audiofile.tag.title = u(json.track.title) overwrite_if_not(audiofile.tag, "artist", artist) overwrite_if_not(audiofile.tag, "audio_file_url", u("https://github.com/luckydonald/pon3downloader/")) overwrite_if_not(audiofile.tag, "artist_url", u(json.track.user.url)) overwrite_if_not(audiofile.tag, "genre", u(json.track.genre.name)) overwrite_if_not(audiofile.tag, "lyrics", [u(json.track.lyrics)]) overwrite_if_not(audiofile.tag, "audio_source_url", u(json.track.url)) #if audiofile.tag.comments.get(u""): # text = audiofile.tag.comments.get(u"").text # text += u("\n-----\nDownloaded from https://pony.fm/ with Pon3Downloader (https://github.com/luckydonald/pon3downloader/).") # audiofile.tag.comments.set(text) #else: audiofile.tag.comments.set(u("Downloaded from {track_url} with Pon3Downloader (https://github.com/luckydonald/pon3downloader/)".format(track_url = json.track.url))) audiofile.tag.comments.set(u("https://github.com/luckydonald/pon3downloader"), u("Downloader")) audiofile.tag.save() ### COVER ART ### if self and isinstance(self, PonyFM) and self.session: imageData, imageMine = download_file(json.track.covers.normal, return_mime=True, return_buffer=True, progress_bar=True, cookies=self.session.cookies, verify=False) else: imageData, imageMine = download_file(json.track.covers.normal, return_mime=True, return_buffer=True, progress_bar=True, verify=False) imageType = eyed3.id3.frames.ImageFrame.FRONT_COVER audiofile.tag.images.set(imageType, imageData, b(imageMine), description=u(" ")) ### SAVE ### audiofile.tag.save() logger.debug("wrote file meta.") new_file_name = "{artist} - {title}".format(artist=artist,title=json.track.title) new_file_name = do_a_filename(new_file_name) music_file_name = new_file_name + "." + extension logger.info("Renaming to '{filename}'".format(filename=music_file_name)) file_folder = os.path.dirname(file_path) music_file_path = os.path.join(file_folder, music_file_name) logger.debug("Full new path will be '{path}'.".format(path=music_file_path)) os.rename(file_path, music_file_path) if cover_as_file: logger.debug("Trying also writing the cover file.") cover_file_name = new_file_name + guess_extension(imageMine) cover_file_path = os.path.join(file_folder, cover_file_name) with open(cover_file_path, mode="wb+") as cover_file: cover_file.write(imageData) ### FAVE ### if json.track.user_data: if json.track.user_data.is_favourited == 0: if self and isinstance(self, PonyFM) and self.session and self.token: logger.debug("Favouriting it now.") self.toggle_fave(json.track.id) else: logger.debug("User is not logged in.") else: logger.info("Song already is favorite.") return music_file_path
table_string = "\n".join(rows) print("TABLE:\n") print(table_string) from luckydonaldUtils.interactions import confirm from luckydonaldUtils.encoding import to_binary as b if confirm('save as file & open in browser?'): import tempfile import webbrowser from html import escape with tempfile.NamedTemporaryFile(suffix='.html', delete=False) as f: f.write(b("<pre>")) f.write(b(escape(table_string))) f.write(b("</pre>")) f.flush() print(f.name) webbrowser.open('file://'+f.name) # end with # end if possibilities = permutations(funcs.keys(), len(funcs)) #for order in possibilities: """
def _do_send(self, command, answer_timeout=default_answer_timeout, retry_connect=2): """ You can force retry with retry_connect=2 (3 tries, default settings, first try + 2 retries) retry_connect=0 , retry_connect=False and retry_connect=None means not to retry, retry_connect=True or retry_connect= -1 means to retry infinite times. :type command: builtins.str :type answer_timeout: builtins.float or builtins.int :param retry_connect: How often the initial connection should be retried. default: 2. Negative number means infinite. :type retry_connect: int :return: """ if isinstance(retry_connect, int): pass # correct elif isinstance(retry_connect, bool): if retry_connect: # True = forever retry_connect = -1 else: retry_connect = 0 elif retry_connect is None: retry_connect = 0 # not forever. else: raise ValueError("retry_connect is not type int, bool or None.") retry_connect_original = retry_connect if not isinstance(command, (text_type, binary_type)): raise TypeError("Command to send is not a unicode(?) string. (Instead of %s you used %s.) " % (str(text_type), str(type(command)))) logger.debug("Sending command >%s<" % n(command)) with self._socked_used: while not self._do_quit: if self.s: self.s.close() self.s = None self.s = socket.socket() try: self.s.connect((self.host, self.port_out)) except socket_error as error: self.s.close() if error.errno == ECONNREFUSED and not self._do_quit: if retry_connect != 0: sleep(1) if retry_connect > 0: retry_connect -= 1 continue else: raise ConnectionError("Could not establish connection to the cli port, failed after {number} tries. (called with retry_connect={retry_connect})".format(number=(retry_connect_original + 1), retry_connect=retry_connect_original)) raise error # Not the error we are looking for, re-raise except Exception as error: self.s.close() raise error logger.debug("Socket Connected.") try: self.s.sendall(b(command)) except Exception as error: self.s.close() raise error # retry? logger.debug("All Sent.") completed = -1 # -1 = answer size yet unknown, >0 = got remaining answer size buffer = b("") self.s.settimeout(answer_timeout) # in seconds. while completed != 0: try: while 1: # retry if CTRL+C'd try: answer = self.s.recv(1) # recv() returns an empty string if the remote end is closed if len(answer) == 0: raise ConnectionError("Remote end closed") break except socket_error as err: if err.errno != EINTR: raise else: logger.exception("Uncatched exception in reading answer from cli.") self.s.settimeout(max(self.default_answer_timeout, answer_timeout)) # in seconds. # If there was input the input is now either the default one or the given one, which waits longer. buffer += answer if completed < -1 and buffer[:len(_ANSWER_SYNTAX)] != _ANSWER_SYNTAX[:len(buffer)]: raise ArithmeticError("Server response does not fit.") if completed <= -1 and buffer.startswith(_ANSWER_SYNTAX) and buffer.endswith(_LINE_BREAK): completed = int(n(buffer[7:-1])) # TODO regex. buffer = b("") completed -= 1 except ConnectionError: self.s.close() raise except socket.timeout: raise NoResponse(command) except KeyboardInterrupt: logger.exception("Exception while reading the Answer for \"%s\". Got so far: >%s< of %i\n" % (n(command), n(buffer), completed)) # TODO remove me self.s.close() raise except Exception: logger.exception("Exception while reading the Answer for \"%s\". Got so far: >%s<\n" % (n(command), n(buffer))) # TODO remove me self.s.close() raise # raise error # end while completed != 0 if self.s: self.s.close() self.s = None return u(buffer) # end while not self._do_quit # end with lock if self.s: self.s.close()
import threading from collections import deque from DictObject import DictObject from luckydonaldUtils.logger import logging from luckydonaldUtils.encoding import to_binary as b from luckydonaldUtils.encoding import to_native as n import socket from ..messages import Message from ..dockerus import ServiceInfos __author__ = 'luckydonald' logger = logging.getLogger(__name__) _EMPTY_RAW_BYTE = b("") _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Receiver(object): _queue = deque() _new_messages = threading.Semaphore(0) _queue_access = threading.Lock() def __init__(self): self._do_quit = False self.s = None # socket self.client = None # end def
from DictObject import DictObject from .utils import coroutine from . import fix_plain_output from .exceptions import ConnectionError from .fix_msg_array import fix_message __author__ = 'luckydonald' logger = logging.getLogger(__name__) SOCKET_SIZE = 1 << 25 BLOCK_SIZE = 256 EMPTY_UNICODE_STRING = u("") # So we don't call it every time in the if header. EMPTY_RAW_BYTE = b("") # So we don't call it every time in the if header. _REGISTER_SESSION = b("main_session\n") _ANSWER_SYNTAX = b("ANSWER ") _LINE_BREAK = b("\n") class Receiver(object): """ Start telegram client somewhere. $ ./bin/telegram-cli -P 4458 -W --json Get a telegram >>> tg = Receiver() >>> tg.start() """ _do_quit = False
def _do_send(self, command, answer_timeout=default_answer_timeout, retry_connect=2): """ You can force retry with retry_connect=2 (3 tries, default settings, first try + 2 retries) retry_connect=0 , retry_connect=False and retry_connect=None means not to retry, retry_connect=True or retry_connect= -1 means to retry infinite times. :type command: builtins.str :type answer_timeout: builtins.float or builtins.int :param retry_connect: How often the initial connection should be retried. default: 2. Negative number means infinite. :type retry_connect: int :return: """ if isinstance(retry_connect, int): pass # correct elif isinstance(retry_connect, bool): if retry_connect: # True = forever retry_connect = -1 else: retry_connect = 0 elif retry_connect is None: retry_connect = 0 # not forever. else: raise ValueError("retry_connect is not type int, bool or None.") retry_connect_original = retry_connect if not isinstance(command, (text_type, binary_type)): raise TypeError( "Command to send is not a unicode(?) string. (Instead of %s you used %s.) " % (str(text_type), str(type(command)))) logger.debug("Sending command >%s<" % n(command)) with self._socked_used: while not self._do_quit: if self.s: self.s.close() self.s = None self.s = socket.socket() try: self.s.connect((self.host, self.port_out)) except socket_error as error: self.s.close() if error.errno == ECONNREFUSED and not self._do_quit: if retry_connect != 0: sleep(1) if retry_connect > 0: retry_connect -= 1 continue else: raise ConnectionError( "Could not establish connection to the cli port, failed after {number} tries. (called with retry_connect={retry_connect})" .format(number=(retry_connect_original + 1), retry_connect=retry_connect_original)) raise error # Not the error we are looking for, re-raise except Exception as error: self.s.close() raise error logger.debug("Socket Connected.") try: self.s.sendall(b(command)) except Exception as error: self.s.close() raise error #retry? logger.debug("All Sent.") completed = -1 # -1 = answer size yet unknown, >0 = got remaining answer size buffer = b("") self.s.settimeout(answer_timeout) # in seconds. while completed != 0: try: while 1: #retry if CTRL+C'd try: answer = self.s.recv(1) # recv() returns an empty string if the remote end is closed if len(answer) == 0: raise ConnectionError("Remote end closed") break except socket_error as err: if err.errno != EINTR: raise else: logger.exception( "Uncatched exception in reading answer from cli." ) self.s.settimeout( max(self.default_answer_timeout, answer_timeout)) # in seconds. # If there was input the input is now either the default one or the given one, which waits longer. buffer += answer if completed < -1 and buffer[:len( _ANSWER_SYNTAX)] != _ANSWER_SYNTAX[:len(buffer )]: raise ArithmeticError( "Server response does not fit.") if completed <= -1 and buffer.startswith( _ANSWER_SYNTAX) and buffer.endswith( _LINE_BREAK): completed = int(n(buffer[7:-1])) #TODO regex. buffer = b("") completed -= 1 except ConnectionError: self.s.close() raise except socket.timeout: raise NoResponse(command) except KeyboardInterrupt as error: logger.exception( "Exception while reading the Answer for \"%s\". Got so far: >%s< of %i\n" % (n(command), n(buffer), completed)) # TODO remove me self.s.close() raise except Exception as error: logger.exception( "Exception while reading the Answer for \"%s\". Got so far: >%s<\n" % (n(command), n(buffer))) #TODO remove me self.s.close() raise #raise error # end while completed != 0 if self.s: self.s.close() self.s = None return u(buffer) # end while not self._do_quit # end with lock if self.s: self.s.close()
def short_custom_base64_url_encode(string, encode_replacements=REPLACEMENTS): base = n(urlsafe_b64encode(b(string))).rstrip("=") return multi_replace(base, encode_replacements)