#!/usr/bin/env python3 """ NAC NAC Lens 服务器(Python实现) 提供HTTP RPC和WebSocket接口 """ import json import asyncio import websockets from http.server import HTTPServer, BaseHTTPRequestHandler from threading import Thread import time class NacLensHandler(BaseHTTPRequestHandler): """NRPC HTTP处理器""" def do_POST(self): """处理POST请求""" content_length = int(self.headers['Content-Length']) post_data = self.rfile.read(content_length) try: request = json.loads(post_data.decode('utf-8')) response = self.handle_rpc_request(request) self.send_response(200) self.send_header('Content-Type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() self.wfile.write(json.dumps(response).encode('utf-8')) except Exception as e: self.send_error(500, str(e)) def do_OPTIONS(self): """处理OPTIONS请求(CORS预检)""" self.send_response(200) self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS') self.send_header('Access-Control-Allow-Headers', 'Content-Type') self.end_headers() def handle_rpc_request(self, request): """处理RPC请求""" method = request.get('method', '') params = request.get('params', []) request_id = request.get('id', 1) # 模拟响应 if method == 'nrpc_getChainInfo': result = { 'chainId': 20260131, 'chainName': 'NAC Testnet', 'consensus': 'CBPP', 'blockHeight': 850, 'tps': 3000, 'activeNodes': 1 } elif method == 'nrpc_getBlockByNumber': result = { 'epoch': 0, 'round': 850, 'branch': 0, 'hash': '0x711d16878e525fd1', 'timestamp': int(time.time() * 1000), 'transactions': [], 'producer': '0x' + '02' * 33 } elif method == 'nrpc_getBalance': result = { 'address': params[0] if params else '0x' + '1' * 40, 'balance': '1000000000000000000000', 'unit': 'wei' } elif method == 'nrpc_getAssetToken': result = { 'tokenId': params[0] if params else '0x9f2462e690ea37e9', 'assetType': 'RealEstate', 'owner': '0x' + '1' * 40, 'valuationUSD': 5000000, 'status': 'Active' } elif method == 'nrpc_getEquityToken': result = { 'contractAddress': params[0] if params else '0x40ee5fcd27e00259', 'name': 'Property Equity Token', 'symbol': 'PET', 'totalSupply': '1000000000000000000000000', 'holders': 100 } elif method == 'nrpc_getStakingInfo': result = { 'stakingId': params[0] if params else '0xed12d6f40e171622', 'stakedAmount': '800000000000000000000000', 'stakingRatio': 0.8, 'issuedTokens': '1000000000000000000000000' } else: return { 'jsonrpc': '2.0', 'id': request_id, 'error': { 'code': -32601, 'message': f'Method not found: {method}' } } return { 'jsonrpc': '2.0', 'id': request_id, 'result': result } def log_message(self, format, *args): """自定义日志""" print(f"[NRPC HTTP] {format % args}") async def websocket_handler(websocket, path): """WebSocket处理器""" print(f"[NRPC WS] 新连接: {websocket.remote_address}") try: async for message in websocket: try: request = json.loads(message) method = request.get('method', '') if method == 'nrpc_subscribe': # 订阅请求 subscription_type = request.get('params', [])[0] if request.get('params') else 'newBlocks' subscription_id = f"sub_{int(time.time() * 1000)}" response = { 'jsonrpc': '2.0', 'id': request.get('id', 1), 'result': subscription_id } await websocket.send(json.dumps(response)) # 开始推送数据 asyncio.create_task(push_subscription_data(websocket, subscription_id, subscription_type)) elif method == 'nrpc_unsubscribe': # 取消订阅 response = { 'jsonrpc': '2.0', 'id': request.get('id', 1), 'result': True } await websocket.send(json.dumps(response)) else: # 普通RPC请求 handler = NacLensHandler(None, None, None) result = handler.handle_rpc_request(request) await websocket.send(json.dumps(result)) except json.JSONDecodeError: error_response = { 'jsonrpc': '2.0', 'error': { 'code': -32700, 'message': 'Parse error' } } await websocket.send(json.dumps(error_response)) except websockets.exceptions.ConnectionClosed: print(f"[NRPC WS] 连接关闭: {websocket.remote_address}") async def push_subscription_data(websocket, subscription_id, subscription_type): """推送订阅数据""" try: while True: await asyncio.sleep(5) # 每5秒推送一次 if subscription_type == 'newBlocks': data = { 'jsonrpc': '2.0', 'method': 'nrpc_subscription', 'params': { 'subscription': subscription_id, 'result': { 'epoch': 0, 'round': int(time.time()) % 1000, 'branch': 0, 'hash': f"0x{int(time.time()):016x}", 'timestamp': int(time.time() * 1000) } } } elif subscription_type == 'balance': data = { 'jsonrpc': '2.0', 'method': 'nrpc_subscription', 'params': { 'subscription': subscription_id, 'result': { 'address': '0x' + '1' * 40, 'balance': str(int(time.time() * 1000000000000000000)), 'timestamp': int(time.time() * 1000) } } } else: continue await websocket.send(json.dumps(data)) print(f"[NRPC WS] 推送数据: {subscription_type}") except websockets.exceptions.ConnectionClosed: print(f"[NRPC WS] 订阅连接关闭: {subscription_id}") def start_http_server(): """启动HTTP服务器""" server = HTTPServer(('0.0.0.0', 18545), NacLensHandler) print("✅ NRPC HTTP服务器启动: http://0.0.0.0:18545") server.serve_forever() async def start_websocket_server(): """启动WebSocket服务器""" async with websockets.serve(websocket_handler, '0.0.0.0', 18546): print("✅ NRPC WebSocket服务器启动: ws://0.0.0.0:18546") await asyncio.Future() # 保持运行 def main(): """主函数""" print("========================================") print("NAC NAC Lens 服务器") print("版本: 1.0.0") print("协议: NAC Lens (神经网络区块链协议)") print("========================================") print() # 启动HTTP服务器(在单独线程中) http_thread = Thread(target=start_http_server, daemon=True) http_thread.start() # 启动WebSocket服务器(在主线程中) asyncio.run(start_websocket_server()) if __name__ == '__main__': main()