ipc-framework 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ipc_framework/__init__.py +28 -0
- ipc_framework/client.py +274 -0
- ipc_framework/core.py +353 -0
- ipc_framework/demo.py +268 -0
- ipc_framework/examples/__init__.py +13 -0
- ipc_framework/examples/basic_server.py +209 -0
- ipc_framework/examples/chat_client.py +168 -0
- ipc_framework/examples/file_client.py +211 -0
- ipc_framework/examples/monitoring_client.py +252 -0
- ipc_framework/exceptions.py +43 -0
- ipc_framework/py.typed +2 -0
- ipc_framework/server.py +298 -0
- ipc_framework-1.0.0.dist-info/METADATA +512 -0
- ipc_framework-1.0.0.dist-info/RECORD +18 -0
- ipc_framework-1.0.0.dist-info/WHEEL +5 -0
- ipc_framework-1.0.0.dist-info/entry_points.txt +6 -0
- ipc_framework-1.0.0.dist-info/licenses/LICENSE +21 -0
- ipc_framework-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
File Sharing Client Example
|
4
|
+
|
5
|
+
This example demonstrates how to use the IPC framework for file sharing operations.
|
6
|
+
It shows request/response patterns and status monitoring.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import time
|
10
|
+
import random
|
11
|
+
import threading
|
12
|
+
from .. import FrameworkClient, Message, MessageType
|
13
|
+
|
14
|
+
|
15
|
+
class FileClient:
|
16
|
+
def __init__(self, client_name: str, host: str = "localhost", port: int = 8888):
|
17
|
+
self.client_name = client_name
|
18
|
+
self.client = FrameworkClient("file_share", host, port)
|
19
|
+
self.uploaded_files = []
|
20
|
+
|
21
|
+
def connect(self):
|
22
|
+
"""Connect to the file sharing server"""
|
23
|
+
if self.client.connect():
|
24
|
+
print(f"File client '{self.client_name}' connected")
|
25
|
+
|
26
|
+
# Subscribe to status updates
|
27
|
+
self.client.subscribe("status", self.handle_status_update)
|
28
|
+
return True
|
29
|
+
else:
|
30
|
+
print("Failed to connect to server")
|
31
|
+
return False
|
32
|
+
|
33
|
+
def handle_status_update(self, message: Message):
|
34
|
+
"""Handle file operation status updates"""
|
35
|
+
payload = message.payload
|
36
|
+
msg_type = payload.get('type', 'unknown')
|
37
|
+
|
38
|
+
if msg_type == 'upload_progress':
|
39
|
+
filename = payload.get('filename', 'unknown')
|
40
|
+
progress = payload.get('progress', 0)
|
41
|
+
status = payload.get('status', 'unknown')
|
42
|
+
print(f"[STATUS] Upload {filename}: {progress}% - {status}")
|
43
|
+
|
44
|
+
def upload_file(self, filename: str, size: int):
|
45
|
+
"""Upload a file (simulated)"""
|
46
|
+
print(f"Uploading file: {filename} ({size} bytes)")
|
47
|
+
|
48
|
+
self.client.request("upload", {
|
49
|
+
'filename': filename,
|
50
|
+
'size': size,
|
51
|
+
'client': self.client_name,
|
52
|
+
'connection_id': self.client.connection_id
|
53
|
+
})
|
54
|
+
|
55
|
+
self.uploaded_files.append(filename)
|
56
|
+
print(f"Upload request sent for {filename}")
|
57
|
+
|
58
|
+
def download_file(self, filename: str) -> bool:
|
59
|
+
"""Download a file and wait for response"""
|
60
|
+
print(f"Requesting download: {filename}")
|
61
|
+
|
62
|
+
response = self.client.send_request("download", {
|
63
|
+
'filename': filename,
|
64
|
+
'client': self.client_name,
|
65
|
+
'connection_id': self.client.connection_id
|
66
|
+
}, timeout=5.0)
|
67
|
+
|
68
|
+
if response:
|
69
|
+
payload = response.payload
|
70
|
+
download_url = payload.get('download_url', 'N/A')
|
71
|
+
expires_at = payload.get('expires_at', 0)
|
72
|
+
expires_in = int(expires_at - time.time())
|
73
|
+
|
74
|
+
print(f"Download ready:")
|
75
|
+
print(f" File: {filename}")
|
76
|
+
print(f" URL: {download_url}")
|
77
|
+
print(f" Expires in: {expires_in} seconds")
|
78
|
+
return True
|
79
|
+
else:
|
80
|
+
print(f"Download request timed out for {filename}")
|
81
|
+
return False
|
82
|
+
|
83
|
+
def list_files(self):
|
84
|
+
"""List uploaded files"""
|
85
|
+
if self.uploaded_files:
|
86
|
+
print("Uploaded files:")
|
87
|
+
for i, filename in enumerate(self.uploaded_files, 1):
|
88
|
+
print(f" {i}. {filename}")
|
89
|
+
else:
|
90
|
+
print("No files uploaded yet")
|
91
|
+
|
92
|
+
def disconnect(self):
|
93
|
+
"""Disconnect from the server"""
|
94
|
+
self.client.disconnect()
|
95
|
+
print(f"File client '{self.client_name}' disconnected")
|
96
|
+
|
97
|
+
|
98
|
+
def simulate_file_operations():
|
99
|
+
"""Simulate various file operations"""
|
100
|
+
# Create multiple clients
|
101
|
+
clients = []
|
102
|
+
for i in range(3):
|
103
|
+
client = FileClient(f"Client_{i+1}")
|
104
|
+
if client.connect():
|
105
|
+
clients.append(client)
|
106
|
+
time.sleep(0.5)
|
107
|
+
|
108
|
+
if not clients:
|
109
|
+
print("No clients could connect")
|
110
|
+
return
|
111
|
+
|
112
|
+
print(f"\n=== Starting file operations with {len(clients)} clients ===\n")
|
113
|
+
|
114
|
+
# Simulate file uploads
|
115
|
+
sample_files = [
|
116
|
+
("document.pdf", 1024000),
|
117
|
+
("image.jpg", 2048000),
|
118
|
+
("video.mp4", 50000000),
|
119
|
+
("data.csv", 512000),
|
120
|
+
("code.zip", 1536000)
|
121
|
+
]
|
122
|
+
|
123
|
+
# Each client uploads some files
|
124
|
+
for client in clients:
|
125
|
+
num_files = random.randint(1, 3)
|
126
|
+
selected_files = random.sample(sample_files, num_files)
|
127
|
+
|
128
|
+
for filename, size in selected_files:
|
129
|
+
client.upload_file(f"{client.client_name}_{filename}", size)
|
130
|
+
time.sleep(1)
|
131
|
+
|
132
|
+
time.sleep(2)
|
133
|
+
print("\n=== Upload phase completed ===\n")
|
134
|
+
|
135
|
+
# Simulate downloads
|
136
|
+
for client in clients:
|
137
|
+
print(f"\n--- {client.client_name} downloads ---")
|
138
|
+
client.list_files()
|
139
|
+
|
140
|
+
# Try to download some files
|
141
|
+
for other_client in clients:
|
142
|
+
if other_client != client and other_client.uploaded_files:
|
143
|
+
file_to_download = random.choice(other_client.uploaded_files)
|
144
|
+
success = client.download_file(file_to_download)
|
145
|
+
time.sleep(1)
|
146
|
+
|
147
|
+
print("\n=== File operations completed ===")
|
148
|
+
|
149
|
+
# Disconnect all clients
|
150
|
+
for client in clients:
|
151
|
+
client.disconnect()
|
152
|
+
|
153
|
+
|
154
|
+
def interactive_mode():
|
155
|
+
"""Run in interactive mode"""
|
156
|
+
client_name = input("Enter client name: ").strip() or "InteractiveClient"
|
157
|
+
client = FileClient(client_name)
|
158
|
+
|
159
|
+
if not client.connect():
|
160
|
+
return
|
161
|
+
|
162
|
+
print("\n=== File Sharing Client ===")
|
163
|
+
print("Commands:")
|
164
|
+
print(" upload <filename> <size> - Upload a file")
|
165
|
+
print(" download <filename> - Download a file")
|
166
|
+
print(" list - List uploaded files")
|
167
|
+
print(" quit - Exit")
|
168
|
+
|
169
|
+
try:
|
170
|
+
while True:
|
171
|
+
command = input(f"\n[{client_name}] > ").strip().split()
|
172
|
+
|
173
|
+
if not command:
|
174
|
+
continue
|
175
|
+
|
176
|
+
cmd = command[0].lower()
|
177
|
+
|
178
|
+
if cmd == 'quit':
|
179
|
+
break
|
180
|
+
elif cmd == 'upload' and len(command) >= 3:
|
181
|
+
filename = command[1]
|
182
|
+
try:
|
183
|
+
size = int(command[2])
|
184
|
+
client.upload_file(filename, size)
|
185
|
+
except ValueError:
|
186
|
+
print("Invalid size. Please enter a number.")
|
187
|
+
elif cmd == 'download' and len(command) >= 2:
|
188
|
+
filename = command[1]
|
189
|
+
client.download_file(filename)
|
190
|
+
elif cmd == 'list':
|
191
|
+
client.list_files()
|
192
|
+
else:
|
193
|
+
print("Invalid command or missing arguments")
|
194
|
+
|
195
|
+
except KeyboardInterrupt:
|
196
|
+
pass
|
197
|
+
finally:
|
198
|
+
client.disconnect()
|
199
|
+
|
200
|
+
|
201
|
+
def main():
|
202
|
+
import sys
|
203
|
+
|
204
|
+
if len(sys.argv) > 1 and sys.argv[1] == 'sim':
|
205
|
+
simulate_file_operations()
|
206
|
+
else:
|
207
|
+
interactive_mode()
|
208
|
+
|
209
|
+
|
210
|
+
if __name__ == "__main__":
|
211
|
+
main()
|
@@ -0,0 +1,252 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
Monitoring Client Example
|
4
|
+
|
5
|
+
This example demonstrates how to use the IPC framework for system monitoring.
|
6
|
+
It shows metrics reporting and alert subscription patterns.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import time
|
10
|
+
import random
|
11
|
+
import threading
|
12
|
+
from .. import FrameworkClient, Message, MessageType
|
13
|
+
|
14
|
+
try:
|
15
|
+
import psutil
|
16
|
+
HAS_PSUTIL = True
|
17
|
+
except ImportError:
|
18
|
+
HAS_PSUTIL = False
|
19
|
+
|
20
|
+
|
21
|
+
class MonitoringClient:
|
22
|
+
def __init__(self, client_name: str, host: str = "localhost", port: int = 8888):
|
23
|
+
self.client_name = client_name
|
24
|
+
self.client = FrameworkClient("monitoring", host, port)
|
25
|
+
self.running = False
|
26
|
+
self.metrics_thread = None
|
27
|
+
|
28
|
+
def connect(self):
|
29
|
+
"""Connect to the monitoring server"""
|
30
|
+
if self.client.connect():
|
31
|
+
print(f"Monitoring client '{self.client_name}' connected")
|
32
|
+
|
33
|
+
# Subscribe to alerts
|
34
|
+
self.client.subscribe("alerts", self.handle_alert)
|
35
|
+
return True
|
36
|
+
else:
|
37
|
+
print("Failed to connect to server")
|
38
|
+
return False
|
39
|
+
|
40
|
+
def handle_alert(self, message: Message):
|
41
|
+
"""Handle system alerts"""
|
42
|
+
payload = message.payload
|
43
|
+
alert_type = payload.get('type', 'unknown')
|
44
|
+
|
45
|
+
if alert_type == 'high_cpu_alert':
|
46
|
+
metric = payload.get('metric', 'unknown')
|
47
|
+
value = payload.get('value', 0)
|
48
|
+
threshold = payload.get('threshold', 0)
|
49
|
+
severity = payload.get('severity', 'info')
|
50
|
+
|
51
|
+
print(f"\n🚨 ALERT [{severity.upper()}]: {alert_type}")
|
52
|
+
print(f" Metric: {metric}")
|
53
|
+
print(f" Current: {value}%")
|
54
|
+
print(f" Threshold: {threshold}%")
|
55
|
+
print(f" Time: {time.strftime('%H:%M:%S')}")
|
56
|
+
|
57
|
+
def send_metric(self, metric_name: str, value: float):
|
58
|
+
"""Send a metric to the monitoring system"""
|
59
|
+
self.client.notify("metrics", {
|
60
|
+
'metric': metric_name,
|
61
|
+
'value': value,
|
62
|
+
'client': self.client_name,
|
63
|
+
'timestamp': time.time()
|
64
|
+
})
|
65
|
+
|
66
|
+
def get_system_metrics(self) -> dict:
|
67
|
+
"""Get current system metrics"""
|
68
|
+
if HAS_PSUTIL:
|
69
|
+
try:
|
70
|
+
return {
|
71
|
+
'cpu_usage': psutil.cpu_percent(interval=1),
|
72
|
+
'memory_usage': psutil.virtual_memory().percent,
|
73
|
+
'disk_usage': psutil.disk_usage('/').percent,
|
74
|
+
'load_average': psutil.getloadavg()[0] * 100, # 1-minute load average as percentage
|
75
|
+
}
|
76
|
+
except Exception:
|
77
|
+
pass
|
78
|
+
|
79
|
+
# Fallback with simulated metrics if psutil not available or fails
|
80
|
+
return {
|
81
|
+
'cpu_usage': random.uniform(10, 95),
|
82
|
+
'memory_usage': random.uniform(30, 80),
|
83
|
+
'disk_usage': random.uniform(40, 70),
|
84
|
+
'load_average': random.uniform(5, 50),
|
85
|
+
}
|
86
|
+
|
87
|
+
def start_monitoring(self, interval: float = 5.0):
|
88
|
+
"""Start continuous monitoring"""
|
89
|
+
self.running = True
|
90
|
+
|
91
|
+
def monitor_loop():
|
92
|
+
while self.running:
|
93
|
+
try:
|
94
|
+
metrics = self.get_system_metrics()
|
95
|
+
|
96
|
+
for metric_name, value in metrics.items():
|
97
|
+
self.send_metric(metric_name, value)
|
98
|
+
print(f"[{self.client_name}] {metric_name}: {value:.1f}%")
|
99
|
+
|
100
|
+
print(f"[{self.client_name}] Metrics sent at {time.strftime('%H:%M:%S')}")
|
101
|
+
time.sleep(interval)
|
102
|
+
|
103
|
+
except Exception as e:
|
104
|
+
print(f"Error in monitoring loop: {e}")
|
105
|
+
time.sleep(interval)
|
106
|
+
|
107
|
+
self.metrics_thread = threading.Thread(target=monitor_loop, daemon=True)
|
108
|
+
self.metrics_thread.start()
|
109
|
+
print(f"Started monitoring with {interval}s interval")
|
110
|
+
|
111
|
+
def stop_monitoring(self):
|
112
|
+
"""Stop monitoring"""
|
113
|
+
self.running = False
|
114
|
+
if self.metrics_thread and self.metrics_thread.is_alive():
|
115
|
+
self.metrics_thread.join(timeout=1.0)
|
116
|
+
print("Monitoring stopped")
|
117
|
+
|
118
|
+
def send_custom_metric(self, name: str, value: float):
|
119
|
+
"""Send a custom metric"""
|
120
|
+
self.send_metric(name, value)
|
121
|
+
print(f"Custom metric sent: {name} = {value}")
|
122
|
+
|
123
|
+
def disconnect(self):
|
124
|
+
"""Disconnect from the server"""
|
125
|
+
self.stop_monitoring()
|
126
|
+
self.client.disconnect()
|
127
|
+
print(f"Monitoring client '{self.client_name}' disconnected")
|
128
|
+
|
129
|
+
|
130
|
+
def simulate_monitoring():
|
131
|
+
"""Simulate multiple monitoring clients"""
|
132
|
+
clients = []
|
133
|
+
|
134
|
+
# Create monitoring clients for different "servers"
|
135
|
+
server_names = ["web-server-1", "db-server", "api-gateway"]
|
136
|
+
|
137
|
+
for server_name in server_names:
|
138
|
+
client = MonitoringClient(server_name)
|
139
|
+
if client.connect():
|
140
|
+
clients.append(client)
|
141
|
+
# Start monitoring with different intervals
|
142
|
+
client.start_monitoring(interval=random.uniform(3, 7))
|
143
|
+
time.sleep(0.5)
|
144
|
+
|
145
|
+
if not clients:
|
146
|
+
print("No monitoring clients could connect")
|
147
|
+
return
|
148
|
+
|
149
|
+
print(f"\n=== Started monitoring {len(clients)} systems ===")
|
150
|
+
print("Monitoring will run for 30 seconds...")
|
151
|
+
print("Watch for alerts when CPU usage exceeds 80%")
|
152
|
+
|
153
|
+
try:
|
154
|
+
time.sleep(30)
|
155
|
+
except KeyboardInterrupt:
|
156
|
+
print("\nStopping simulation...")
|
157
|
+
|
158
|
+
# Stop all monitoring
|
159
|
+
for client in clients:
|
160
|
+
client.disconnect()
|
161
|
+
|
162
|
+
print("\n=== Monitoring simulation completed ===")
|
163
|
+
|
164
|
+
|
165
|
+
def interactive_mode():
|
166
|
+
"""Run in interactive mode"""
|
167
|
+
client_name = input("Enter monitoring client name: ").strip() or "MonitoringClient"
|
168
|
+
client = MonitoringClient(client_name)
|
169
|
+
|
170
|
+
if not client.connect():
|
171
|
+
return
|
172
|
+
|
173
|
+
print("\n=== Monitoring Client ===")
|
174
|
+
print("Commands:")
|
175
|
+
print(" start [interval] - Start automatic monitoring (default 5s)")
|
176
|
+
print(" stop - Stop automatic monitoring")
|
177
|
+
print(" metric <name> <val> - Send custom metric")
|
178
|
+
print(" status - Show current system metrics")
|
179
|
+
print(" quit - Exit")
|
180
|
+
|
181
|
+
auto_monitoring = False
|
182
|
+
|
183
|
+
try:
|
184
|
+
while True:
|
185
|
+
if not auto_monitoring:
|
186
|
+
command = input(f"\n[{client_name}] > ").strip().split()
|
187
|
+
else:
|
188
|
+
# In auto monitoring mode, just wait for input with timeout
|
189
|
+
print(f"\n[{client_name}] (auto-monitoring) > ", end="", flush=True)
|
190
|
+
command = input().strip().split()
|
191
|
+
|
192
|
+
if not command:
|
193
|
+
continue
|
194
|
+
|
195
|
+
cmd = command[0].lower()
|
196
|
+
|
197
|
+
if cmd == 'quit':
|
198
|
+
break
|
199
|
+
elif cmd == 'start':
|
200
|
+
if not auto_monitoring:
|
201
|
+
interval = 5.0
|
202
|
+
if len(command) > 1:
|
203
|
+
try:
|
204
|
+
interval = float(command[1])
|
205
|
+
except ValueError:
|
206
|
+
print("Invalid interval, using 5 seconds")
|
207
|
+
client.start_monitoring(interval)
|
208
|
+
auto_monitoring = True
|
209
|
+
else:
|
210
|
+
print("Monitoring is already running. Use 'stop' first.")
|
211
|
+
elif cmd == 'stop':
|
212
|
+
if auto_monitoring:
|
213
|
+
client.stop_monitoring()
|
214
|
+
auto_monitoring = False
|
215
|
+
else:
|
216
|
+
print("Monitoring is not running")
|
217
|
+
elif cmd == 'metric' and len(command) >= 3:
|
218
|
+
try:
|
219
|
+
name = command[1]
|
220
|
+
value = float(command[2])
|
221
|
+
client.send_custom_metric(name, value)
|
222
|
+
except ValueError:
|
223
|
+
print("Invalid metric value")
|
224
|
+
elif cmd == 'status':
|
225
|
+
metrics = client.get_system_metrics()
|
226
|
+
print("Current system metrics:")
|
227
|
+
for name, value in metrics.items():
|
228
|
+
print(f" {name}: {value:.1f}%")
|
229
|
+
else:
|
230
|
+
print("Invalid command or missing arguments")
|
231
|
+
|
232
|
+
except KeyboardInterrupt:
|
233
|
+
pass
|
234
|
+
finally:
|
235
|
+
client.disconnect()
|
236
|
+
|
237
|
+
|
238
|
+
def main():
|
239
|
+
import sys
|
240
|
+
|
241
|
+
print("System Monitoring Client")
|
242
|
+
print("This example requires 'psutil' for real system metrics.")
|
243
|
+
print("If not available, simulated metrics will be used.\n")
|
244
|
+
|
245
|
+
if len(sys.argv) > 1 and sys.argv[1] == 'sim':
|
246
|
+
simulate_monitoring()
|
247
|
+
else:
|
248
|
+
interactive_mode()
|
249
|
+
|
250
|
+
|
251
|
+
if __name__ == "__main__":
|
252
|
+
main()
|
@@ -0,0 +1,43 @@
|
|
1
|
+
"""
|
2
|
+
Custom exceptions for the IPC Framework
|
3
|
+
"""
|
4
|
+
|
5
|
+
|
6
|
+
class IPCError(Exception):
|
7
|
+
"""Base exception for IPC Framework"""
|
8
|
+
pass
|
9
|
+
|
10
|
+
|
11
|
+
class ConnectionError(IPCError):
|
12
|
+
"""Raised when connection-related errors occur"""
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
class RoutingError(IPCError):
|
17
|
+
"""Raised when message routing fails"""
|
18
|
+
pass
|
19
|
+
|
20
|
+
|
21
|
+
class AuthenticationError(IPCError):
|
22
|
+
"""Raised when authentication fails"""
|
23
|
+
pass
|
24
|
+
|
25
|
+
|
26
|
+
class ChannelError(IPCError):
|
27
|
+
"""Raised when channel operations fail"""
|
28
|
+
pass
|
29
|
+
|
30
|
+
|
31
|
+
class ApplicationError(IPCError):
|
32
|
+
"""Raised when application operations fail"""
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class SerializationError(IPCError):
|
37
|
+
"""Raised when message serialization/deserialization fails"""
|
38
|
+
pass
|
39
|
+
|
40
|
+
|
41
|
+
class TimeoutError(IPCError):
|
42
|
+
"""Raised when operations timeout"""
|
43
|
+
pass
|
ipc_framework/py.typed
ADDED