import os import time # pylint: disable=import-error import win32pipe import win32file import winerror import pywintypes import win32event TIMEOUT = 100 DEFAULT_BUFLEN = 4096 CLIENT_MESSAGES = [ 'STATUS', 'REGISTER_PATH', 'UNREGISTER_PATH', 'UPDATE_VIEW', 'GET_STRINGS', 'STRING', 'VERSION', 'SHARE', 'GET_MENU_ITEMS', 'MENU_ITEM', ] def get_pipe_path(): pipename = r'\\.\\pipe\\' pipename = os.path.join(pipename, 'openCloud-' + os.getenv('USERNAME')) return pipename class WinPipeConnect: def __init__(self): self.connected = False self._pipe = None self._remainder = ''.encode('utf-8') self._overlapped = pywintypes.OVERLAPPED() self._overlapped.hEvent = win32event.CreateEvent(None, 1, 0, None) self.connect_to_pipe_server() def connect_to_pipe_server(self): try: pipename = get_pipe_path() self._pipe = win32file.CreateFile( pipename, win32file.GENERIC_READ | win32file.GENERIC_WRITE, 0, None, win32file.OPEN_EXISTING, win32file.FILE_FLAG_OVERLAPPED, None, ) if self._pipe == win32file.INVALID_HANDLE_VALUE: win32pipe.CloseHandle(self._pipe) raise OSError('Invalid _pipe value') self.connected = True except Exception as e: # pylint: disable=broad-except print(f'Could not connect to named pipe {pipename}\n' + str(e)) win32file.CloseHandle(self._pipe) def sendCommand(self, cmd): # pylint: disable=invalid-name if self.connected: w_res, _ = win32file.WriteFile( self._pipe, cmd.encode('utf-8'), self._overlapped ) if w_res == winerror.ERROR_IO_PENDING: res = win32event.WaitForSingleObject(self._overlapped.hEvent, TIMEOUT) if res != win32event.WAIT_OBJECT_0: print('Sending timed out!') return False if not win32file.GetOverlappedResult( self._pipe, self._overlapped, False ): print('GetOverlappedResult failed') return False else: print('Cannot send, not connected!') return False return True # Reads data that becomes available. # New responses can be accessed with get_available_responses(). def read_socket_data_with_timeout(self, timeout): messages = b'' start_time = time.time() while True: # pylint: disable=too-many-nested-blocks if (time.time() - start_time) >= timeout: self._remainder += messages break peek_bytes = win32pipe.PeekNamedPipe(self._pipe, DEFAULT_BUFLEN)[1] if isinstance(peek_bytes, int) and peek_bytes > 0: _, message_mem = win32file.ReadFile( self._pipe, DEFAULT_BUFLEN, self._overlapped ) if message_mem: m_bytes = bytes(message_mem) if b'\n' in m_bytes: for m in m_bytes.split(b'\n'): try: # append decodable and client specific bytes m.decode('utf-8') start = m.split(b':', 1)[0] if start.decode('utf-8') in CLIENT_MESSAGES: messages += m + b'\n' except: pass else: res = win32event.WaitForSingleObject( self._overlapped.hEvent, int(timeout * 1000) ) if res != win32event.WAIT_OBJECT_0: print('Reading timed out!') return False if not win32file.GetOverlappedResult( self._pipe, self._overlapped, False ): return False return True # Parses response lines out of collected data, returns list of strings def get_available_responses(self): if (end := self._remainder.rfind(b'\n')) == -1: return [] data = self._remainder[:end] self._remainder = self._remainder[end + 1 :] return data.decode('utf-8').split('\n') def close_conn(self): win32file.CloseHandle(self._pipe)