How do I connect to RabbitMQ from my ReactJS application? - reactjs

Im having trouble connecting to a RabbitMQ instance and can not find a good tutorial or guide for doing so. I can connect to a RabbitMQ websocket by
var ws = new WebSocket('ws://localhost:15674/ws')
But now I don't know how to connect to my cluster with my credentials. I also need to consume messages from a queue like this /exchange/myExchange/routingKey. I was able to easily do this in angular application by using RxStompService with the following code
rxStompService.configure({
brokerURL: `ws://localhost:15674/ws`,
connectHeaders: {
login: 'guest',
passcode: 'guest'
},
heartbeatIncoming: 0, // Typical value 0 - disabled
heartbeatOutgoing: 20000, // Typical value 20000 - every 20 seconds
reconnectDelay: 200,
debug: (msg: string): void => {
console.log(new Date(), msg);
}
})
this.exchange = 'myExchange'
this.routingKey = 'routingKey'
this.headers ={
'x-queue-name': 'myQueue',
'durable': 'true',
'auto-delete': 'false'
}
ngOnInit() {
this.rxStompService.watch(`/exchange/${this.exchange}/${this.routingKey}`, this.headers ).subscribe((message: Message) => {
this.user = new User(JSON.parse(message.body))
});
}
How can I do the same but from my react app?

I was able to connect and subscribe to a queue by using stompjs.
import Stomp from 'stompjs'
export function connectRabbit(){
let stompClient
var ws = new WebSocket('ws://localhost:15674/ws')
const headers = {
'login': 'guest',
'passcode': 'guest',
'durable': 'true',
'auto-delete': 'false'
}
stompClient = Stomp.over(ws)
stompClient.connect(headers , function(frame){
console.log('Connected')
const subscription = stompClient.subscribe('/queue/myQueue', function(message){
console.log(message)
})
})
}

Related

Error connect to Spring-boot-Rsocket (Auth JWT) from web-client RSocketWebSocketClient

The connection to server with spring-boot client works good:
public RSocketAdapter() throws IOException {
requester = createRSocketRequesterBuilder()
.connectWebSocket(URI.create("ws://localhost:7878/"))
.block();
}
private RSocketRequester.Builder createRSocketRequesterBuilder() {
RSocketStrategies strategies = RSocketStrategies.builder()
.encoders(encoders -> encoders.add(new Jackson2CborEncoder()))
.decoders(decoders -> decoders.add(new Jackson2CborDecoder()))
.dataBufferFactory(new NettyDataBufferFactory(PooledByteBufAllocator.DEFAULT))
.build();
return RSocketRequester.builder().rsocketStrategies(strategies);
}
public Mono<HelloToken> signIn(String principal, String credential) {
return requester
.route("signin.v1")
.data(HelloUser.builder().userId(principal).password(credential).build())
.retrieveMono(HelloToken.class)
.doOnNext(token -> {
accessToken = token.getAccessToken();
})
.onErrorStop();
}
And server receives such frame:
Correct byte frame
But the same request from web-client:
authSocketReactiv = () => {
const maxRSocketRequestN = 2147483647;
const keepAlive = 60000;
const lifetime = 180000;
const dataMimeType = 'application/json';
const metadataMimeType = 'message/x.rsocket.authentication.bearer.v0';
var client = new RSocketClient({
serializers: {
data: JsonSerializer,
metadata: JsonSerializer,
},
setup: {
dataMimeType,
keepAlive,
lifetime,
metadataMimeType
},
transport: new RSocketWebSocketClient({
url: 'ws://localhost:7878'
},Encoders)
});
// Open the connection
client.connect().subscribe({
onComplete: socket => {
socket.requestStream({
data:{
'user_id': '0000',
'password': 'Zero4'
},
metadata:'signin.v1'
}).subscribe({
onComplete: () => console.log('complete'),
onError: error => {
console.log(error);
},
onNext: payload => {
console.log('Subscribe1');
},
onSubscribe: subscription => {
console.log('Subscribe');
subscription.request(2147483647);
},
});
},
onError: error => {
console.log(error);
},
onSubscribe: cancel => {
}
});
Forms the incorrect frame and fall with “metadata is malformed ERROR” :
Error byte frame from web
What encoding or buffering options should be used here? Thanks for any tips and suggestions.
You are likely going to want to work with composite metadata and set your metadataMimeType to MESSAGE_RSOCKET_COMPOSITE_METADATA.string.
The important bit is going to be the routing metadata, which is what tells the server how to route the incoming RSocket request.
I haven't dug through the server example code you linked on StackOverflow, but just by looking at your example code, you would supply the routing metadata with your requestStream as so:
Also, the example project you listed though references signin as a request/response so you actually don't want requestStream, but requestResponse.
socket
.requestResponse({
data: Buffer.from(JSON.stringify({
user_id: '0000',
password: 'Zero4'
})),
metadata: encodeCompositeMetadata([
[MESSAGE_RSOCKET_ROUTING, encodeRoute("signin.v1")],
]),
})
You will likely want to use BufferEncoders, as shown in this example. And additionally, I believe you should not use JsonSerializer for the metadata, but instead IdentitySerializer, which will pass the composite metadata buffer straight through, rather than trying to serialize to and from JSON.
You may still run into some issues, but I suspect that this will get you past the metadata is malformed ERROR error.
Hope that helps.
Grate thanks for the detailed advices. According to directions, this complined solution works for my case:
getAuthToken = () => {
const maxRSocketRequestN = 2147483647;
const keepAlive = 60000;
const lifetime = 180000;
const dataMimeType = APPLICATION_JSON.string;
const metadataMimeType = MESSAGE_RSOCKET_COMPOSITE_METADATA.string;
var client = new RSocketClient({
serializers: {
data: IdentitySerializer,
metadata: IdentitySerializer,
},
setup: {
dataMimeType,
keepAlive,
lifetime,
metadataMimeType
},
transport: new RSocketWebSocketClient({
url: 'ws://localhost:7878'
},BufferEncoders)
});
client.connect().then(
(socket) => {
socket.requestResponse({
data: Buffer.from(JSON.stringify({
user_id: '0000',
password: 'Zero4'
})),
metadata: encodeCompositeMetadata([
[MESSAGE_RSOCKET_ROUTING, encodeRoute("signin.v1")],
]),
}).subscribe({
onComplete: (data) => console.log(data),
onError: error =>
console.error(`Request-stream error:${error.message}`),
});
},
(error) => {
console.log("composite initial connection failed");
}
);

RSocket error 0x201 (APPLICATION_ERROR): readerIndex(1) + length(102) exceeds writerIndex(8): UnpooledSlicedByteBu

setInterval(() => {
let that = this;
this.socket && this.socket.requestResponse({
data: '' + (++index),
metadata: 'org.mvnsearch.account.AccountService.findById',
}).subscribe({
onComplete(payload) {
let account = JSON.parse(payload.data);
that.setState({
nick: account.nick
})
},
onError: (e) => {
console.log('onError', e)
}
});
}, 2000)
trying to connect to spring rsocket using reactjs. getting an error before subscribe in the javascript code shown below.
**this.socket.requestResponse({
data: '' + (++index),
metadata: 'org.mvnsearch.account.AccountService.findById',
})**
How to resolve the above issue?
If you are using rsocket routing on the backend, it is length prefixed. See https://github.com/rsocket/rsocket-demo/blob/master/src/main/js/app.js#L22-L36
// Create an instance of a client
const client = new RSocketClient({
setup: {
keepAlive: 60000,
lifetime: 180000,
dataMimeType: 'application/json',
metadataMimeType: 'message/x.rsocket.routing.v0',
},
transport: new RSocketWebSocketClient({url: url}),
});
const stream = Flowable.just({
data: '{"join": {"name": "Web"}}',
metadata: String.fromCharCode('chat/web'.length) + 'chat/web',
});
The routing specification allows multiple routes, so the encoding of a single route is unfortunately complicated by this. https://github.com/rsocket/rsocket/blob/master/Extensions/Routing.md

SignalR and React - Invocation canceled due to the underlying connection being closed

Good evening.
I am building a chat component using SignalR(5.0.1, I also tried an early version 3.0.0) and dotnet core 3.1.
The comment that any of the users makes can be sent to all the connected clients, and all the connected clients can see the comment. However, the client which sent the comment will disconnect, and an error is caught addComment() in the mobx store.
A client will lose its connection after sending a comment (the sender and the other clients can get the comment which has been processed from ChatHub). I don't know why the server decides to drop the connection and raise an error. I
The error:
[2021-01-10T22:38:14.314Z] Information: Connection disconnected.
adventureStore.ts:73 Error: Invocation canceled due to the underlying connection being closed.
at HubConnection.connectionClosed (HubConnection.ts:654)
at HttpConnection.HubConnection.connection.onclose (HubConnection.ts:103)
at HttpConnection.stopConnection (HttpConnection.ts:488)
at WebSocketTransport.transport.onclose (HttpConnection.ts:410)
at WebSocketTransport.close (WebSocketTransport.ts:135)
at WebSocket.webSocket.onclose (WebSocketTransport.ts:97)
Here are the codes:
startup:
public class Startup
{
// only showing the codes related to problem
services.AddSignalR();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateAudience = false,
ValidateIssuer = false
};
opt.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/chat")))
{
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<ErrorHandlingMiddleware>();
if (env.IsDevelopment())
{
// app.UseDeveloperExceptionPage();
}
// app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<ChatHub>("/chat");
});
}
}
ChatHub.cs:
public class ChatHub : Hub
{
private readonly IMediator _mediator;
public ChatHub(IMediator mediator)
{
_mediator = mediator;
}
public async Task SendComment(Create.Command command)
{
var username = Context.User?.Claims?.FirstOrDefault(x => x.Type ==
ClaimTypes.NameIdentifier)?.Value;
command.Username = username;
var comment = await _mediator.Send(command);
// clients can successfully receive the comment and load it to their mobx store
await Clients.All.SendAsync("ReceiveComment", comment);
}
}
the mobx store where the connection is built:
#observable comments: IComment[] | null = null;
#observable.ref hubConnection: HubConnection | null = null;
#action createHubConnection = () => {
this.hubConnection = new HubConnectionBuilder()
.withUrl("http://localhost:5000/chat", {
accessTokenFactory: () => this.rootStore.commonStore.token!,
})
.configureLogging(LogLevel.Information)
// i have to do this for now. Need to fix that disconnecting right
// after Clients.All.SendAsync("ReceiveComment", comment); in ChatHub.cs
// .withAutomaticReconnect([0, 0, 10000])
.build();
this.hubConnection
.start()
.then(() => console.log(this.hubConnection!.state))
.catch((error) => console.log("Error establishing connection: ", error));
this.hubConnection.on("ReceiveComment", (comment) => {
runInAction(() => {
if (this.comments == null) {
this.comments = new Array<IComment>();
}
this.comments.push(comment);
});
});
};
#action stopHubConnection = () => {
this.hubConnection!.stop();
};
#action addComment = async (values: any) => {
try {
await this.hubConnection!.invoke("SendComment", values);
} catch (error) {
console.log(error);
}
};
I have an Angular client facing same issues when connect to SignalR Hub in Asp.net Core 3.1. The applied NuGet package is "Microsoft.AspNetCore.SignalR.Core" version 1.1.0. After upgrade Asp.net Web API portal to .Net 5.0. The problem is resolved.
I've faced the same issue. I've use System.Text.Json as default json serializer.
To fix this issue i upgrade 'Microsoft.AspNetCore.SignalR.Protocols.Json' nuget to the valid version.
Who is using nginx for reverse proxy please update your nginx.config:
microsoft docs
These steps help me to resolve the same issue.

Polling using Websockets Unable to Communicate [Integrated with AWS]

Client Side:
import openSocket from 'socket.io-client';
const socket = openSocket(‘https://url/', {
transports: ['polling', 'websocket', 'flashsocket']
});
function onQueueUpdated(callback) {
socket.on('queue update', callback);
}
export {
onQueueUpdated
};
Server Side:
var options = {
key: fs.readFileSync(path.join(path.resolve('.'), secret.key')),
cert: fs.readFileSync(path.join(path.resolve('.'), ‘certi.crt')),
ca: fs.readFileSync(path.join(path.resolve('.'), ‘ca.crt')),
requestCert: false,
rejectUnauthorized: false
};
app.set("port", 8443);
server = https.createServer(options, app);
io = SocketIO(server);
io.set('origins', '*:*’);
server.listen(8443);
Its working fine on my local but When executed on AWS creates an issue
Error states:
enter image description here

Real Time Database.in Laravel and Websockets

Is there any way through which we can update data on Front end when we make some changes in database in Laravel and Websockets without using Tokens/Passport.
Just simply show updated data in Real time without Timeout.
A simple Solution for this is a websocket server in node which get the updates from laravel through redis publish.
The websocket server subscribe for the client(front user) in the topic, you push your data through.
Here is some code to try out. (no auth, so dont use in prod!). redistopic is the topic for redis
var express = require('express'),
fs = require('fs'),
http = require('http'),
server = http.createServer(app),
var app = express();
/* redis + socket.io */
const redis = require('redis');
const io = require('socket.io');
server.listen(8080);
log("Server Start");
io.listen(server).on('connection', function (socket) {
const redisClient = redis.createClient();
socket.on('auth', function (data) {
if(data.sockethash == 'noauth')
redisClient.subscribe('redistopic')
}
// Redis Nachrichten Verabrieten und entsprechend weiterleiten
redisClient.on("message", function (channel, message) {
if (channel == "redistopic")
socket.emit('redistopic', message);
});
socket.on('disconnect', function () {
redisClient.quit();
});
});
The javascript part
socket = io.connect('localhost:8080');
socket.on('connect', function (data) {
socket.emit('auth', { sockethash: 'noauth' });
});
socket.on('redistopic', function (data) {
var jd = JSON.parse(data); // if data is json
console.log(jd) // else use data
}
Laravel code for publish updates
need "use Illuminate\Support\Facades\Redis;" before
Redis::publish('redistopic', json_encode(
[
'var1' => 'value1',
'var2' => 'value2',
]
));

Resources