Autohotkey concerning Websocket | Winhttp and stuff question - websocket

Trying to get trading information via websocket method. There are many guides and manuals for other languages, I would like to get it via Autohotkey preferably.
Below is the code that I am using when receiving info with Autohotkey.
Get_Price(Target_Site, Target_Coin, Price_Type = "KRW") {
if (Target_Site = "UpBit") {
API_Url := "https://crix-api-endpoint.upbit.com/v1/crix/candles/minutes/10?code=CRIX.UPBIT."
}
Result_URL := API_Url "" Price_Type "-" Target_Coin
Result_Json := Get_WinHttp(Result_URL)
RegExMatch(Result_Json, "tradePrice"`":(.*?)\.", Result) ;If(Target_Coin="BTT") Or (Target_Coin="DOGE") If(Target_Coin="BTT") Or (Target_Coin="DOGE")RegExMatch(Result_Json, "tradePrice"`":(.*?)\,", Result)
Return Result1
}
It seems like the approach above was kinda more explicit and easy compared to Websocket. Only thing I had to was forming right url with my info and sending that url and get the result from the website.
But, when it comes to websocket, I know of the right url, right info to send, but don't know how I can send and .. yeah how.
Url : wss://api.upbit.com/websocket/v1
What to send : '[{"ticket":"test1243563456"},{"type":"trade",{"type":"trade","codes":["KRW-BTC", "KRW-ETH"]}]'
How : I don't know. But I happen to come across some interesting AHK example, I am wishing I can modifying this. Will appreciate if you can have a look and guide me if possible.
#Include, Websocket.Ahk
class Example extends WebSocket
{
OnOpen(Event)
{
InputBox, Data, WebSocket, Enter some text to send through the websocket.
If (ErrorLevel==1)
this.Close()
this.Send(Data)
}
OnMessage(Event)
{
MsgBox, % "Received Data: " Event.data
new Example("wss://echo.websocket.org/")
}
OnClose(Event)
{
MsgBox, Websocket Closed
this.Disconnect()
}

First things first, in AHK v1 you escape quotes by doing a double quote "".
Here "tradePrice"`":(.*?)\." your resulting string has a double quote in it by pretty much sheer luck.
Actually it's supposed to be done like this: "tradePrice"":(.*?)\.".
You'll need to correctly escape quotes in what you're going to do next.
Also, since you have a json response, you might want to parse the json and use it how it's supposed to be used.(See AHK JSON/Jxon)
So about the websocket.
Personally I'd say G33kDude's example(Github) explains it pretty well, but maybe you were thrown off by the object oriented code style choice he's made for it.
It's not that easy to understand if you're not experienced with OOP/OOP AHK I guess.
Here's an example for calling an echo websocket with the data you wanted to send.
#Include WebSocket.ahk
New HelperClass("wss://echo.websocket.org/")
class HelperClass extends WebSocket
{
OnOpen(Event)
{
DataToSend := "[{""ticket"":""test1243563456""},{""type"":""trade"",{""type"":""trade"",""codes"":[""KRW-BTC"", ""KRW-ETH""]}]"
this.Send(DataToSend)
}
OnMessage(event)
{
MsgBox, % "Received a message!:`n" Event.data
this.Close()
}
OnClose(Event)
{
MsgBox, Websocket Closed
this.Disconnect()
}
OnError(Event)
{
MsgBox, Websocket Error
}
__Delete()
{
MsgBox, Exiting
ExitApp
}
}
You have to make this class that extends the WebSocket class due to how it's designed, but it's actually pretty convenient if you know OOP (AHK).
So here's how it works:
New HelperClass("wss://echo.websocket.org/")
You prepare the behind the scenes magic open a websocket connection to the specified websocket
The OnOpen() function runs in your HelperClass once the magic has been prepared
this.Send(DataToSend)
You call the Send function (which if found inside the WebSocket class) and pass in the data you want
You receive a response message (OnMessage() runs in your HelperClass), or maybe you receive an error (OnError() runs in your HelperClass)
The connection closes, so OnClose() runs in your HelperClass.
And you also want to reset the behind the scenes magic by calling Disconnect() function inside the WebSocket class by doing this.Disconnect()
(When I say inside HelperClass or inside WebSocket class, it's actually incorrect because they're kind of the same class, you're just extending WebSocket class with your HelperClass)
So that's about it.
Misc notes:
Download the WebSocket class from G33kDude's GitHub and include the WebSocket.ahk file to your own script with #Include(docs).
G33kDude example script uses #Include ../WebSocket.ahk to include it, because his example script is in a subfolder, so he goes back one folder with .. and then specifies the file to include.
Also note how the quotation marks are correctly escaped in the DataToSend variable.

Related

How can I use `firstValueFrom` with `WebSocketSubject` without closing the underlying web socket?

I am using a WebSocketSubject, and I often want to block execution until a given event arrives, which is why I use firstValueFrom, like in the following code:
let websocket = new WebSocketSubject<any>(url);
let firstMessage = await firstValueFrom(websocket.pipe(filter(m => true));
I only have one issue, which is that firstValueFrom calls websocket.unsubscribe() when it resolves the promise, but on a WebSocketSubject that has the effect of closing the underlying Web Socket, which I want to keep open!
Currently, I have thought of a few possible ways out:
Writing an equivalent of firstValueFrom that does not unsubscribe.
Counter argument: I would prefer not reimplementing a function that is nearly perfect, except for one small issue;
Using another Subject that will subscribe to WebSocketSubject, and I will use firstValueFrom on that subject.
Counter argument: In terms of usage, I see potential confusion to have two Subject objects, and having to know which one to use (E.g. Use websocket.next for sending messages upstream, and only use websocketProxy for receiving messages, and never get confused between the two!);
Using multiplex to create temporary Observable objects that will then be closed by firstValueFrom without issue.
Counter argument: As I am not actually multiplexing in this case, I would rather not use that method, whose signature and usage seems overkill for my use case.
In short, I suspect that I am missing something basic (e.g. an appropriate OperatorFunction) that would allow me to make it so that the unsubscribe call made by firstValueFrom does not result in the underlying web socket being closed.
Essentially, you want to always have a subscription so the socket connection stays open. I don't think firstValueFrom is the proper tool for the job. I think its simpler to just create an explicit subscription.
If the intent is to keep it open for the lifetime of the app, just subscribe at app launch.
Since you want to filter out the first several emissions until some condition is met, you can use skipWhile:
const websocket = new WebSocketSubject<any>(url);
const messages = websocket.pipe(skipWhile(m => m !== 'my special event'));
websocket.subscribe(); // keep socket open
// listen
messages.subscribe(m => console.log('message received:', m);
// send
websocket.next('hello server');
It may be worth creating a light wrapper class around the rxjs websocket that handles keeping the connection open and filtering out the first few events:
class MyWebsocket {
private websocket = new WebSocketSubject<any>(this.url);
public messages = websocket.pipe(skipWhile(m => m !== 'my special event'));
constructor(private url) {
this.websocket.subscribe(); // keep socket open
}
public sendMessage(message: any) {
this.websocket.sendMessage(message);
}
}
const websocket = new MyWebsocket(url);
// listen
websocket.messages.subscribe(m => console.log('message received:', m);
// send
websocket.sendMessage('hello server');

Mono returned by ServerRequest.bodyToMono() method not extracting the body if I return ServerResponse immediately

I am using web reactive in spring web flux. I have implemented a Handler function for POST request. I want the server to return immediately. So, I have implemeted the handler as below -:
public class Sample implements HandlerFunction<ServerResponse>{
public Mono<ServerResponse> handle(ServerRequest request) {
Mono bodyMono = request.bodyToMono(String.class);
bodyMono.map(str -> {
System.out.println("body got is " + str);
return str;
}).subscribe();
return ServerResponse.status(HttpStatus.CREATED).build();
}
}
But the print statement inside the map function is not getting called. It means the body is not getting extracted.
If I do not return the response immediately and use
return bodyMono.then(ServerResponse.status(HttpStatus.CREATED).build())
then the map function is getting called.
So, how can I do processing on my request body in the background?
Please help.
EDIT
I tried using flux.share() like below -:
Flux<String> bodyFlux = request.bodyToMono(String.class).flux().share();
Flux<String> processFlux = bodyFlux.map(str -> {
System.out.println("body got is");
try{
Thread.sleep(1000);
}catch (Exception ex){
}
return str;
});
processFlux.subscribeOn(Schedulers.elastic()).subscribe();
return bodyFlux.then(ServerResponse.status(HttpStatus.CREATED).build());
In the above code, sometimes the map function is getting called and sometimes not.
As you've found, you can't just arbitrarily subscribe() to the Mono returned by bodyToMono(), since in that case the body simply doesn't get passed into the Mono for processing. (You can verify this by putting a single() call in that Mono, it'll throw an exception since no element will be emitted.)
So, how can I do processing on my request body in the background?
If you really still want to just use reactor to do a long task in the background while returning immediately, you can do something like:
return request.bodyToMono(String.class).doOnNext(str -> {
Mono.just(str).publishOn(Schedulers.elastic()).subscribe(s -> {
System.out.println("proc start!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("proc end!");
});
}).then(ServerResponse.status(HttpStatus.CREATED).build());
This approach immediately publishes the emitted element to a new Mono, set to publish on an elastic scheduler, that is then subscribed in the background. However, it's kind of ugly, and it's not really what reactor is designed to do. You may be misunderstanding the idea behind reactor / reactive programming here:
It's not written with the idea of "returning a quick result and then doing stuff in the background" - that's generally the purpose of a work queue, often implemented with something like RabbitMQ or Kafka. It's "raison d'être" is instead to be non-blocking, so a single thread is never idly blocked, waiting for something else to complete.
The map() method isn't designed for side effects, it's designed to transform each object into another. For side effects, you want doOnNext() instead;
Reactor uses a single thread by default, so your "additional processing" in your map() method would still block that thread.
If your application is for anything more than quick demo purposes, and/or you need to make heavy use of this pattern, then I'd seriously consider setting up a proper work queue instead.
This is not possible.
Web servers (including Reactor Netty, Tomcat, etc) clean up and recycle resources when request processing is done. This means that when your controller handler is done, the HTTP resources, the request itself, reusable buffers, etc are recycled or closed. At that point, you cannot read from the request body anymore.
In your case, you need to read and buffer the whole request body first, then return a response and kick off a task for processing that request in a separate execution.

How to make Camel's "Netty4" component output an endpoint's results, but NOT echo back all the input as well?

I am experimenting with using Apache Camel to implement a TCP game server. It will accept bi-directional, synchronous telnet or SSH connections from multiple human or bot players.
The communication "protocol" is a bit crude, and based on legacy infrastructure that's already in place from an earlier version. Basically, the client and server exchange I/O over a socket (one connection per client).
Usually, this consists of one-line command strings, or one-line response strings. However, in some cases the input or output can span multiple line breaks before it is considered "complete" and ready for the other side's response. So my plan is to:
Create a TCP socket server using Spring Boot and Apache Camel, with the latter's "Netty4" component.
Use aggregation to collect the incoming lines of text from a socket connection. Roll them up into messages of one or more lines, depending on the type of input detected.
Pass the resulting message to an endpoint, which parses the input and returns the appropriate response back to the socket.
I can show any other code or Spring config, but the heart of my question seems to be the route I'm declaring:
#Component
public class EchoRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
// "sync=true" seems necessary to return any response to the client at all
//
// "textline=true&autoAppendDelimiter=false" seem necessary to properly handle
// the socket input at newline-terminated strings, rather than processing
// input byte-by-byte
from("netty4:tcp://localhost:4321?sync=true&textline=true&autoAppendDelimiter=false")
// This line, and the corresponding `.header("incoming")` line below, are
// perhaps a bit dodgy. I'm assuming that all messages on the route
// from a given client socket are already effectively "correlated", and
// that messages from multiple client sockets are not inter-mingled
// here. So I'm basically wildcard-ing the correlation mechanism. If my
// assumption is wrong, then I'm not sure how to correlate by
// client socket.
.setHeader("incoming", constant(true))
// Taken from numerous examples I've seen in Camel books and website
// pages. Just concatenates the correlated messages until
// completion occurs.
.aggregate(new AggregationStrategy() {
#Override
public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
if (oldExchange == null) {
return newExchange;
}
final String oldBody = oldExchange.getIn().getBody(String.class);
final String newBody = newExchange.getIn().getBody(String.class);
oldExchange.getIn().setBody(oldBody + newBody);
return oldExchange;
}
})
// See comment on "setHeader(...) above.
.header("incoming")
// In this initial testing, aggregation of a particular message is
// considered complete when the last line received is "EOM".
.completionPredicate(exchange -> {
final String body = exchange.getIn().getBody(String.class);
final boolean done = body.endsWith("EOM");
return done;
})
// This endpoint will eventually parse the aggregated message and
// perform logic on it. Right now, it just returning the input message
// with a prefix.
.to("bean:echoService");
}
}
When I start my server, and telnet to port 4321 from a separate terminal window, I can verify in the debugger that:
The .completetionPredicate(...) logic is being invoked upon each line of input as expected, and
The echoService endpoint is being invoked as expected after an EOM line of input. The message passed to the endpoint contains the expected aggregated content.
However, there are two problems:
The server is echoing each line of input back to the client connection, rather than letting the endpoint determine the response content.
The server is not sending the endpoint return value to the client. I log it to the server console, but otherwise it's silently discarded.
Any suggestions on what I might be missing here? The desired behavior is for the route to send the endpoint's return value to the client socket, and nothing but the endpoint's return value. Thanks!

How can I ensure the writable flag is true before send()?

I am creating an abstraction layer for Dart WebSocket who is also protocol compatible with Socket.IO, but it has a problem I can not solve.
The follow code convert the HttpRequest into a WebSocket and save the socket instance on the Transport... Here you can see I change the value of the writable flag to true in order to inform the socket is open.
WebSocketTransformer.upgrade(req).then((socket) {
this._socket = socket;
this.writable = true;
this._socket.handleError(() {
this.onClose();
});
// start listen the socket;
socket.listen((packet) {
this.onData(packet);
});
}).catchError((Exception e) {
this.onError('Can\'t conenct with the socket.', e.toString());
});
(The full code can be founded here.)
When I debug the code first the debugger stops inside that closure and only then stops here, where the check is make but writable still false :/
void flush([_]) {
if (this._readyState != SocketStates.closed && this.transport.writable &&
!this._writeBuffer.isEmpty) {
(The full code can be founded here)
I really need help...
Your constructor makes an async call but doesn't return a future (not possible in a constructor)
WebSocketTransformer.upgrade(req).then
Use a static method instead which returns Future<WebSocketTransformer> or use an init method where you initiaize your class after creation.
There might be other problems but yor code does not show how you use your class therefore its hard to tell.

Get room/rooms of client [duplicate]

I can get room's clients list with this code in socket.io 0.9.
io.sockets.clients(roomName)
How can I do this in socket.io 1.0?
Consider this rather more complete answer linked in a comment above on the question: https://stackoverflow.com/a/24425207/1449799
The clients in a room can be found at
io.nsps[yourNamespace].adapter.rooms[roomName]
This is an associative array with keys that are socket ids. In our case, we wanted to know the number of clients in a room, so we did Object.keys(io.nsps[yourNamespace].adapter.rooms[roomName]).length
In case you haven't seen/used namespaces (like this guy[me]), you can learn about them here http://socket.io/docs/rooms-and-namespaces/ (importantly: the default namespace is '/')
Updated (esp. for #Zettam):
checkout this repo to see this working: https://github.com/thegreatmichael/socket-io-clients
Using #ryan_Hdot link, I made a small temporary function in my code, which avoids maintaining a patch. Here it is :
function getClient(roomId) {
var res = [],
room = io.sockets.adapter.rooms[roomId];
if (room) {
for (var id in room) {
res.push(io.sockets.adapter.nsp.connected[id]);
}
}
return res;
}
If using a namespace :
function getClient (ns, id) {
return io.nsps[ns].adapter.rooms[id]
}
Which I use as a temporary fix for io.sockets.clients(roomId) which becomes findClientsSocketByRoomId(roomId).
EDIT :
Most of the time it is worth considering avoiding using this method if possible.
What I do now is that I usually put a client in it's own room (ie. in a room whose name is it's clientID). I found the code more readable that way, and I don't have to rely on this workaround anymore.
Also, I haven't tested this with a Redis adapter.
If you have to, also see this related question if you are using namespaces.
For those of you using namespaces I made a function too that can handle different namespaces. It's quite the same as the answer of nha.
function get_users_by_room(nsp, room) {
var users = []
for (var id in io.of(nsp).adapter.rooms[room]) {
users.push(io.of(nsp).adapter.nsp.connected[id]);
};
return users;
};
As of at least 1.4.5 nha’s method doesn’t work anymore either, and there is still no public api for getting clients in a room. Here is what works for me.
io.sockets.adapter.rooms[roomId] returns an object that has two properties, sockets, and length. The first is another object that has socketId’s for keys, and boolean’s as the values:
Room {
sockets:
{ '/#vQh0q0gVKgtLGIQGAAAB': true,
'/#p9Z7l6UeYwhBQkdoAAAD': true },
length: 2 }
So my code to get clients looks like this:
var sioRoom = io.sockets.adapter.rooms[roomId];
if( sioRoom ) {
Object.keys(sioRoom.sockets).forEach( function(socketId){
console.log("sioRoom client socket Id: " + socketId );
});
}
You can see this github pull request for discussion on the topic, however, it seems as though that functionality has been stripped from the 1.0 pre release candidate for SocketIO.

Resources