zexus 1.6.8 → 1.7.2
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.
- package/README.md +12 -5
- package/package.json +1 -1
- package/src/__init__.py +7 -0
- package/src/zexus/__init__.py +1 -1
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/debug_sanitizer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/input_validation.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +17 -2
- package/src/zexus/blockchain/__init__.py +411 -0
- package/src/zexus/blockchain/accelerator.py +1160 -0
- package/src/zexus/blockchain/chain.py +660 -0
- package/src/zexus/blockchain/consensus.py +821 -0
- package/src/zexus/blockchain/contract_vm.py +1019 -0
- package/src/zexus/blockchain/crypto.py +79 -14
- package/src/zexus/blockchain/events.py +526 -0
- package/src/zexus/blockchain/loadtest.py +721 -0
- package/src/zexus/blockchain/monitoring.py +350 -0
- package/src/zexus/blockchain/mpt.py +716 -0
- package/src/zexus/blockchain/multichain.py +951 -0
- package/src/zexus/blockchain/multiprocess_executor.py +338 -0
- package/src/zexus/blockchain/network.py +886 -0
- package/src/zexus/blockchain/node.py +666 -0
- package/src/zexus/blockchain/rpc.py +1203 -0
- package/src/zexus/blockchain/rust_bridge.py +421 -0
- package/src/zexus/blockchain/storage.py +423 -0
- package/src/zexus/blockchain/tokens.py +750 -0
- package/src/zexus/blockchain/upgradeable.py +1004 -0
- package/src/zexus/blockchain/verification.py +1602 -0
- package/src/zexus/blockchain/wallet.py +621 -0
- package/src/zexus/capability_system.py +184 -9
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +383 -34
- package/src/zexus/cli/zpm.py +1 -1
- package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +124 -7
- package/src/zexus/compiler/compat_runtime.py +6 -2
- package/src/zexus/compiler/lexer.py +16 -5
- package/src/zexus/compiler/parser.py +108 -7
- package/src/zexus/compiler/semantic.py +18 -19
- package/src/zexus/compiler/zexus_ast.py +26 -1
- package/src/zexus/concurrency_system.py +79 -0
- package/src/zexus/config.py +54 -0
- package/src/zexus/crypto_bridge.py +244 -8
- package/src/zexus/dap/__init__.py +10 -0
- package/src/zexus/dap/__main__.py +4 -0
- package/src/zexus/dap/dap_server.py +391 -0
- package/src/zexus/dap/debug_engine.py +298 -0
- package/src/zexus/environment.py +112 -9
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +457 -37
- package/src/zexus/evaluator/core.py +644 -50
- package/src/zexus/evaluator/expressions.py +358 -62
- package/src/zexus/evaluator/functions.py +458 -20
- package/src/zexus/evaluator/resource_limiter.py +4 -4
- package/src/zexus/evaluator/statements.py +774 -122
- package/src/zexus/evaluator/unified_execution.py +573 -72
- package/src/zexus/evaluator/utils.py +14 -2
- package/src/zexus/evaluator_original.py +1 -1
- package/src/zexus/event_loop.py +186 -0
- package/src/zexus/lexer.py +742 -458
- package/src/zexus/lsp/__init__.py +1 -1
- package/src/zexus/lsp/definition_provider.py +163 -9
- package/src/zexus/lsp/server.py +22 -8
- package/src/zexus/lsp/symbol_provider.py +182 -9
- package/src/zexus/module_cache.py +239 -9
- package/src/zexus/module_manager.py +129 -1
- package/src/zexus/object.py +76 -6
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/parser.py +1349 -408
- package/src/zexus/parser/strategy_context.py +755 -58
- package/src/zexus/parser/strategy_structural.py +121 -21
- package/src/zexus/persistence.py +15 -1
- package/src/zexus/renderer/__init__.py +61 -0
- package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
- package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
- package/src/zexus/renderer/backend.py +261 -0
- package/src/zexus/renderer/canvas.py +78 -0
- package/src/zexus/renderer/color_system.py +201 -0
- package/src/zexus/renderer/graphics.py +31 -0
- package/src/zexus/renderer/layout.py +222 -0
- package/src/zexus/renderer/main_renderer.py +66 -0
- package/src/zexus/renderer/painter.py +30 -0
- package/src/zexus/renderer/tk_backend.py +208 -0
- package/src/zexus/renderer/web_backend.py +260 -0
- package/src/zexus/runtime/__init__.py +10 -2
- package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
- package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
- package/src/zexus/runtime/file_flags.py +137 -0
- package/src/zexus/runtime/load_manager.py +368 -0
- package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
- package/src/zexus/security.py +424 -34
- package/src/zexus/stdlib/fs.py +23 -18
- package/src/zexus/stdlib/http.py +289 -186
- package/src/zexus/stdlib/sockets.py +207 -163
- package/src/zexus/stdlib/websockets.py +282 -0
- package/src/zexus/stdlib_integration.py +369 -2
- package/src/zexus/strategy_recovery.py +6 -3
- package/src/zexus/type_checker.py +423 -0
- package/src/zexus/virtual_filesystem.py +189 -2
- package/src/zexus/vm/__init__.py +113 -3
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +80 -6
- package/src/zexus/vm/binary_bytecode.py +659 -0
- package/src/zexus/vm/bytecode.py +59 -11
- package/src/zexus/vm/bytecode_converter.py +26 -12
- package/src/zexus/vm/cabi.c +1985 -0
- package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/cabi.h +127 -0
- package/src/zexus/vm/cache.py +561 -17
- package/src/zexus/vm/compiler.py +818 -51
- package/src/zexus/vm/fastops.c +15743 -0
- package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/fastops.pyx +288 -0
- package/src/zexus/vm/gas_metering.py +50 -9
- package/src/zexus/vm/jit.py +364 -20
- package/src/zexus/vm/native_jit_backend.py +1816 -0
- package/src/zexus/vm/native_runtime.cpp +1388 -0
- package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
- package/src/zexus/vm/optimizer.py +161 -11
- package/src/zexus/vm/parallel_vm.py +140 -45
- package/src/zexus/vm/peephole_optimizer.py +82 -4
- package/src/zexus/vm/profiler.py +38 -18
- package/src/zexus/vm/register_allocator.py +16 -5
- package/src/zexus/vm/register_vm.py +8 -5
- package/src/zexus/vm/vm.py +3581 -531
- package/src/zexus/vm/wasm_compiler.py +658 -0
- package/src/zexus/zexus_ast.py +137 -11
- package/src/zexus/zexus_token.py +16 -5
- package/src/zexus/zpm/installer.py +55 -15
- package/src/zexus/zpm/package_manager.py +1 -1
- package/src/zexus/zpm/registry.py +257 -28
- package/src/zexus.egg-info/PKG-INFO +16 -6
- package/src/zexus.egg-info/SOURCES.txt +129 -17
- package/src/zexus.egg-info/entry_points.txt +1 -0
- package/src/zexus.egg-info/requires.txt +4 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
"""WebSocket client & server module for Zexus standard library.
|
|
2
|
+
|
|
3
|
+
Provides ``WebSocketServer`` and ``WebSocketClient`` backed by the
|
|
4
|
+
``websockets`` library running on the shared asyncio background loop
|
|
5
|
+
(same one used by the async TCP sockets module).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import threading
|
|
10
|
+
from typing import Callable, Optional, Dict, Any, List
|
|
11
|
+
|
|
12
|
+
# Re-use the background event loop from sockets module
|
|
13
|
+
from .sockets import _get_bg_loop, _run_async
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
# Optional dependency guard
|
|
18
|
+
# ---------------------------------------------------------------------------
|
|
19
|
+
try:
|
|
20
|
+
import websockets
|
|
21
|
+
import websockets.server
|
|
22
|
+
import websockets.client
|
|
23
|
+
_WS_AVAILABLE = True
|
|
24
|
+
except ImportError:
|
|
25
|
+
_WS_AVAILABLE = False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _require_ws():
|
|
29
|
+
if not _WS_AVAILABLE:
|
|
30
|
+
raise RuntimeError(
|
|
31
|
+
"WebSocket support requires the 'websockets' package. "
|
|
32
|
+
"Install with: pip install websockets"
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# WebSocket Module (factory)
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
class WebSocketModule:
|
|
41
|
+
"""Factory for WebSocket servers and clients."""
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def create_server(host: str, port: int, handler: Callable,
|
|
45
|
+
path: Optional[str] = None) -> 'WebSocketServer':
|
|
46
|
+
"""Create a WebSocket server.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
host: Host address to bind (e.g. '0.0.0.0').
|
|
50
|
+
port: Port number.
|
|
51
|
+
handler: Callback ``action(ws)`` invoked for each connection.
|
|
52
|
+
``ws`` is a *WebSocketConnection* with ``send`` /
|
|
53
|
+
``receive`` / ``close`` methods.
|
|
54
|
+
path: Optional URL path filter (not enforced; for documentation).
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
WebSocketServer instance (call ``.start()`` to begin listening).
|
|
58
|
+
"""
|
|
59
|
+
_require_ws()
|
|
60
|
+
return WebSocketServer(host, port, handler, path)
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def connect(url: str, timeout: float = 10.0) -> 'WebSocketClient':
|
|
64
|
+
"""Open a WebSocket client connection.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
url: WebSocket URL, e.g. ``ws://localhost:8080/path``.
|
|
68
|
+
timeout: Connection timeout in seconds.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
WebSocketClient with ``send`` / ``receive`` / ``close``.
|
|
72
|
+
"""
|
|
73
|
+
_require_ws()
|
|
74
|
+
return WebSocketClient(url, timeout)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# WebSocket Server
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
class WebSocketServer:
|
|
82
|
+
"""WebSocket server backed by ``websockets.serve``."""
|
|
83
|
+
|
|
84
|
+
def __init__(self, host: str, port: int, handler: Callable,
|
|
85
|
+
path: Optional[str] = None):
|
|
86
|
+
_require_ws()
|
|
87
|
+
self.host = host
|
|
88
|
+
self.port = port
|
|
89
|
+
self.handler = handler
|
|
90
|
+
self.path = path
|
|
91
|
+
self.running = False
|
|
92
|
+
self._server = None
|
|
93
|
+
self._loop = _get_bg_loop()
|
|
94
|
+
|
|
95
|
+
def start(self) -> None:
|
|
96
|
+
if self.running:
|
|
97
|
+
raise RuntimeError("WebSocket server is already running")
|
|
98
|
+
_run_async(self._async_start())
|
|
99
|
+
|
|
100
|
+
def stop(self) -> None:
|
|
101
|
+
if not self.running:
|
|
102
|
+
return
|
|
103
|
+
self.running = False
|
|
104
|
+
if self._server:
|
|
105
|
+
asyncio.run_coroutine_threadsafe(
|
|
106
|
+
self._async_stop(), self._loop
|
|
107
|
+
).result(timeout=5)
|
|
108
|
+
|
|
109
|
+
def is_running(self) -> bool:
|
|
110
|
+
return self.running
|
|
111
|
+
|
|
112
|
+
def get_address(self) -> Dict[str, Any]:
|
|
113
|
+
return {
|
|
114
|
+
'host': self.host,
|
|
115
|
+
'port': self.port,
|
|
116
|
+
'running': self.running,
|
|
117
|
+
'path': self.path or '/',
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# -- async internals ---------------------------------------------------
|
|
121
|
+
|
|
122
|
+
async def _async_start(self):
|
|
123
|
+
self._server = await websockets.server.serve(
|
|
124
|
+
self._async_handle,
|
|
125
|
+
self.host,
|
|
126
|
+
self.port,
|
|
127
|
+
)
|
|
128
|
+
self.running = True
|
|
129
|
+
|
|
130
|
+
async def _async_stop(self):
|
|
131
|
+
if self._server:
|
|
132
|
+
self._server.close()
|
|
133
|
+
await self._server.wait_closed()
|
|
134
|
+
self.running = False
|
|
135
|
+
|
|
136
|
+
async def _async_handle(self, ws):
|
|
137
|
+
"""Per-connection handler coroutine."""
|
|
138
|
+
conn = WebSocketConnection(ws)
|
|
139
|
+
loop = asyncio.get_running_loop()
|
|
140
|
+
try:
|
|
141
|
+
# Run sync handler in thread executor to avoid deadlock
|
|
142
|
+
await loop.run_in_executor(None, self.handler, conn)
|
|
143
|
+
except Exception as e:
|
|
144
|
+
print(f"WebSocket handler error: {e}")
|
|
145
|
+
finally:
|
|
146
|
+
conn._closed = True
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# ---------------------------------------------------------------------------
|
|
150
|
+
# WebSocket Client
|
|
151
|
+
# ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
class WebSocketClient:
|
|
154
|
+
"""WebSocket client connection."""
|
|
155
|
+
|
|
156
|
+
def __init__(self, url: str, timeout: float = 10.0):
|
|
157
|
+
_require_ws()
|
|
158
|
+
self.url = url
|
|
159
|
+
self._ws = None
|
|
160
|
+
self._closed = False
|
|
161
|
+
|
|
162
|
+
async def _connect():
|
|
163
|
+
return await asyncio.wait_for(
|
|
164
|
+
websockets.client.connect(url), timeout=timeout
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
self._ws = _run_async(_connect())
|
|
168
|
+
|
|
169
|
+
def send(self, message: str) -> None:
|
|
170
|
+
"""Send a text message."""
|
|
171
|
+
if self._closed:
|
|
172
|
+
raise RuntimeError("WebSocket is closed")
|
|
173
|
+
|
|
174
|
+
async def _send():
|
|
175
|
+
await self._ws.send(message)
|
|
176
|
+
|
|
177
|
+
_run_async(_send())
|
|
178
|
+
|
|
179
|
+
def send_bytes(self, data: bytes) -> None:
|
|
180
|
+
"""Send binary data."""
|
|
181
|
+
if self._closed:
|
|
182
|
+
raise RuntimeError("WebSocket is closed")
|
|
183
|
+
|
|
184
|
+
async def _send():
|
|
185
|
+
await self._ws.send(data)
|
|
186
|
+
|
|
187
|
+
_run_async(_send())
|
|
188
|
+
|
|
189
|
+
def receive(self, timeout: float = 30.0) -> str:
|
|
190
|
+
"""Receive a text message."""
|
|
191
|
+
if self._closed:
|
|
192
|
+
raise RuntimeError("WebSocket is closed")
|
|
193
|
+
|
|
194
|
+
async def _recv():
|
|
195
|
+
return await asyncio.wait_for(self._ws.recv(), timeout=timeout)
|
|
196
|
+
|
|
197
|
+
return _run_async(_recv())
|
|
198
|
+
|
|
199
|
+
def receive_bytes(self, timeout: float = 30.0) -> bytes:
|
|
200
|
+
"""Receive binary data."""
|
|
201
|
+
return self.receive(timeout) # websockets handles both
|
|
202
|
+
|
|
203
|
+
def close(self) -> None:
|
|
204
|
+
if self._closed:
|
|
205
|
+
return
|
|
206
|
+
self._closed = True
|
|
207
|
+
try:
|
|
208
|
+
async def _close():
|
|
209
|
+
await self._ws.close()
|
|
210
|
+
_run_async(_close(), timeout=5)
|
|
211
|
+
except Exception:
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
def is_connected(self) -> bool:
|
|
215
|
+
return not self._closed and self._ws is not None
|
|
216
|
+
|
|
217
|
+
def get_address(self) -> Dict[str, Any]:
|
|
218
|
+
return {'url': self.url, 'connected': self.is_connected()}
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# ---------------------------------------------------------------------------
|
|
222
|
+
# WebSocket Connection (server-side wrapper)
|
|
223
|
+
# ---------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
class WebSocketConnection:
|
|
226
|
+
"""Wraps a server-side websocket for use in synchronous Zexus handlers."""
|
|
227
|
+
|
|
228
|
+
def __init__(self, ws):
|
|
229
|
+
self._ws = ws
|
|
230
|
+
self._closed = False
|
|
231
|
+
|
|
232
|
+
def send(self, message: str) -> None:
|
|
233
|
+
"""Send a text message to the client."""
|
|
234
|
+
if self._closed:
|
|
235
|
+
raise RuntimeError("WebSocket is closed")
|
|
236
|
+
|
|
237
|
+
async def _send():
|
|
238
|
+
await self._ws.send(message)
|
|
239
|
+
|
|
240
|
+
_run_async(_send())
|
|
241
|
+
|
|
242
|
+
def send_bytes(self, data: bytes) -> None:
|
|
243
|
+
"""Send binary data to the client."""
|
|
244
|
+
if self._closed:
|
|
245
|
+
raise RuntimeError("WebSocket is closed")
|
|
246
|
+
|
|
247
|
+
async def _send():
|
|
248
|
+
await self._ws.send(data)
|
|
249
|
+
|
|
250
|
+
_run_async(_send())
|
|
251
|
+
|
|
252
|
+
def receive(self, timeout: float = 30.0) -> str:
|
|
253
|
+
"""Receive a message from the client."""
|
|
254
|
+
if self._closed:
|
|
255
|
+
raise RuntimeError("WebSocket is closed")
|
|
256
|
+
|
|
257
|
+
async def _recv():
|
|
258
|
+
return await asyncio.wait_for(self._ws.recv(), timeout=timeout)
|
|
259
|
+
|
|
260
|
+
return _run_async(_recv())
|
|
261
|
+
|
|
262
|
+
def close(self) -> None:
|
|
263
|
+
if self._closed:
|
|
264
|
+
return
|
|
265
|
+
self._closed = True
|
|
266
|
+
try:
|
|
267
|
+
async def _close():
|
|
268
|
+
await self._ws.close()
|
|
269
|
+
_run_async(_close(), timeout=5)
|
|
270
|
+
except Exception:
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
def is_connected(self) -> bool:
|
|
274
|
+
return not self._closed
|
|
275
|
+
|
|
276
|
+
def get_address(self) -> Dict[str, Any]:
|
|
277
|
+
remote = getattr(self._ws, 'remote_address', None) or ('unknown', 0)
|
|
278
|
+
return {
|
|
279
|
+
'host': remote[0] if isinstance(remote, tuple) else str(remote),
|
|
280
|
+
'port': remote[1] if isinstance(remote, tuple) and len(remote) > 1 else 0,
|
|
281
|
+
'connected': self.is_connected(),
|
|
282
|
+
}
|
|
@@ -234,10 +234,208 @@ def create_stdlib_module(module_name, evaluator=None):
|
|
|
234
234
|
except Exception as e:
|
|
235
235
|
return EvaluationError(f"pbkdf2 error: {str(e)}")
|
|
236
236
|
|
|
237
|
+
# generate_keypair(algorithm?) and derive_address(public_key, [prefix])
|
|
238
|
+
try:
|
|
239
|
+
from .blockchain.crypto import CryptoPlugin as _BCPlugin
|
|
240
|
+
|
|
241
|
+
def _crypto_generate_keypair(*args):
|
|
242
|
+
algorithm = args[0].value if len(args) > 0 and hasattr(args[0], 'value') else 'ECDSA'
|
|
243
|
+
try:
|
|
244
|
+
private_key, public_key = _BCPlugin.generate_keypair(algorithm)
|
|
245
|
+
return Map({
|
|
246
|
+
String('private_key'): String(private_key),
|
|
247
|
+
String('public_key'): String(public_key)
|
|
248
|
+
})
|
|
249
|
+
except Exception as e:
|
|
250
|
+
return EvaluationError(f"Keypair generation error: {str(e)}")
|
|
251
|
+
|
|
252
|
+
def _crypto_derive_address(*args):
|
|
253
|
+
if len(args) < 1 or len(args) > 2:
|
|
254
|
+
return EvaluationError("derive_address() expects 1 or 2 arguments: public_key, [prefix]")
|
|
255
|
+
public_key = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
256
|
+
prefix = None
|
|
257
|
+
if len(args) > 1:
|
|
258
|
+
prefix = args[1].value if hasattr(args[1], 'value') else str(args[1])
|
|
259
|
+
try:
|
|
260
|
+
result = _BCPlugin.derive_address(public_key, prefix=prefix)
|
|
261
|
+
return String(result)
|
|
262
|
+
except Exception as e:
|
|
263
|
+
return EvaluationError(f"Address derivation error: {str(e)}")
|
|
264
|
+
|
|
265
|
+
env.set("generate_keypair", Builtin(_crypto_generate_keypair))
|
|
266
|
+
env.set("derive_address", Builtin(_crypto_derive_address))
|
|
267
|
+
# Also register camelCase aliases used by demo files
|
|
268
|
+
env.set("generateKeypair", Builtin(_crypto_generate_keypair))
|
|
269
|
+
env.set("deriveAddress", Builtin(_crypto_derive_address))
|
|
270
|
+
except ImportError:
|
|
271
|
+
pass # blockchain.crypto not available
|
|
272
|
+
|
|
237
273
|
env.set("hash_sha256", Builtin(_crypto_hash_sha256))
|
|
238
274
|
env.set("keccak256", Builtin(_crypto_keccak256))
|
|
239
275
|
env.set("random_bytes", Builtin(_crypto_random_bytes))
|
|
240
276
|
env.set("pbkdf2", Builtin(_crypto_pbkdf2))
|
|
277
|
+
|
|
278
|
+
elif module_name == "perf" or module_name == "stdlib/perf":
|
|
279
|
+
def _perf_vm_stats(*args):
|
|
280
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
281
|
+
return EvaluationError("perf.vm_stats() requires unified executor")
|
|
282
|
+
stats = evaluator.unified_executor.get_statistics()
|
|
283
|
+
return _python_to_zexus(stats)
|
|
284
|
+
|
|
285
|
+
def _perf_set_vm_thresholds(*args):
|
|
286
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
287
|
+
return EvaluationError("perf.set_vm_thresholds() requires unified executor")
|
|
288
|
+
workload = evaluator.unified_executor.workload
|
|
289
|
+
if len(args) >= 1:
|
|
290
|
+
val = _zexus_to_python(args[0])
|
|
291
|
+
if isinstance(val, int):
|
|
292
|
+
workload.vm_threshold = val
|
|
293
|
+
if len(args) >= 2:
|
|
294
|
+
val = _zexus_to_python(args[1])
|
|
295
|
+
if isinstance(val, int):
|
|
296
|
+
workload.jit_threshold = val
|
|
297
|
+
if len(args) >= 3:
|
|
298
|
+
val = _zexus_to_python(args[2])
|
|
299
|
+
if isinstance(val, int):
|
|
300
|
+
workload.parallel_threshold = val
|
|
301
|
+
return Boolean(True)
|
|
302
|
+
|
|
303
|
+
def _perf_enable_vm(*args):
|
|
304
|
+
if evaluator is None:
|
|
305
|
+
return EvaluationError("perf.enable_vm() requires evaluator")
|
|
306
|
+
flag = True
|
|
307
|
+
if len(args) >= 1:
|
|
308
|
+
val = _zexus_to_python(args[0])
|
|
309
|
+
flag = bool(val)
|
|
310
|
+
evaluator.use_vm = flag
|
|
311
|
+
if evaluator.unified_executor:
|
|
312
|
+
evaluator.unified_executor.vm_enabled = flag
|
|
313
|
+
return Boolean(True)
|
|
314
|
+
|
|
315
|
+
def _perf_collect_gc(*args):
|
|
316
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
317
|
+
return EvaluationError("perf.collect_gc() requires unified executor")
|
|
318
|
+
vm = evaluator.unified_executor.vm
|
|
319
|
+
if vm is None:
|
|
320
|
+
return EvaluationError("perf.collect_gc() requires VM initialization")
|
|
321
|
+
force = False
|
|
322
|
+
if len(args) >= 1:
|
|
323
|
+
force = bool(_zexus_to_python(args[0]))
|
|
324
|
+
result = vm.collect_garbage(force=force)
|
|
325
|
+
return _python_to_zexus(result)
|
|
326
|
+
|
|
327
|
+
def _perf_memory_stats(*args):
|
|
328
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
329
|
+
return EvaluationError("perf.memory_stats() requires unified executor")
|
|
330
|
+
vm = evaluator.unified_executor.vm
|
|
331
|
+
if vm is None:
|
|
332
|
+
return EvaluationError("perf.memory_stats() requires VM initialization")
|
|
333
|
+
stats = vm.get_memory_stats()
|
|
334
|
+
return _python_to_zexus(stats)
|
|
335
|
+
|
|
336
|
+
def _perf_warmup(*args):
|
|
337
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
338
|
+
return EvaluationError("perf.warmup() requires unified executor")
|
|
339
|
+
workload = evaluator.unified_executor.workload
|
|
340
|
+
vm_threshold = 1
|
|
341
|
+
jit_threshold = workload.jit_threshold
|
|
342
|
+
if len(args) >= 1:
|
|
343
|
+
val = _zexus_to_python(args[0])
|
|
344
|
+
if isinstance(val, int):
|
|
345
|
+
vm_threshold = val
|
|
346
|
+
if len(args) >= 2:
|
|
347
|
+
val = _zexus_to_python(args[1])
|
|
348
|
+
if isinstance(val, int):
|
|
349
|
+
jit_threshold = val
|
|
350
|
+
workload.vm_threshold = vm_threshold
|
|
351
|
+
workload.jit_threshold = jit_threshold
|
|
352
|
+
return Boolean(True)
|
|
353
|
+
|
|
354
|
+
def _perf_profile_start(*args):
|
|
355
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
356
|
+
return EvaluationError("perf.profile_start() requires unified executor")
|
|
357
|
+
evaluator.unified_executor.ensure_vm(profile_active=True)
|
|
358
|
+
vm = evaluator.unified_executor.vm
|
|
359
|
+
if vm is None:
|
|
360
|
+
return EvaluationError("perf.profile_start() requires VM initialization")
|
|
361
|
+
vm.start_profiling()
|
|
362
|
+
return Boolean(True)
|
|
363
|
+
|
|
364
|
+
def _perf_profile_stop(*args):
|
|
365
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
366
|
+
return EvaluationError("perf.profile_stop() requires unified executor")
|
|
367
|
+
vm = evaluator.unified_executor.vm
|
|
368
|
+
if vm is None:
|
|
369
|
+
return EvaluationError("perf.profile_stop() requires VM initialization")
|
|
370
|
+
vm.stop_profiling()
|
|
371
|
+
return Boolean(True)
|
|
372
|
+
|
|
373
|
+
def _perf_profile_report(*args):
|
|
374
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
375
|
+
return EvaluationError("perf.profile_report() requires unified executor")
|
|
376
|
+
evaluator.unified_executor.ensure_vm(profile_active=True)
|
|
377
|
+
vm = evaluator.unified_executor.vm
|
|
378
|
+
if vm is None:
|
|
379
|
+
return EvaluationError("perf.profile_report() requires VM initialization")
|
|
380
|
+
report_format = "text"
|
|
381
|
+
top_n = 20
|
|
382
|
+
if len(args) >= 1:
|
|
383
|
+
report_format = str(_zexus_to_python(args[0]))
|
|
384
|
+
if len(args) >= 2:
|
|
385
|
+
val = _zexus_to_python(args[1])
|
|
386
|
+
if isinstance(val, int):
|
|
387
|
+
top_n = val
|
|
388
|
+
report = vm.get_profiling_report(format=report_format, top_n=top_n)
|
|
389
|
+
return String(report)
|
|
390
|
+
|
|
391
|
+
def _perf_set_vm_config(*args):
|
|
392
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
393
|
+
return EvaluationError("perf.set_vm_config() requires unified executor")
|
|
394
|
+
if len(args) < 1:
|
|
395
|
+
return EvaluationError("perf.set_vm_config() requires 1 argument: config map")
|
|
396
|
+
config = _zexus_to_python(args[0])
|
|
397
|
+
if not isinstance(config, dict):
|
|
398
|
+
return EvaluationError("perf.set_vm_config() expects a map")
|
|
399
|
+
evaluator.unified_executor.configure_vm(config)
|
|
400
|
+
return Boolean(True)
|
|
401
|
+
|
|
402
|
+
def _perf_set_vm_mode(*args):
|
|
403
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
404
|
+
return EvaluationError("perf.set_vm_mode() requires unified executor")
|
|
405
|
+
if len(args) < 1:
|
|
406
|
+
return EvaluationError("perf.set_vm_mode() requires 1 argument: mode")
|
|
407
|
+
mode_value = _zexus_to_python(args[0])
|
|
408
|
+
evaluator.unified_executor.configure_vm({"mode": mode_value})
|
|
409
|
+
return Boolean(True)
|
|
410
|
+
|
|
411
|
+
def _perf_force_vm_loops(*args):
|
|
412
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
413
|
+
return EvaluationError("perf.force_vm_loops() requires unified executor")
|
|
414
|
+
flag = True
|
|
415
|
+
if len(args) >= 1:
|
|
416
|
+
flag = bool(_zexus_to_python(args[0]))
|
|
417
|
+
evaluator.unified_executor.set_force_vm_loops(flag)
|
|
418
|
+
return Boolean(True)
|
|
419
|
+
|
|
420
|
+
def _perf_reset_vm(*args):
|
|
421
|
+
if evaluator is None or not hasattr(evaluator, "unified_executor") or not evaluator.unified_executor:
|
|
422
|
+
return EvaluationError("perf.reset_vm() requires unified executor")
|
|
423
|
+
evaluator.unified_executor.reset_vm()
|
|
424
|
+
return Boolean(True)
|
|
425
|
+
|
|
426
|
+
env.set("vm_stats", Builtin(_perf_vm_stats))
|
|
427
|
+
env.set("set_vm_thresholds", Builtin(_perf_set_vm_thresholds))
|
|
428
|
+
env.set("enable_vm", Builtin(_perf_enable_vm))
|
|
429
|
+
env.set("collect_gc", Builtin(_perf_collect_gc))
|
|
430
|
+
env.set("memory_stats", Builtin(_perf_memory_stats))
|
|
431
|
+
env.set("warmup", Builtin(_perf_warmup))
|
|
432
|
+
env.set("profile_start", Builtin(_perf_profile_start))
|
|
433
|
+
env.set("profile_stop", Builtin(_perf_profile_stop))
|
|
434
|
+
env.set("profile_report", Builtin(_perf_profile_report))
|
|
435
|
+
env.set("set_vm_config", Builtin(_perf_set_vm_config))
|
|
436
|
+
env.set("set_vm_mode", Builtin(_perf_set_vm_mode))
|
|
437
|
+
env.set("force_vm_loops", Builtin(_perf_force_vm_loops))
|
|
438
|
+
env.set("reset_vm", Builtin(_perf_reset_vm))
|
|
241
439
|
|
|
242
440
|
elif module_name == "blockchain" or module_name == "stdlib/blockchain":
|
|
243
441
|
from .stdlib.blockchain import BlockchainModule
|
|
@@ -283,11 +481,180 @@ def create_stdlib_module(module_name, evaluator=None):
|
|
|
283
481
|
except Exception as e:
|
|
284
482
|
return EvaluationError(f"create_genesis_block error: {str(e)}")
|
|
285
483
|
|
|
484
|
+
def _blockchain_create_block(*args):
|
|
485
|
+
if len(args) < 4:
|
|
486
|
+
return EvaluationError("create_block() requires 4 args: index, timestamp, data, previous_hash")
|
|
487
|
+
index = int(args[0].value if hasattr(args[0], 'value') else args[0])
|
|
488
|
+
timestamp = float(args[1].value if hasattr(args[1], 'value') else args[1])
|
|
489
|
+
data = args[2].value if hasattr(args[2], 'value') else str(args[2])
|
|
490
|
+
prev_hash = args[3].value if hasattr(args[3], 'value') else str(args[3])
|
|
491
|
+
nonce = int(args[4].value if hasattr(args[4], 'value') else args[4]) if len(args) > 4 else 0
|
|
492
|
+
try:
|
|
493
|
+
result = BlockchainModule.create_block(index, timestamp, data, prev_hash, nonce)
|
|
494
|
+
return _python_to_zexus(result)
|
|
495
|
+
except Exception as e:
|
|
496
|
+
return EvaluationError(f"create_block error: {str(e)}")
|
|
497
|
+
|
|
498
|
+
def _blockchain_hash_block(*args):
|
|
499
|
+
if len(args) < 1:
|
|
500
|
+
return EvaluationError("hash_block() requires 1 argument: block (map)")
|
|
501
|
+
block_obj = args[0]
|
|
502
|
+
block = {}
|
|
503
|
+
if isinstance(block_obj, Map):
|
|
504
|
+
for k, v in block_obj.pairs.items():
|
|
505
|
+
key = k.value if hasattr(k, 'value') else str(k)
|
|
506
|
+
val = v.value if hasattr(v, 'value') else str(v)
|
|
507
|
+
block[key] = val
|
|
508
|
+
try:
|
|
509
|
+
result = BlockchainModule.hash_block(block)
|
|
510
|
+
return String(result)
|
|
511
|
+
except Exception as e:
|
|
512
|
+
return EvaluationError(f"hash_block error: {str(e)}")
|
|
513
|
+
|
|
514
|
+
def _blockchain_validate_block(*args):
|
|
515
|
+
if len(args) < 1:
|
|
516
|
+
return EvaluationError("validate_block() requires 1 argument: block")
|
|
517
|
+
block_obj = args[0]
|
|
518
|
+
block = {}
|
|
519
|
+
if isinstance(block_obj, Map):
|
|
520
|
+
for k, v in block_obj.pairs.items():
|
|
521
|
+
key = k.value if hasattr(k, 'value') else str(k)
|
|
522
|
+
val = v.value if hasattr(v, 'value') else str(v)
|
|
523
|
+
block[key] = val
|
|
524
|
+
prev = None
|
|
525
|
+
if len(args) > 1 and isinstance(args[1], Map):
|
|
526
|
+
prev = {}
|
|
527
|
+
for k, v in args[1].pairs.items():
|
|
528
|
+
key = k.value if hasattr(k, 'value') else str(k)
|
|
529
|
+
val = v.value if hasattr(v, 'value') else str(v)
|
|
530
|
+
prev[key] = val
|
|
531
|
+
try:
|
|
532
|
+
result = BlockchainModule.validate_block(block, prev)
|
|
533
|
+
return Boolean(result)
|
|
534
|
+
except Exception as e:
|
|
535
|
+
return EvaluationError(f"validate_block error: {str(e)}")
|
|
536
|
+
|
|
537
|
+
def _blockchain_proof_of_work(*args):
|
|
538
|
+
if len(args) < 1:
|
|
539
|
+
return EvaluationError("proof_of_work() requires 1 argument: block_data")
|
|
540
|
+
block_data = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
541
|
+
difficulty = int(args[1].value if hasattr(args[1], 'value') else args[1]) if len(args) > 1 else 4
|
|
542
|
+
max_iter = int(args[2].value if hasattr(args[2], 'value') else args[2]) if len(args) > 2 else 1000000
|
|
543
|
+
try:
|
|
544
|
+
nonce, hash_val = BlockchainModule.proof_of_work(block_data, difficulty, max_iter)
|
|
545
|
+
return _python_to_zexus({"nonce": nonce, "hash": hash_val})
|
|
546
|
+
except Exception as e:
|
|
547
|
+
return EvaluationError(f"proof_of_work error: {str(e)}")
|
|
548
|
+
|
|
549
|
+
def _blockchain_create_transaction(*args):
|
|
550
|
+
if len(args) < 3:
|
|
551
|
+
return EvaluationError("create_transaction() requires 3 args: sender, recipient, amount")
|
|
552
|
+
sender = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
553
|
+
recipient = args[1].value if hasattr(args[1], 'value') else str(args[1])
|
|
554
|
+
amount = float(args[2].value if hasattr(args[2], 'value') else args[2])
|
|
555
|
+
timestamp = float(args[3].value if hasattr(args[3], 'value') else args[3]) if len(args) > 3 else None
|
|
556
|
+
try:
|
|
557
|
+
result = BlockchainModule.create_transaction(sender, recipient, amount, timestamp)
|
|
558
|
+
return _python_to_zexus(result)
|
|
559
|
+
except Exception as e:
|
|
560
|
+
return EvaluationError(f"create_transaction error: {str(e)}")
|
|
561
|
+
|
|
562
|
+
def _blockchain_hash_transaction(*args):
|
|
563
|
+
if len(args) < 1:
|
|
564
|
+
return EvaluationError("hash_transaction() requires 1 argument: transaction")
|
|
565
|
+
tx_obj = args[0]
|
|
566
|
+
tx = {}
|
|
567
|
+
if isinstance(tx_obj, Map):
|
|
568
|
+
for k, v in tx_obj.pairs.items():
|
|
569
|
+
key = k.value if hasattr(k, 'value') else str(k)
|
|
570
|
+
val = v.value if hasattr(v, 'value') else str(v)
|
|
571
|
+
tx[key] = val
|
|
572
|
+
try:
|
|
573
|
+
result = BlockchainModule.hash_transaction(tx)
|
|
574
|
+
return String(result)
|
|
575
|
+
except Exception as e:
|
|
576
|
+
return EvaluationError(f"hash_transaction error: {str(e)}")
|
|
577
|
+
|
|
578
|
+
def _blockchain_validate_chain(*args):
|
|
579
|
+
if len(args) < 1:
|
|
580
|
+
return EvaluationError("validate_chain() requires 1 argument: chain (list of blocks)")
|
|
581
|
+
if not isinstance(args[0], ListObj):
|
|
582
|
+
return EvaluationError("validate_chain() expects a list of block maps")
|
|
583
|
+
chain = []
|
|
584
|
+
for block_obj in args[0].elements:
|
|
585
|
+
block = {}
|
|
586
|
+
if isinstance(block_obj, Map):
|
|
587
|
+
for k, v in block_obj.pairs.items():
|
|
588
|
+
key = k.value if hasattr(k, 'value') else str(k)
|
|
589
|
+
val = v.value if hasattr(v, 'value') else str(v)
|
|
590
|
+
block[key] = val
|
|
591
|
+
chain.append(block)
|
|
592
|
+
try:
|
|
593
|
+
result = BlockchainModule.validate_chain(chain)
|
|
594
|
+
return Boolean(result)
|
|
595
|
+
except Exception as e:
|
|
596
|
+
return EvaluationError(f"validate_chain error: {str(e)}")
|
|
597
|
+
|
|
286
598
|
env.set("create_address", Builtin(_blockchain_create_address))
|
|
287
599
|
env.set("validate_address", Builtin(_blockchain_validate_address))
|
|
288
600
|
env.set("calculate_merkle_root", Builtin(_blockchain_calculate_merkle_root))
|
|
289
601
|
env.set("create_genesis_block", Builtin(_blockchain_create_genesis_block))
|
|
290
|
-
|
|
602
|
+
env.set("create_block", Builtin(_blockchain_create_block))
|
|
603
|
+
env.set("hash_block", Builtin(_blockchain_hash_block))
|
|
604
|
+
env.set("validate_block", Builtin(_blockchain_validate_block))
|
|
605
|
+
env.set("proof_of_work", Builtin(_blockchain_proof_of_work))
|
|
606
|
+
env.set("create_transaction", Builtin(_blockchain_create_transaction))
|
|
607
|
+
env.set("hash_transaction", Builtin(_blockchain_hash_transaction))
|
|
608
|
+
env.set("validate_chain", Builtin(_blockchain_validate_chain))
|
|
609
|
+
|
|
610
|
+
elif module_name == "websocket" or module_name == "stdlib/websocket":
|
|
611
|
+
try:
|
|
612
|
+
from .stdlib.websockets import WebSocketModule
|
|
613
|
+
except ImportError:
|
|
614
|
+
return env # websockets package not installed
|
|
615
|
+
|
|
616
|
+
def _ws_create_server(*args):
|
|
617
|
+
if len(args) < 3:
|
|
618
|
+
return EvaluationError("ws_create_server() requires 3 args: host, port, handler")
|
|
619
|
+
host = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
620
|
+
port = int(args[1].value if hasattr(args[1], 'value') else args[1])
|
|
621
|
+
handler = args[2] # Zexus Action/Builtin — caller wraps
|
|
622
|
+
path = args[3].value if len(args) > 3 and hasattr(args[3], 'value') else None
|
|
623
|
+
try:
|
|
624
|
+
server = WebSocketModule.create_server(host, port, handler, path)
|
|
625
|
+
server.start()
|
|
626
|
+
stop_fn = Builtin(lambda *_a: (server.stop(), Boolean(True))[1])
|
|
627
|
+
is_running_fn = Builtin(lambda *_a: Boolean(server.is_running()))
|
|
628
|
+
return Map({
|
|
629
|
+
String("stop"): stop_fn,
|
|
630
|
+
String("is_running"): is_running_fn,
|
|
631
|
+
})
|
|
632
|
+
except Exception as e:
|
|
633
|
+
return EvaluationError(f"ws_create_server error: {e}")
|
|
634
|
+
|
|
635
|
+
def _ws_connect(*args):
|
|
636
|
+
if len(args) < 1:
|
|
637
|
+
return EvaluationError("ws_connect() requires 1 arg: url")
|
|
638
|
+
url = args[0].value if hasattr(args[0], 'value') else str(args[0])
|
|
639
|
+
timeout = float(args[1].value if len(args) > 1 and hasattr(args[1], 'value') else 10)
|
|
640
|
+
try:
|
|
641
|
+
client = WebSocketModule.connect(url, timeout)
|
|
642
|
+
send_fn = Builtin(lambda *a: (client.send(a[0].value if hasattr(a[0], 'value') else str(a[0])), Boolean(True))[1])
|
|
643
|
+
recv_fn = Builtin(lambda *a: String(client.receive(float(a[0].value) if a else 30)))
|
|
644
|
+
close_fn = Builtin(lambda *_a: (client.close(), Boolean(True))[1])
|
|
645
|
+
connected_fn = Builtin(lambda *_a: Boolean(client.is_connected()))
|
|
646
|
+
return Map({
|
|
647
|
+
String("send"): send_fn,
|
|
648
|
+
String("receive"): recv_fn,
|
|
649
|
+
String("close"): close_fn,
|
|
650
|
+
String("is_connected"): connected_fn,
|
|
651
|
+
})
|
|
652
|
+
except Exception as e:
|
|
653
|
+
return EvaluationError(f"ws_connect error: {e}")
|
|
654
|
+
|
|
655
|
+
env.set("create_server", Builtin(_ws_create_server))
|
|
656
|
+
env.set("connect", Builtin(_ws_connect))
|
|
657
|
+
|
|
291
658
|
return env
|
|
292
659
|
|
|
293
660
|
|
|
@@ -323,7 +690,7 @@ def _zexus_to_python(obj):
|
|
|
323
690
|
|
|
324
691
|
def is_stdlib_module(module_name):
|
|
325
692
|
"""Check if a module name refers to a stdlib module."""
|
|
326
|
-
stdlib_modules = ['fs', 'http', 'json', 'datetime', 'crypto', 'blockchain']
|
|
693
|
+
stdlib_modules = ['fs', 'http', 'json', 'datetime', 'crypto', 'blockchain', 'perf', 'websocket']
|
|
327
694
|
|
|
328
695
|
# Handle both "fs" and "stdlib/fs" formats
|
|
329
696
|
if module_name in stdlib_modules:
|