mirror of
https://github.com/SantaSpeen/winConnect.git
synced 2026-05-20 16:50:13 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eed17d6ced | |||
| 82b33111cc | |||
| 313a842573 | |||
| 13dc23c5d8 | |||
| 8a88783ef5 | |||
| bb7d9d6813 | |||
| ea520cd8e4 | |||
| 09280de4e4 |
Generated
+1
-1
@@ -3,5 +3,5 @@
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (winConnect)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (winConnect)" project-jdk-type="Python SDK" />
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (winConnect)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
@@ -3,8 +3,20 @@ Communicate Client-Server via Windows NamedPipe
|
||||
|
||||
## ToDo:
|
||||
|
||||
- [x] Add support for sending and receiving data (0.1.0)
|
||||
- [x] Add support for safe closing (0.9.0)
|
||||
- [x] Basic class structure
|
||||
- [x] WinConnectBase (0.1.0)
|
||||
- [ ] WinConnectNamedPipe
|
||||
- [ ] WinConnectTCPSocket
|
||||
- [x] WinConnectDaemon (0.1.0)
|
||||
- [x] WinConnectClient (0.1.0)
|
||||
- [x] NamedPipe support: (Windows Only)
|
||||
- [x] Using pywin32pipe (0.1.0)
|
||||
- [x] Add support for sending and receiving data (0.1.0)
|
||||
- [x] Add support for safe closing (0.9.0)
|
||||
- [ ] TPCSocket support: (Universal)
|
||||
- [ ] Using socket
|
||||
- [ ] Add support for sending and receiving data
|
||||
- [ ] Add support for safe closing
|
||||
- [x] Add support for other header settings (0.9.0)
|
||||
- [x] Add logging (0.9.1)
|
||||
- [x] Send data in chunks (if data is too large) (0.9.3)
|
||||
@@ -17,16 +29,16 @@ Communicate Client-Server via Windows NamedPipe
|
||||
|
||||
## Description
|
||||
|
||||
This is a simple client-server communication system for Windows. The client and server communicate via a named pipe. The client sends a message to the server, and the server responds with a message. The client and server can be run on the same machine or on different machines.
|
||||
This is a simple client-server communication system.
|
||||
The client and server communicate via a named pipe (or TCP Socket).
|
||||
The server listens for incoming messages from clients and sends a response.
|
||||
|
||||
## Installation
|
||||
|
||||
To install the package, use the following command:
|
||||
|
||||
```bash
|
||||
|
||||
pip install winConnect
|
||||
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -38,15 +50,15 @@ You can find examples in the [examples](examples) directory.
|
||||
The server is a daemon that listens for incoming messages from clients. The server can be run on the same machine as the client or on a different machine. To run the server, use the following command:
|
||||
|
||||
```python
|
||||
from winConnect import WinConnectDaemon
|
||||
from winConnect import WinConnectServer
|
||||
|
||||
connector = WinConnectDaemon('test') # test - name of the pipe
|
||||
connector = WinConnectServer('test') # test - name of the pipe
|
||||
|
||||
for data in connector.listen():
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
from winConnect import WinConnectClient
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
|
||||
def console():
|
||||
with connector as conn:
|
||||
while True:
|
||||
i = input(":> ")
|
||||
if i == "exit":
|
||||
break
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
console()
|
||||
@@ -1,17 +0,0 @@
|
||||
from winConnect import WinConnectClient
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
|
||||
def console():
|
||||
conn = connector.connect()
|
||||
while True:
|
||||
i = input(":> ")
|
||||
if i == "exit":
|
||||
break
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
conn.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
console()
|
||||
@@ -1,10 +0,0 @@
|
||||
from winConnect import WinConnectClient
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
|
||||
i = b'i' * 1024 * 1024
|
||||
with connector as conn:
|
||||
print(f"Sending {len(i)/1024}kb...")
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data[:9]=}; ok={data == i}")
|
||||
@@ -1,21 +0,0 @@
|
||||
from dataclasses import dataclass
|
||||
|
||||
from winConnect import WinConnectClient
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
|
||||
# Dataclass covert to json and send to server
|
||||
@dataclass
|
||||
class TestUser:
|
||||
name: str
|
||||
age: int
|
||||
|
||||
def send_data():
|
||||
i = TestUser("test", 123)
|
||||
with connector as conn:
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
send_data()
|
||||
@@ -1,27 +0,0 @@
|
||||
import uuid
|
||||
|
||||
from winConnect import WinConnectClient
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
|
||||
test_data = (
|
||||
[1, 2, 3, 4, 5], # List
|
||||
# {"test"}, # Set - Not supported
|
||||
{"test": "test"}, # Dict
|
||||
"test", # Str
|
||||
123, # Int
|
||||
123.456, # Float
|
||||
None, # None
|
||||
True, # Bool
|
||||
uuid.uuid4() # UUID; Transformed to str
|
||||
)
|
||||
|
||||
def send_data():
|
||||
with connector as conn:
|
||||
for i in test_data:
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
send_data()
|
||||
@@ -1,17 +0,0 @@
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
from winConnect import WinConnectDaemon
|
||||
|
||||
connector = WinConnectDaemon('test')
|
||||
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="DEBUG")
|
||||
|
||||
connector.set_logger(logger)
|
||||
|
||||
for data in connector.listen():
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
@@ -1,9 +0,0 @@
|
||||
from winConnect import WinConnectDaemon
|
||||
|
||||
connector = WinConnectDaemon('test')
|
||||
|
||||
for data in connector.listen():
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
@@ -1,27 +0,0 @@
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from winConnect import WinConnectClient, crypto
|
||||
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="DEBUG")
|
||||
|
||||
crypt_mode = crypto.WinConnectCryptoPassword("test_password")
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
connector.set_logger(logger)
|
||||
connector.set_crypto(crypt_mode)
|
||||
|
||||
def console():
|
||||
with connector as conn:
|
||||
while True:
|
||||
i = input(":> ")
|
||||
if i == "exit":
|
||||
break
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
console()
|
||||
@@ -1,27 +0,0 @@
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from winConnect import WinConnectClient, crypto
|
||||
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="DEBUG")
|
||||
|
||||
crypt_mode = crypto.WinConnectCryptoSimple()
|
||||
|
||||
connector = WinConnectClient('test')
|
||||
connector.set_logger(logger)
|
||||
connector.set_crypto(crypt_mode)
|
||||
|
||||
def console():
|
||||
with connector as conn:
|
||||
while True:
|
||||
i = input(":> ")
|
||||
if i == "exit":
|
||||
break
|
||||
conn.send_data(i)
|
||||
data = conn.read_pipe()
|
||||
print(f"({type(data)}) {data=}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
console()
|
||||
@@ -1,21 +0,0 @@
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from winConnect import WinConnectDaemon
|
||||
from winConnect import crypto
|
||||
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="DEBUG")
|
||||
|
||||
crypt_mode = crypto.WinConnectCryptoPassword("test_password")
|
||||
|
||||
connector = WinConnectDaemon('test')
|
||||
connector.set_logger(logger)
|
||||
connector.set_crypto(crypt_mode)
|
||||
|
||||
for data in connector.listen():
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
@@ -1,21 +0,0 @@
|
||||
import sys
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from winConnect import WinConnectDaemon
|
||||
from winConnect import crypto
|
||||
|
||||
logger.remove()
|
||||
logger.add(sys.stdout, level="DEBUG")
|
||||
|
||||
crypt_mode = crypto.WinConnectCryptoSimple()
|
||||
|
||||
connector = WinConnectDaemon('test')
|
||||
connector.set_logger(logger)
|
||||
connector.set_crypto(crypt_mode)
|
||||
|
||||
for data in connector.listen():
|
||||
print(f"({type(data)}) {data=}")
|
||||
if data is None and connector.closed:
|
||||
break
|
||||
connector.send_data(data)
|
||||
@@ -2,5 +2,4 @@
|
||||
# 12.03.2025
|
||||
pywin32==309
|
||||
ormsgpack==1.8.0
|
||||
orjson==3.10.15
|
||||
pycryptodome==3.21.0
|
||||
@@ -1,5 +1,5 @@
|
||||
from .WinConnectDaemon import WinConnectDaemon
|
||||
from .WinConnectClient import WinConnectClient
|
||||
from .connectors import named_pipe
|
||||
from .connectors import socket
|
||||
|
||||
from . import crypto
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import hashlib
|
||||
import orjson
|
||||
import json
|
||||
import logging
|
||||
import struct
|
||||
import threading
|
||||
@@ -7,14 +7,13 @@ import zlib
|
||||
from typing import Any
|
||||
|
||||
import ormsgpack
|
||||
import pywintypes
|
||||
import win32file
|
||||
|
||||
from .crypto.WinConnectCrypto import WinConnectCrypto
|
||||
from .crypto.crypto_classes import WinConnectCryptoNone
|
||||
from .errors import WinConnectErrors, WinConnectError
|
||||
from . import exceptions
|
||||
from .utils import SimpleConvertor
|
||||
from .. import exceptions
|
||||
from ..crypto.WinConnectCrypto import WinConnectCrypto
|
||||
from ..crypto.crypto_classes import WinConnectCryptoNone
|
||||
from ..errors import WinConnectErrors, WinConnectError
|
||||
from ..utils import SimpleConvertor
|
||||
|
||||
|
||||
# header: len(data) in struct.pack via header_format
|
||||
# data: action:data
|
||||
@@ -30,27 +29,29 @@ class WinConnectBase:
|
||||
|
||||
ormsgpack_options = ormsgpack.OPT_NON_STR_KEYS | ormsgpack.OPT_NAIVE_UTC | ormsgpack.OPT_PASSTHROUGH_TUPLE # ormsgpack options
|
||||
|
||||
def __init__(self, pipe_name: str):
|
||||
self._log = logging.getLogger(f"WinConnect:{pipe_name}")
|
||||
def __init__(self):
|
||||
self._log = logging.getLogger(f"WinConnectBase")
|
||||
self._log_prefix = "WinConnectBase"
|
||||
# versions:
|
||||
# 1 - 0.9.1
|
||||
# 2 - 0.9.2 (with crypto)
|
||||
# 3 - 0.9.3+ (with crypto+salt)
|
||||
self._version = 3
|
||||
self._pipe_name = r'\\.\pipe\{}'.format(pipe_name)
|
||||
self._pipe = None
|
||||
|
||||
self._sock = None
|
||||
|
||||
self._opened = False
|
||||
self._connected = False
|
||||
self._inited = False
|
||||
|
||||
self._header_format = self.init_header_format
|
||||
self._header_size = struct.calcsize(self._header_format) # bytes
|
||||
self._calc_body_max_size()
|
||||
|
||||
self._connected = False
|
||||
self._inited = False
|
||||
self._session_encoding = self.init_encoding
|
||||
|
||||
self.__crypto = WinConnectCrypto()
|
||||
self.__crypto.set_crypto_class(WinConnectCryptoNone())
|
||||
self._crypto = WinConnectCrypto()
|
||||
self._crypto.set_crypto_class(WinConnectCryptoNone())
|
||||
|
||||
self._pipe_lock = threading.Lock()
|
||||
self._read_lock = threading.Lock()
|
||||
@@ -59,14 +60,14 @@ class WinConnectBase:
|
||||
def set_crypto(self, crypto):
|
||||
if self._connected:
|
||||
raise exceptions.WinConnectConnectionAlreadyOpenException("Can't change crypto while session is active")
|
||||
self.__crypto.set_crypto_class(crypto)
|
||||
if not self.__crypto.test_and_load():
|
||||
self._crypto.set_crypto_class(crypto)
|
||||
if not self._crypto.test_and_load():
|
||||
raise exceptions.WinConnectCryptoException("Crypto failed test")
|
||||
|
||||
def set_logger(self, logger):
|
||||
logger.debug(f"[{self._pipe_name}] Update logger")
|
||||
logger.debug(f"[{self._log_prefix}] Update logger")
|
||||
self._log = logger
|
||||
self.__crypto.set_logger(logger)
|
||||
self._crypto.set_logger(logger)
|
||||
|
||||
def _calc_body_max_size(self):
|
||||
# Max size of body: struct_range - header_size - crypt_fix - action_and_data
|
||||
@@ -87,10 +88,6 @@ class WinConnectBase:
|
||||
except struct.error as e:
|
||||
raise exceptions.WinConnectStructFormatException(f"Error in struct format. ({e})")
|
||||
|
||||
@property
|
||||
def pipe_name(self):
|
||||
return self._pipe_name
|
||||
|
||||
@property
|
||||
def encoding(self):
|
||||
if not self._inited:
|
||||
@@ -111,7 +108,9 @@ class WinConnectBase:
|
||||
def __parse_message(message: bytes):
|
||||
return message.split(b":", 1)
|
||||
|
||||
def _open_pipe(self): ...
|
||||
def _open_sock(self): ...
|
||||
|
||||
def _wait_connect(self): ...
|
||||
|
||||
def __handle_send_data(self, action, data) -> bytes:
|
||||
t = type(data)
|
||||
@@ -137,22 +136,12 @@ class WinConnectBase:
|
||||
raise exceptions.WinConnectBadDataTypeException('Is client using correct lib? Unknown data type')
|
||||
return action, ready_data
|
||||
|
||||
def __raw_read(self, size):
|
||||
with self._pipe_lock:
|
||||
try:
|
||||
_, data = win32file.ReadFile(self._pipe, size)
|
||||
return data
|
||||
except pywintypes.error as e:
|
||||
if e.winerror == 109:
|
||||
exc = exceptions.WinConnectConnectionClosedException("Connection closed")
|
||||
exc.real_exc = e
|
||||
raise exc
|
||||
raise e
|
||||
def __raw_read(self, size) -> bytes: ...
|
||||
|
||||
def __read_and_decrypt(self, size):
|
||||
data = self.__raw_read(size)
|
||||
if self._inited:
|
||||
data = self.__crypto.decrypt(data)
|
||||
data = self._crypto.decrypt(data)
|
||||
return data
|
||||
|
||||
def _read_message(self) -> (str, Any):
|
||||
@@ -175,27 +164,23 @@ class WinConnectBase:
|
||||
# Read body
|
||||
data = self.__read_and_decrypt(message_size)
|
||||
action, data = self.__handle_receive_data_type(data)
|
||||
self._log.debug(f"[{self._pipe_name}] Received message: {action=} {data=}")
|
||||
self._log.debug(f"[{self._log_prefix}] Received message: {action=} {data=}")
|
||||
return action, data
|
||||
|
||||
def __raw_write(self, packet):
|
||||
with self._pipe_lock:
|
||||
if self.closed:
|
||||
raise exceptions.WinConnectSessionClosedException("Session is closed")
|
||||
win32file.WriteFile(self._pipe, packet)
|
||||
def __raw_write(self, packet): ...
|
||||
|
||||
def _send_message(self, action: str, data: Any):
|
||||
with self._write_lock:
|
||||
action = action.encode(self.encoding)
|
||||
packed_data = self.__handle_send_data(action, data)
|
||||
if self._inited:
|
||||
packed_data = self.__crypto.encrypt(packed_data)
|
||||
packed_data = self._crypto.encrypt(packed_data)
|
||||
|
||||
message_size = len(packed_data)
|
||||
if message_size > self._body_max_size:
|
||||
raise exceptions.WinConnectBaseException('Message is too big')
|
||||
|
||||
self._log.debug(f"[{self._pipe_name}] Sending message: {action=} {data=}; {message_size} {packed_data=}")
|
||||
self._log.debug(f"[{self._log_prefix}] Sending message: {action=} {data=}; {message_size} {packed_data=}")
|
||||
# Send header
|
||||
self.__raw_write(struct.pack(self.__header_settings[0], message_size))
|
||||
# Send body
|
||||
@@ -206,7 +191,7 @@ class WinConnectBase:
|
||||
self._send_message("err", e)
|
||||
|
||||
def __read_chunked_message(self, data_info: bytes):
|
||||
self._log.debug(f"[{self._pipe_name}] Receive long message. Reading in chunks...")
|
||||
self._log.debug(f"[{self._log_prefix}] Receive long message. Reading in chunks...")
|
||||
chunk_size = self._body_max_size - 32
|
||||
cdata_sha256, cdata_len = data_info[:32], int(data_info[32:])
|
||||
if cdata_len > self.read_max_buffer:
|
||||
@@ -224,7 +209,7 @@ class WinConnectBase:
|
||||
return zlib.decompress(_buffer)
|
||||
|
||||
def __send_chunked_message(self, data: bytes):
|
||||
self._log.debug(f"[{self._pipe_name}] Long message. Sending in chunks...")
|
||||
self._log.debug(f"[{self._log_prefix}] Long message. Sending in chunks...")
|
||||
chunk_size = self._body_max_size - 32
|
||||
cdata = zlib.compress(data)
|
||||
|
||||
@@ -236,7 +221,7 @@ class WinConnectBase:
|
||||
|
||||
with self._write_lock:
|
||||
for i in range(0, cdata_len, chunk_size):
|
||||
_encrypted = self.__crypto.encrypt(cdata[i:i + chunk_size])
|
||||
_encrypted = self._crypto.encrypt(cdata[i:i + chunk_size])
|
||||
self.__raw_write(_encrypted)
|
||||
|
||||
def _parse_action(self, action, data: Any) -> (bool, Any):
|
||||
@@ -267,18 +252,18 @@ class WinConnectBase:
|
||||
command, data = self.__parse_message(data)
|
||||
match command:
|
||||
case b'get_session_settings':
|
||||
self._log.debug(f"[{self._pipe_name}] Received get_session_settings from {data}")
|
||||
self._log.debug(f"[{self._log_prefix}] Received get_session_settings from {data}")
|
||||
_blank_settings['version'] = self._version
|
||||
_blank_settings['encoding'] = self._session_encoding
|
||||
_blank_settings['header_size'] = self._header_size
|
||||
_blank_settings['header_format'] = self._header_format
|
||||
_blank_settings['max_buffer'] = self.read_max_buffer
|
||||
_blank_settings['crypto'] = self.__crypto.crypt_name
|
||||
session_settings = f"set_session_settings:{len(self.__crypto.crypt_salt)}:".encode(self.encoding) + orjson.dumps(_blank_settings) + self.__crypto.crypt_salt
|
||||
_blank_settings['crypto'] = self._crypto.crypt_name
|
||||
session_settings = f"set_session_settings:{len(self._crypto.crypt_salt)}:{json.dumps(_blank_settings)}".encode(self.encoding) + self._crypto.crypt_salt
|
||||
self._send_message("cmd", session_settings)
|
||||
return True
|
||||
case b'set_session_settings':
|
||||
self._log.debug(f"[{self._pipe_name}] Received session settings.")
|
||||
self._log.debug(f"[{self._log_prefix}] Received session settings.")
|
||||
len_salt, data_salt = self.__parse_message(data)
|
||||
len_salt = int(len_salt)
|
||||
if len_salt > 0:
|
||||
@@ -286,13 +271,13 @@ class WinConnectBase:
|
||||
else:
|
||||
data, salt = data_salt, b''
|
||||
|
||||
if salt != self.__crypto.crypt_salt:
|
||||
self._log.debug(f"[{self._pipe_name}] Updating salt")
|
||||
self.__crypto.set_salt(salt)
|
||||
if salt != self._crypto.crypt_salt:
|
||||
self._log.debug(f"[{self._log_prefix}] Updating salt")
|
||||
self._crypto.set_salt(salt)
|
||||
|
||||
try:
|
||||
settings = orjson.loads(data.decode(self.init_encoding))
|
||||
except orjson.JSONDecodeError as e:
|
||||
settings = json.loads(data.decode(self.init_encoding))
|
||||
except json.JSONDecodeError as e:
|
||||
self._send_error(WinConnectErrors.BAD_DATA, f"JSONDecodeError: {e}")
|
||||
return self.close()
|
||||
|
||||
@@ -305,7 +290,7 @@ class WinConnectBase:
|
||||
self._log.error(f"{WinConnectErrors.BAD_VERSION}")
|
||||
self._send_error(WinConnectErrors.BAD_VERSION, f"Version mismatch")
|
||||
return self.close()
|
||||
if settings['crypto'] != self.__crypto.crypt_name:
|
||||
if settings['crypto'] != self._crypto.crypt_name:
|
||||
self._log.error(f"{WinConnectErrors.BAD_CRYPTO}")
|
||||
self._send_error(WinConnectErrors.BAD_CRYPTO, f"Crypto mismatch")
|
||||
return self.close()
|
||||
@@ -342,15 +327,17 @@ class WinConnectBase:
|
||||
|
||||
def _close_session(self): ...
|
||||
|
||||
def _close_pipe(self): ...
|
||||
|
||||
def close(self):
|
||||
self._close_session()
|
||||
if self._connected:
|
||||
win32file.CloseHandle(self._pipe)
|
||||
self._close_pipe()
|
||||
self._opened = False
|
||||
self._connected = False
|
||||
self._inited = False
|
||||
self._pipe = None
|
||||
self._log.debug(f"[{self._pipe_name}] Session closed")
|
||||
self._sock = None
|
||||
self._log.debug(f"[{self._log_prefix}] Session closed")
|
||||
|
||||
def _read(self) -> Any:
|
||||
if self.closed:
|
||||
@@ -0,0 +1,39 @@
|
||||
from ._base_base import WinConnectBase
|
||||
|
||||
|
||||
class WinConnectClient(WinConnectBase):
|
||||
|
||||
def __init__(self, pipe_name: str):
|
||||
super().__init__(pipe_name)
|
||||
|
||||
def _init(self, program_name="NoName"):
|
||||
self._send_message("cmd", b"get_session_settings:" + program_name.encode(self.encoding))
|
||||
self._init_session()
|
||||
|
||||
def _close_session(self):
|
||||
"""Send close command to server"""
|
||||
if not self.closed:
|
||||
self._send_message("cmd", b"close:")
|
||||
|
||||
def __check_sock(self):
|
||||
if not self._opened:
|
||||
self._open_sock()
|
||||
if not self._inited:
|
||||
self._init()
|
||||
|
||||
def __enter__(self):
|
||||
self.__check_sock()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.close()
|
||||
|
||||
def connect(self, program_name: str="NoName"):
|
||||
"""Connect to server and initialize session"""
|
||||
self._open_sock()
|
||||
self._init(program_name)
|
||||
return self
|
||||
|
||||
def read_pipe(self):
|
||||
self.__check_sock()
|
||||
return self._read()
|
||||
@@ -0,0 +1,36 @@
|
||||
import win32pipe
|
||||
|
||||
from ._base_base import WinConnectBase
|
||||
|
||||
|
||||
class WinConnectServer(WinConnectBase):
|
||||
|
||||
def __init__(self, pipe_name: str):
|
||||
super().__init__(pipe_name)
|
||||
self.run = True
|
||||
|
||||
def _close_session(self):
|
||||
self.run = False
|
||||
|
||||
def wait_client(self):
|
||||
if not self._opened:
|
||||
self._open_sock()
|
||||
self._wait_connect()
|
||||
self._connected = True
|
||||
self._log.debug(f"[{self._log_prefix}] Client connected")
|
||||
|
||||
def read_pipe(self):
|
||||
if not self._connected:
|
||||
self.wait_client()
|
||||
if not self._inited:
|
||||
self._init_session()
|
||||
return self._read()
|
||||
|
||||
def listen(self):
|
||||
while self.run:
|
||||
yield self.read_pipe()
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
self.run = False
|
||||
self.close()
|
||||
@@ -0,0 +1,2 @@
|
||||
from .client import WinConnectPipeClient
|
||||
from .server import WinConnectPipeServer
|
||||
@@ -0,0 +1,40 @@
|
||||
import logging
|
||||
|
||||
import pywintypes
|
||||
import win32file
|
||||
|
||||
from winConnect import exceptions
|
||||
from .._base_base import WinConnectBase
|
||||
|
||||
|
||||
class WinConnectNamedPipe(WinConnectBase):
|
||||
def __init__(self, pipe_name: str):
|
||||
super().__init__()
|
||||
self._log = logging.getLogger(f"WinConnectNamedPipe:{pipe_name}")
|
||||
self._pipe_name = r'\\.\pipe\{}'.format(pipe_name)
|
||||
self._sock = None
|
||||
|
||||
@property
|
||||
def pipe_path(self):
|
||||
return self._pipe_name
|
||||
|
||||
def __raw_read(self, size):
|
||||
with self._pipe_lock:
|
||||
try:
|
||||
_, data = win32file.ReadFile(self._sock, size)
|
||||
return data
|
||||
except pywintypes.error as e:
|
||||
if e.winerror == 109:
|
||||
exc = exceptions.WinConnectConnectionClosedException("Connection closed")
|
||||
exc.real_exc = e
|
||||
raise exc
|
||||
raise e
|
||||
|
||||
def __raw_write(self, packet):
|
||||
with self._pipe_lock:
|
||||
if self.closed:
|
||||
raise exceptions.WinConnectSessionClosedException("Session is closed")
|
||||
win32file.WriteFile(self._sock, packet)
|
||||
|
||||
def _close_pipe(self):
|
||||
win32file.CloseHandle(self._sock)
|
||||
@@ -1,11 +1,12 @@
|
||||
import pywintypes
|
||||
import win32file
|
||||
|
||||
from .WinConnectBase import WinConnectBase
|
||||
from .exceptions import WinConnectConnectionNoPipeException
|
||||
from winConnect.exceptions import WinConnectConnectionNoPipeException
|
||||
from ._base import WinConnectNamedPipe
|
||||
from .._base_client import WinConnectClient
|
||||
|
||||
|
||||
class WinConnectClient(WinConnectBase):
|
||||
class WinConnectPipeClient(WinConnectNamedPipe, WinConnectClient):
|
||||
# see: https://mhammond.github.io/pywin32/win32pipe__CreateNamedPipe_meth.html
|
||||
pipe_desiredAccess = win32file.GENERIC_READ | win32file.GENERIC_WRITE # Access mode (read/write)
|
||||
pipe_shareMode = 0 # Share mode (None)
|
||||
@@ -17,7 +18,7 @@ class WinConnectClient(WinConnectBase):
|
||||
def __init__(self, pipe_name: str):
|
||||
super().__init__(pipe_name)
|
||||
|
||||
def _open_pipe(self):
|
||||
def _open_sock(self):
|
||||
try:
|
||||
self._pipe = win32file.CreateFile(
|
||||
self._pipe_name,
|
||||
@@ -37,35 +38,3 @@ class WinConnectClient(WinConnectBase):
|
||||
exc.real_exc = e
|
||||
raise exc
|
||||
raise e
|
||||
|
||||
def _init(self, program_name="NoName"):
|
||||
self._send_message("cmd", b"get_session_settings:" + program_name.encode(self.encoding))
|
||||
self._init_session()
|
||||
|
||||
def _close_session(self):
|
||||
"""Send close command to server"""
|
||||
if not self.closed:
|
||||
self._send_message("cmd", b"close:")
|
||||
|
||||
def __check_pipe(self):
|
||||
if not self._opened:
|
||||
self._open_pipe()
|
||||
if not self._inited:
|
||||
self._init()
|
||||
|
||||
def __enter__(self):
|
||||
self.__check_pipe()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.close()
|
||||
|
||||
def connect(self, program_name: str="NoName"):
|
||||
"""Connect to server and initialize session"""
|
||||
self._open_pipe()
|
||||
self._init(program_name)
|
||||
return self
|
||||
|
||||
def read_pipe(self):
|
||||
self.__check_pipe()
|
||||
return self._read()
|
||||
@@ -1,9 +1,10 @@
|
||||
import win32pipe
|
||||
|
||||
from .WinConnectBase import WinConnectBase
|
||||
from ._base import WinConnectNamedPipe
|
||||
from .._base_server import WinConnectServer
|
||||
|
||||
|
||||
class WinConnectDaemon(WinConnectBase):
|
||||
class WinConnectPipeServer(WinConnectNamedPipe, WinConnectServer):
|
||||
# see: https://mhammond.github.io/pywin32/win32pipe__CreateNamedPipe_meth.html
|
||||
pipe_openMode = win32pipe.PIPE_ACCESS_DUPLEX # Open mode (read/write)
|
||||
pipe_pipeMode = win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_READMODE_MESSAGE | win32pipe.PIPE_WAIT # Pipe mode (message type, message read mode, blocking mode)
|
||||
@@ -15,12 +16,12 @@ class WinConnectDaemon(WinConnectBase):
|
||||
super().__init__(pipe_name)
|
||||
self.run = True
|
||||
|
||||
def _open_pipe(self):
|
||||
def _open_sock(self):
|
||||
pipe_nOutBufferSize, pipe_nInBufferSize = self._body_max_size+20, self._body_max_size+20
|
||||
self._log.debug(f"[{self._pipe_name}] Creating pipe. "
|
||||
f"Settings: {self.pipe_openMode=}, {self.pipe_pipeMode=}, {self.pipe_nMaxInstances=}, "
|
||||
f"{pipe_nOutBufferSize=}, {pipe_nInBufferSize=}, {self.pipe_nDefaultTimeOut=}, {self.pipe_sa=}")
|
||||
self._pipe = win32pipe.CreateNamedPipe(
|
||||
self._sock = win32pipe.CreateNamedPipe(
|
||||
self._pipe_name,
|
||||
self.pipe_openMode,
|
||||
self.pipe_pipeMode,
|
||||
@@ -33,30 +34,5 @@ class WinConnectDaemon(WinConnectBase):
|
||||
self._opened = True
|
||||
self._log.debug(f"[{self._pipe_name}] Pipe opened")
|
||||
|
||||
def _close_session(self):
|
||||
self.run = False
|
||||
|
||||
def wait_client(self):
|
||||
if not self._opened:
|
||||
self._open_pipe()
|
||||
win32pipe.ConnectNamedPipe(self._pipe, None)
|
||||
self._connected = True
|
||||
self._log.debug(f"[{self._pipe_name}] Client connected")
|
||||
|
||||
def read_pipe(self):
|
||||
if not self._connected:
|
||||
self.wait_client()
|
||||
if not self._inited:
|
||||
self._init_session()
|
||||
# if not self._read():
|
||||
# raise
|
||||
return self._read()
|
||||
|
||||
def listen(self):
|
||||
while self.run:
|
||||
yield self.read_pipe()
|
||||
self.stop()
|
||||
|
||||
def stop(self):
|
||||
self.run = False
|
||||
self.close()
|
||||
def _wait_connect(self):
|
||||
win32pipe.ConnectNamedPipe(self._sock, None)
|
||||
@@ -0,0 +1,2 @@
|
||||
from .server import WinConnectTCPServer
|
||||
from .client import WinConnectTPCClient
|
||||
@@ -0,0 +1,5 @@
|
||||
from .._base_base import WinConnectBase
|
||||
|
||||
|
||||
class WinConnectTPC(WinConnectBase):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from ._base import WinConnectTPC
|
||||
from .._base_client import WinConnectClient
|
||||
|
||||
|
||||
class WinConnectTPCClient(WinConnectTPC, WinConnectClient):
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
from ._base import WinConnectTPC
|
||||
from .._base_server import WinConnectServer
|
||||
|
||||
|
||||
class WinConnectTCPServer(WinConnectTPC, WinConnectServer):
|
||||
pass
|
||||
@@ -1,8 +1,9 @@
|
||||
import os
|
||||
import random
|
||||
from pathlib import Path
|
||||
|
||||
from winConnect.exceptions import WinConnectCryptoSimpleBadHeaderException
|
||||
from .crypto_class_base import WinConnectCryptoBase
|
||||
from winConnect.exceptions import WinConnectCryptoSimpleBadHeaderException
|
||||
|
||||
_pip_crypto = True
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user