Files
QSfera/Desktop/test/gui/helpers/WinPipeHelper.py
T
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

137 lines
4.5 KiB
Python

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)