Dart shelf_web_socket with shelf_router gives Hijack exception - http

I am trying to implement a basic server which serves both websockets and http requests.
Code is this;
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_web_socket/shelf_web_socket.dart';
void main(List<String> args) async {
var app = Router();
var wsHandle = webSocketHandler((webSocket) {
webSocket.stream.listen((message) {
print(message);
webSocket.sink.add("echo $message");
});
});
app.get('/', (Request r) {
return Response.ok('hello-world');
});
app.get("/ws", wsHandle);
var server = await io.serve(app, 'localhost', 8080);
print("Server is on at ${server.address.host} ${server.port}");
}
When I try to connect the ws url I get Hijack Error.
Exception has occurred.
HijackException (A shelf request's underlying data stream was hijacked.
This exception is used for control flow and should only be handled by a Shelf adapter.)
I could not find a workaround. This solution does not work for me.

Your code works just switch app.get("/ws") and app.get("/").

Related

Oak framework Doesnt respond to request in deno deploy

I tried deploying my deno app to deno deploy but I have tried all means to work but still no response and I have no error in logs.
This my code below..
import { load } from "https://deno.land/std#0.171.0/dotenv/mod.ts";
import { Application } from "https://deno.land/x/oak#v11.1.0/mod.ts";
import { socketIo } from "../src/controllers/websocket/setup.ts";
import fileRouter from "./../src/routes/file_rt.ts";
import ordersRouter from "./../src/routes/orders_rt.ts";
import mealRouter from "./../src/routes/meal_rt.ts";
import userRouter from "./../src/routes/user_rt.ts";
load();
const app = new Application();
app.use(await rateLimit);
app.use(userRouter.routes());
app.use(ordersRouter.routes());
app.use(mealRouter.routes());
app.use(fileRouter.routes());
app.use(userRouter.allowedMethods());
app.use(ordersRouter.allowedMethods());
app.use(mealRouter.allowedMethods());
app.use(fileRouter.allowedMethods());
socketIo();
await app.listen({port:80});
I tried to test an api route using postman but the endpoint didn't log anything
I have fixed it by removing the socket IO connection I imported. [ socketIO() ]
But now the socket connection is not working.
export const socketIo = async () => {
io.on("connection", (socket) => {
console.log(`socket ${socket.id} connected`);
skt = socket;
signUSER(socket);
socket.on("disconnect", (reason) => {
console.log(`socket ${socket.id} disconnected due to ${reason}`);
});
console.log("Socket Hit 😎✨");
});
await serve(io.handler(), {
port: 3000,
});
}

Get Timeout Error on Firebase Functions when calling external API in functions

I am using Firebase Functions
Everything works perfectly except for a few issues
Some requests that worked flawlessly before are now giving a timeout error
I mean,
I am making an http post request using "axios" from within the firebase functions (outbound or external request, whatever it is called )
When I run it with the emulator, the codes work correctly, although I see that my http requests are working correctly, when I deploy the firebase function, I see that the same requests get timeouts.
By the way I'm using the Blaze plan.
However,
The code I get the timeout is as follows:
var getToken = async () => {
var link = configLink("GENERAL") + "CreateTokenV2";
try {
var result = await axios.post(link, {
"channelCredential": {
"ChannelCode": _CONFIG.TENANT.ChannelCode,
"ChannelPassword": _CONFIG.TENANT.ChannelPassword,
}
});
var ds = result.data;
if (ds.HasError) {
console.log(ds.ErrorMessage);
return false;
}
await insertHelper("kplus", {
url: _CONFIG.url,
channelcode: _CONFIG.TENANT.ChannelCode,
channelpassword: _CONFIG.TENANT.ChannelPassword,
token: ds.Result.TokenCode,
lastdate: new Date(ds.Result.ExpiresAt),
tokenobject: ds.Result
})
return ds.Result;
} catch (err) {
console.error(err);
return new Error(err);
}
}

SignalR message from client not received

I was initially trying to setup my server-side signalR HUB to send messages to the client, but so far have not succeeded.
So I decided to try to send a message from the client instead; and setup a button to trigger a message from client to server.
I can launch my Core 3.1 project (image below), and setup the Hub connection just fine, but cannot verify in any way that the message is being received on the server.
In fact, my server breakpoints never get hit.
In my html:
<button mat-button (click)="sendClientMessage()"> Send Message </button>
TypeScript component:
sendClientMessage(): void {
this.notificationService.sendMessageToHub();
}
import { Injectable } from '#angular/core';
import * as signalr from '#microsoft/signalr';
import { SIGCONT } from 'constants';
#Injectable({
providedIn: 'root',
})
export class NotificationService {
private hubConnection: signalr.HubConnection;
hubMessage: string;
public startConnection = () => {
this.hubConnection = new signalr.HubConnectionBuilder()
.withUrl('https://localhost:44311/hub')
.configureLogging(signalr.LogLevel.Debug)
.build();
this.hubConnection
.start()
.then(() => {
console.log('Hub Connection started');
this.sendMessageToHub();
})
.catch((err) => console.log(`Error while starting connection: ${err}`));
this.hubConnection.serverTimeoutInMilliseconds = 50000;
}
public hubListener = () => {
this.hubConnection.on('messageReceived', (message) => {
this.hubMessage = message;
console.log(message);
});
}
public sendMessageToHub = () => {
if (this.hubConnection == undefined || this.hubConnection.state === signalr.HubConnectionState.Disconnected) {
this.startConnection();
} else {
this.hubConnection.send('NewMessage', 'client', 'You have a notification from the front end !')
.then(() => console.log('Message sent from client.'));
}
}
constructor() { }
}
My server-side Core project - Notifications.cs
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace NotificationHub.Hubs
{
public class Notifications: Hub
{
public async Task NewMessage(long username, string message)
{
await Clients.All.SendAsync("messageReceived", username, message);
}
internal Task NewMessage(string v1, string v2)
{
throw new NotImplementedException();
}
}
}
When I click the button above, it appears to send something to the server:
I would appreciate any help in getting my Core project to first hit those breakpoints, and to see what the NewMessage method is not receiving the client message.
From there I can try and figure out how to send messages from server to client (i.e. using some Timer example).
thank you.
You're sending 2 strings from the client to the server but you've made your server method take a long and a string so it doesn't match. If you looked at the server logs you would see a message about the method no being found.
Another way to observe the error would be to call invoke instead of send from the client side which will expect a response from the server on completion of the hub method, or in this case an error will be sent from the server.

.NET Core SignalR, Server timeoute / Reconnect issue

I have a SignalR hub written in my MVC solution, with a Javascript client connecting from the view.
The point of the connection is to receive changes for a wallboard from the server. This has to happen almost instantly and requires a lifetime connection, since the webpage is running on a screen without direct pc access.
So far the SignalR connection works for a couple of hours before it gives error.
The error I get is
Error: Connection disconnected with error 'Error: Server timeout elapsed without receiving a message form the server.'.
Failed to load resource: net::ERR_CONNECTION_TIMED_OUT
Warning: Error from HTTP request. 0:
Error: Failed to complete negotiation with the server: Error
Error: Failed to start the connection: Error
Uncaught (in promise) Error
at new HttpError (singlar.js:1436)
at XMLHttpRequest.xhr.onerror (singalr.js:1583)
My client code
let connection = new signalR.HubConnectionBuilder()
.withUrl("/wbHub")
.configureLogging(signalR.LogLevel.Information)
.build();
connection.start().then(function () {
connection.invoke("GetAllWallboards").then(function (wallboard) {
for (var i = 0; i < wallboard.length; i++) {
displayWallboard(wallboard[i]);
}
startStreaming();
})
})
connection.onclose(function () {
connection.start().then(function () {
startStreaming();
})
})
function startStreaming() {
connection.stream("StreamWallboards").subscribe({
close: false,
next: displayWallboard
});
}
Hub Code:
public class WallboardHub : Hub
{
private readonly WallboardTicker _WallboardTicker;
public WallboardHub(WallboardTicker wallboardTicker)
{
_WallboardTicker = wallboardTicker;
}
public IEnumerable<Wallboard> GetAllWallboards()
{
return _WallboardTicker.GetAllWallboards();
}
public ChannelReader<Wallboard> StreamWallboards()
{
return _WallboardTicker.StreamWallboards().AsChannelReader(10);
}
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnDisconnectedAsync(exception);
}
}
Question 1: Is the way I handle reconnecting correct? From the error it feels like the .onclose works, but that it only tries one time? Is there anyway to try for x min before showing error?
Question 2: Reloading the website makes the connection work again, is there potential anyway to refresh the browser on signalR connection error?
I have the same issue (Question 1), and i resolve with this:
const connection = new SignalR.HubConnectionBuilder()
.withUrl("/hub")
.configureLogging(SignalR.LogLevel.Information)
.build();
connect(connection);
async function connect(conn){
conn.start().catch( e => {
sleep(5000);
console.log("Reconnecting Socket");
connect(conn);
}
)
}
connection.onclose(function (e) {
connect(connection);
});
async function sleep(msec) {
return new Promise(resolve => setTimeout(resolve, msec));
}
Every 5 seconds tries to reconnect, but i don't know if this is the right way to do this.
ASP.NET Core 2.1 (current LTS release) with the corresponding SignalR release doesn't seem to have some integrated reconnecting method avaliable. The code from #Shidarg doesn't work for me, it calls the reconnect method in a infinitive loop crashiny my browser. I also like the async/await syntax from C# more, so I updated it:
let reconnectWaitTime = 5000
let paramStr = '?myCustomArg=true'
let client = new signalR.HubConnectionBuilder()
.withUrl("/overviewHub" + paramStr)
.build();
client.onclose(async () => {
console.warn(`WS connection closed, try reconnecting with loop interval ${reconnectWaitTime}`)
tryReconnect(client)
})
await tryReconnect(client)
async function tryReconnect(client) {
try {
let started = await client.start()
console.log('WS client connected!')
// Here i'm initializing my services, e.g. fetch history of a chat when connection got established
return started;
} catch (e) {
await new Promise(resolve => setTimeout(resolve, reconnectWaitTime));
return await tryReconnect(client)
}
}
But for ASP.NET Core 3 they included a reconnecting method:
let client = new signalR.HubConnectionBuilder()
.withUrl("/myHub")
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();
Per default it try three reconnects: First after 2 seconds, second after 10 seconds and the last about 30 seconds. This could be modificated by passing the intervalls as array parameter:
.withAutomaticReconnect([5000, 1500, 50000, null])
This example re-trys after 5s, 15s and 50s. The last null param tell SignalR to stop re-trying. More information could be found here: https://www.jerriepelser.com/blog/automatic-reconnects-signalr/
Configuring automatic reconnects only requires a call to withAutomaticReconnect on the HubConnectionBuilder. Here is what my JavaScript code looks like for configuring my connection:
connection = new signalR.HubConnectionBuilder()
.withUrl("/publish-document-job-progress")
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();
You can configure the backoff period by passing an array of retry delays to the call to withAutomaticReconnect(). The default for this is [0, 2000, 10000, 30000, null]. The null value tells SignalR to stop trying. So, for example, if I wanted it to retry at 0, 1 second and 5 seconds, I can configure my HubConnectionBuilder as follows:
connection = new signalR.HubConnectionBuilder()
.withUrl("/publish-document-job-progress")
.withAutomaticReconnect([0, 1000, 5000, null])
.configureLogging(signalR.LogLevel.Information)
.build();

How to listen to node http-proxy traffic?

I am using node-http-proxy. However, in addition to relaying HTTP requests, I also need to listen to the incoming and outgoing data.
Intercepting the response data is where I'm struggling. Node's ServerResponse object (and more generically the WritableStream interface) doesn't broadcast a 'data' event. http-proxy seems to create it's own internal request, which produces a ClientResponse object (which does broadcast the 'data' event) however this object is not exposed publically outside the proxy.
Any ideas how to solve this without monkey-patching node-http-proxy or creating a wrapper around the response object?
Related issue in issues of node-http-proxy on Github seems to imply this is not possible. For future attempts by others, here is how I hacked the issue:
you'll quickly find out that the proxy is only calling writeHead(), write() and end() methods of the res object
since res is already an EventEmitter, you can start emitting new custom events
listen for these new events to assemble the response data and then use it
var eventifyResponse = function(res) {
var methods = ['writeHead', 'write', 'end'];
methods.forEach(function(method){
var oldMethod = res[method]; // remember original method
res[method] = function() { // replace with a wrapper
oldMethod.apply(this, arguments); // call original method
arguments = Array.prototype.slice.call(arguments, 0);
arguments.unshift("method_" + method);
this.emit.apply(this, arguments); // broadcast the event
};
});
};
res = eventifyResponse(res), outputData = '';
res.on('method_writeHead', function(statusCode, headers) { saveHeaders(); });
res.on('method_write', function(data) { outputData += data; });
res.on('method_end', function(data) { use_data(outputData + data); });
proxy.proxyRequest(req, res, options)
This is a simple proxy server sniffing the traffic and writing it to console:
var http = require('http'),
httpProxy = require('http-proxy');
//
// Create a proxy server with custom application logic
//
var proxy = httpProxy.createProxyServer({});
// assign events
proxy.on('proxyRes', function (proxyRes, req, res) {
// collect response data
var proxyResData='';
proxyRes.on('data', function (chunk) {
proxyResData +=chunk;
});
proxyRes.on('end',function () {
var snifferData =
{
request:{
data:req.body,
headers:req.headers,
url:req.url,
method:req.method},
response:{
data:proxyResData,
headers:proxyRes.headers,
statusCode:proxyRes.statusCode}
};
console.log(snifferData);
});
// console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
});
proxy.on('proxyReq', function(proxyReq, req, res, options) {
// collect request data
req.body='';
req.on('data', function (chunk) {
req.body +=chunk;
});
req.on('end', function () {
});
});
proxy.on('error',
function(err)
{
console.error(err);
});
// run the proxy server
var server = http.createServer(function(req, res) {
// every time a request comes proxy it:
proxy.web(req, res, {
target: 'http://localhost:4444'
});
});
console.log("listening on port 5556")
server.listen(5556);
I tried your hack but it didn't work for me. My use case is simple: I want to log the in- and outgoing traffic from an Android app to our staging server which is secured by basic auth.
https://github.com/greim/hoxy/
was the solution for me. My node-http-proxy always returned 500 (while the direct request to stage did not). Maybe the authorization headers would not be forwarded correctly or whatever.
Hoxy worked fine right from the start.
npm install hoxy [-g]
hoxy --port=<local-port> --stage=<your stage host>:<port>
As rules for logging I specified:
request: $aurl.log()
request: #log-headers()
request: $method.log()
request: $request-body.log()
response: $url.log()
response: $status-code.log()
response: $response-body.log()
Beware, this prints any binary content.

Resources