-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathvm_client.py
More file actions
executable file
·203 lines (166 loc) · 6 KB
/
vm_client.py
File metadata and controls
executable file
·203 lines (166 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env python3
"""
VM-to-Host Bridge Client Library
Use this on the VM side to send commands to the Mac host
"""
import socket
import json
import time
import uuid
import logging
logger = logging.getLogger(__name__)
class VMBridgeClient:
"""Client for communicating with VM Bridge Daemon"""
def __init__(self, host='localhost', port=9999, timeout=5):
self.host = host
self.port = port
self.timeout = timeout
def send_command(self, cmd, stdin=None, args=None, timeout=None):
"""
Send a command to the Mac host
Args:
cmd: Command name (must be whitelisted on daemon)
stdin: Optional stdin data to send
args: Optional arguments list
timeout: Command timeout in seconds
Returns:
dict: Response from daemon with success, stdout, stderr, etc.
"""
request_id = str(uuid.uuid4())
request = {
'id': request_id,
'cmd': cmd,
'timeout': timeout or self.timeout
}
if stdin is not None:
request['stdin'] = stdin
if args is not None:
request['args'] = args
try:
# Connect to daemon
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
sock.connect((self.host, self.port))
# Send request
request_json = json.dumps(request)
sock.send(request_json.encode('utf-8'))
# Receive response
response_data = b''
while True:
chunk = sock.recv(4096)
if not chunk:
break
response_data += chunk
# Try to parse as JSON to see if complete
try:
response = json.loads(response_data.decode('utf-8'))
break
except:
continue
sock.close()
return response
except socket.timeout:
logger.error(f"Timeout connecting to daemon at {self.host}:{self.port}")
return {
'success': False,
'error': 'Connection timeout - is daemon running?'
}
except ConnectionRefusedError:
logger.error(f"Connection refused to {self.host}:{self.port}")
return {
'success': False,
'error': 'Connection refused - is daemon running?'
}
except Exception as e:
logger.error(f"Client error: {e}")
return {
'success': False,
'error': str(e)
}
def copy_to_clipboard(self, content):
"""Copy content to Mac clipboard"""
result = self.send_command('pbcopy', stdin=content)
return result.get('success', False)
def paste_from_clipboard(self):
"""Get content from Mac clipboard"""
result = self.send_command('pbpaste')
if result.get('success'):
return result.get('stdout', '')
return None
def notify(self, message):
"""Show notification on Mac"""
result = self.send_command('notify', args=[message])
return result.get('success', False)
def open_url(self, url):
"""Open URL in Mac browser"""
result = self.send_command('open_url', args=[url])
return result.get('success', False)
def is_daemon_running(self):
"""Check if daemon is accessible"""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex((self.host, self.port))
sock.close()
return result == 0
except:
return False
# Convenience functions for direct use
_default_client = None
def get_client():
"""Get or create default client instance"""
global _default_client
if _default_client is None:
_default_client = VMBridgeClient()
return _default_client
def copy_to_mac_clipboard(content):
"""Quick function to copy to Mac clipboard"""
return get_client().copy_to_clipboard(content)
def paste_from_mac_clipboard():
"""Quick function to paste from Mac clipboard"""
return get_client().paste_from_clipboard()
def notify_mac(message):
"""Quick function to show Mac notification"""
return get_client().notify(message)
def open_url_on_mac(url):
"""Quick function to open URL on Mac"""
return get_client().open_url(url)
if __name__ == '__main__':
# Test the client
import sys
print("VM Bridge Client Test")
print("=" * 40)
client = VMBridgeClient()
if not client.is_daemon_running():
print("❌ Daemon not running on localhost:9999")
print("Start the daemon first on your Mac:")
print(" python3 mac_daemon.py")
sys.exit(1)
print("✅ Daemon is running")
# Test clipboard
test_content = f"Test from VM at {time.strftime('%Y-%m-%d %H:%M:%S')}"
print(f"\n1. Testing clipboard copy: '{test_content}'")
if client.copy_to_clipboard(test_content):
print(" ✅ Copied to Mac clipboard")
else:
print(" ❌ Failed to copy")
# Test paste
print("\n2. Testing clipboard paste")
content = client.paste_from_clipboard()
if content is not None:
print(f" ✅ Mac clipboard contains: '{content[:50]}...'")
else:
print(" ❌ Failed to paste")
# Test notification
print("\n3. Testing notification")
if client.notify("Hello from VM!"):
print(" ✅ Notification sent")
else:
print(" ❌ Failed to send notification")
# Test URL
print("\n4. Testing URL open")
if client.open_url("https://claude.ai"):
print(" ✅ URL opened")
else:
print(" ❌ Failed to open URL")
print("\n✅ All tests completed!")