importasyncioimportjsonimportosimportrandomimportuuidimportstomperfromwebsocketsimportconnectNODE_URL=os.getenv('NODE_URL','http://libertalia.nemtest.net:7890')WS_URL=NODE_URL.replace(':7890',':7778')print(f'Using node {NODE_URL}')# SockJS has no Python client library.# These helpers wrap the raw WebSocket transport.defsockjs_url(endpoint_url):# SockJS raw WebSocket transport adds a random server and session idserver=random.randint(100,999)session=uuid.uuid4().hexws_base=endpoint_url.replace('http','ws',1)returnf'{ws_base}/{server}/{session}/websocket'asyncdefsend_frame(websocket,frame):# SockJS wraps each client payload as a JSON array of frame stringsawaitwebsocket.send(json.dumps([frame]))asyncdefstomp_connect(websocket):awaitwebsocket.recv()# consume the SockJS open frameawaitsend_frame(websocket,stomper.connect('','',WS_URL,heartbeats=(0,0)))asyncdefstomp_subscribe(websocket,destination,sub_id):awaitsend_frame(websocket,stomper.subscribe(destination,sub_id))asyncdefstomp_unsubscribe(websocket,sub_id):awaitsend_frame(websocket,stomper.unsubscribe(sub_id))asyncdefstomp_disconnect(websocket):awaitsend_frame(websocket,stomper.disconnect())defstomp_messages(raw_frame):# Yield the JSON body of each STOMP MESSAGE in a SockJS data frameif'a'!=raw_frame[0]:# skip 'o' open, 'h' heartbeat, 'c' closereturnforpayloadinjson.loads(raw_frame[1:]):frame=stomper.unpack_frame(payload)if'MESSAGE'==frame['cmd']:yieldjson.loads(frame['body'])asyncdefmain():# Open connectionasyncwithconnect(sockjs_url(f'{WS_URL}/w/messages'))aswebsocket:awaitstomp_connect(websocket)print(f'Connected to {WS_URL}')# Subscribe to the new block channeldestination='/blocks'awaitstomp_subscribe(websocket,destination,'id-0')print(f'Subscribed to {destination} channel')# Read and format each new blocktry:asyncforraw_frameinwebsocket:forblockinstomp_messages(raw_frame):print(f'New block: height={block["height"]:,}'f' harvester={block["signer"][:16].upper()}...')# Unsubscribe on exitfinally:awaitstomp_unsubscribe(websocket,'id-0')awaitstomp_disconnect(websocket)print('Unsubscribed and disconnected')try:asyncio.run(main())exceptKeyboardInterrupt:passexceptExceptionaserror:print(error)
import{Client}from'@stomp/stompjs';importSockJSfrom'sockjs-client';constNODE_URL=process.env.NODE_URL||'http://libertalia.nemtest.net:7890';constWS_URL=NODE_URL.replace(':7890',':7778');console.log(`Using node ${NODE_URL}`);// Open connectionconstclient=newClient({webSocketFactory:()=>newSockJS(`${WS_URL}/w/messages`)});awaitnewPromise(resolve=>{client.onConnect=resolve;client.activate();});console.log(`Connected to ${WS_URL}`);// Read and format each new blockfunctionformatBlock(message){constblock=JSON.parse(message.body);console.log(`New block: height=${block.height.toLocaleString()}`+` harvester=${block.signer.substring(0,16).toUpperCase()}...`);}// Subscribe to the new block channelconstdestination='/blocks';constsubscription=client.subscribe(destination,formatBlock,{id:'id-0'});console.log(`Subscribed to ${destination} channel`);// Unsubscribe on exitprocess.on('SIGINT',()=>{subscription.unsubscribe();client.deactivate();console.log('Unsubscribed and disconnected');process.exit(0);});
//JAVA 21+//DEPS com.fasterxml.jackson.core:jackson-databind:2.17.1//DEPS org.glassfish.tyrus.bundles:tyrus-standalone-client:2.2.0importjava.io.IOException;importjava.net.URI;importjava.util.UUID;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ThreadLocalRandom;importcom.fasterxml.jackson.databind.JsonNode;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.node.ArrayNode;importjakarta.websocket.ClientEndpoint;importjakarta.websocket.ContainerProvider;importjakarta.websocket.OnMessage;importjakarta.websocket.RemoteEndpoint;importjakarta.websocket.Session;importjakarta.websocket.WebSocketContainer;@ClientEndpointpublicfinalclassListenNewBlocks{privatestaticfinalObjectMapperJSON_MAPPER=newObjectMapper();privatefinalCompletableFuture<Void>openFuture=newCompletableFuture<>();privatefinalStringnodeUrl=System.getenv().getOrDefault("NODE_URL","http://libertalia.nemtest.net:7890");privatefinalStringwsUrl=nodeUrl.replace(":7890",":7778");publicstaticvoidmain(finalString[]args){try{newListenNewBlocks().run();}catch(finalExceptionex){System.out.println(null==ex.getMessage()?ex.toString():ex.getMessage());}}privatevoidrun()throwsException{System.out.printf("Using node %s%n",nodeUrl);// Open connectionfinalWebSocketContainercontainer=ContainerProvider.getWebSocketContainer();finalSessionsession=container.connectToServer(this,URI.create(sockJsUrl(wsUrl+"/w/messages")));finalRemoteEndpoint.Basicremote=session.getBasicRemote();openFuture.join();sendFrame(remote,"CONNECT\naccept-version:1.1,1.0\n"+"heart-beat:0,0\nhost:"+wsUrl+"\n\n\0");System.out.printf("Connected to %s%n",wsUrl);// Subscribe to the new block channelfinalStringdestination="/blocks";sendFrame(remote,"SUBSCRIBE\nid:id-0\ndestination:"+destination+"\nack:auto\n\n\0");System.out.printf("Subscribed to %s channel%n",destination);// Unsubscribe on exitRuntime.getRuntime().addShutdownHook(newThread(()->{try{sendFrame(remote,"UNSUBSCRIBE\nid:id-0\n\n\0");sendFrame(remote,"DISCONNECT\n\n\0");session.close();System.out.println("Unsubscribed and disconnected");}catch(finalIOExceptionex){thrownewIllegalStateException(ex);}}));newCompletableFuture<Void>().join();}// Read and format each new block@OnMessagepublicvoidonMessage(finalStringrawFrame)throwsIOException{if("o".equals(rawFrame)){openFuture.complete(null);return;}if(!rawFrame.startsWith("a"))return;for(finalJsonNodepayload:JSON_MAPPER.readTree(rawFrame.substring(1))){finalStringframe=payload.asText();if(!frame.startsWith("MESSAGE\n"))continue;finalintbodyStart=frame.indexOf("\n\n")+2;finalStringbody=frame.substring(bodyStart).replace("\0","");finalJsonNodeblock=JSON_MAPPER.readTree(body);System.out.printf("New block: height=%,d harvester=%s...%n",block.get("height").asLong(),block.get("signer").asText().substring(0,16).toUpperCase());}}privatestaticStringsockJsUrl(finalStringendpoint){finalintserver=ThreadLocalRandom.current().nextInt(100,1000);returnendpoint.replaceFirst("http","ws")+"/"+server+"/"+UUID.randomUUID().toString().replace("-","")+"/websocket";}privatestaticvoidsendFrame(finalRemoteEndpoint.Basicremote,finalStringframe)throwsIOException{finalArrayNodepayload=JSON_MAPPER.createArrayNode();payload.add(frame);remote.sendText(payload.toString());}}
// Open connectionconstclient=newClient({webSocketFactory:()=>newSockJS(`${WS_URL}/w/messages`)});awaitnewPromise(resolve=>{client.onConnect=resolve;client.activate();});console.log(`Connected to ${WS_URL}`);
// Open connectionfinalWebSocketContainercontainer=ContainerProvider.getWebSocketContainer();finalSessionsession=container.connectToServer(this,URI.create(sockJsUrl(wsUrl+"/w/messages")));finalRemoteEndpoint.Basicremote=session.getBasicRemote();openFuture.join();sendFrame(remote,"CONNECT\naccept-version:1.1,1.0\n"+"heart-beat:0,0\nhost:"+wsUrl+"\n\n\0");System.out.printf("Connected to %s%n",wsUrl);
# Subscribe to the new block channeldestination='/blocks'awaitstomp_subscribe(websocket,destination,'id-0')print(f'Subscribed to {destination} channel')
// Subscribe to the new block channelconstdestination='/blocks';constsubscription=client.subscribe(destination,formatBlock,{id:'id-0'});console.log(`Subscribed to ${destination} channel`);
// Subscribe to the new block channelfinalStringdestination="/blocks";sendFrame(remote,"SUBSCRIBE\nid:id-0\ndestination:"+destination+"\nack:auto\n\n\0");System.out.printf("Subscribed to %s channel%n",destination);
# Read and format each new blocktry:asyncforraw_frameinwebsocket:forblockinstomp_messages(raw_frame):print(f'New block: height={block["height"]:,}'f' harvester={block["signer"][:16].upper()}...')
// Read and format each new blockfunctionformatBlock(message){constblock=JSON.parse(message.body);console.log(`New block: height=${block.height.toLocaleString()}`+` harvester=${block.signer.substring(0,16).toUpperCase()}...`);}
// Read and format each new block@OnMessagepublicvoidonMessage(finalStringrawFrame)throwsIOException{if("o".equals(rawFrame)){openFuture.complete(null);return;}if(!rawFrame.startsWith("a"))return;for(finalJsonNodepayload:JSON_MAPPER.readTree(rawFrame.substring(1))){finalStringframe=payload.asText();if(!frame.startsWith("MESSAGE\n"))continue;finalintbodyStart=frame.indexOf("\n\n")+2;finalStringbody=frame.substring(bodyStart).replace("\0","");finalJsonNodeblock=JSON_MAPPER.readTree(body);System.out.printf("New block: height=%,d harvester=%s...%n",block.get("height").asLong(),block.get("signer").asText().substring(0,16).toUpperCase());}}
// Unsubscribe on exitprocess.on('SIGINT',()=>{subscription.unsubscribe();client.deactivate();console.log('Unsubscribed and disconnected');process.exit(0);});
// Unsubscribe on exitRuntime.getRuntime().addShutdownHook(newThread(()->{try{sendFrame(remote,"UNSUBSCRIBE\nid:id-0\n\n\0");sendFrame(remote,"DISCONNECT\n\n\0");session.close();System.out.println("Unsubscribed and disconnected");}catch(finalIOExceptionex){thrownewIllegalStateException(ex);}}));
Using node http://libertalia.nemtest.net:7890
Connected to http://libertalia.nemtest.net:7778
Subscribed to /blocks channel
New block: height=682,352 harvester=95BA0E864CD5EDB3...
New block: height=682,353 harvester=95BA0E864CD5EDB3...
New block: height=682,354 harvester=7C814B3B44B1A98B...
New block: height=682,355 harvester=95BA0E864CD5EDB3...
New block: height=682,356 harvester=95BA0E864CD5EDB3...
Unsubscribed and disconnected