How can I use shel_web_socket to listen for HTTP and ws requests on the same port

https://pub.dartlang.org/packages/shelf_web_socket shows this example

import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_web_socket/shelf_web_socket.dart';

void main() {
  var handler = webSocketHandler((webSocket) {
    webSocket.listen((message) {
      webSocket.add("echo $message");
    });
  });

  shelf_io.serve(handler, 'localhost', 8080).then((server) {
    print('Serving at ws://${server.address.host}:${server.port}');
  });
}

      

I would like to know how to combine this with my HTTP server initialization

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as sIo;
import 'package:shelf_auth/shelf_auth.dart' as sAuth;
import 'package:shelf_auth/src/authentication.dart' as sAuth2;
import 'package:option/option.dart';
import 'package:shelf_web_socket/shelf_web_socket.dart' as sWs;

...

var authMiddleware = sAuth.authenticate(
    [new MyAuthenticator()],
    sessionHandler: new sAuth.JwtSessionHandler('bla', 'blub', new UserLookup()),
    allowHttp: true,
    allowAnonymousAccess: false);

var handler = const shelf.Pipeline()
    .addMiddleware(shelf.logRequests())
    .addMiddleware(authMiddleware)
    .addHandler(_handleHttpRequest);

// var wsHandler = sWs.webSocketHandler(_handleWebSocketConnect);

sIo.serve(handler, '0.0.0.0', servePort).then((server) {
  _log.finest('Serving at http://${server.address.host}:${server.port}');
});

      

What needs to be done so that the callee wsHandler

gets called for WebSocket connections and handler

continues to process HTTP requests (on the same port if possible) and, if possible, uses configured authentication and session management.

I tried it on a different port, but with authentication / session middleware (don't know if this would be used together)

   var authMiddleware = sAuth.authenticate(
        [new MyAuthenticator()],
        sessionHandler: new sAuth.JwtSessionHandler('bla', 'blub', new UserLookup()),
        allowHttp: true,
        allowAnonymousAccess: false);

    var handler = const shelf.Pipeline()
        .addMiddleware(shelf.logRequests())
        .addMiddleware(authMiddleware)
        .addHandler(_handleHttpRequest);

    sIo.serve(handler, '0.0.0.0', servePort).then((server) {
      _log.finest('Serving at http://${server.address.host}:${server.port}');
    });


    var wsHandler = const shelf.Pipeline()
      .addMiddleware(shelf.logRequests())
      .addMiddleware(authMiddleware)
      .addHandler(sWs.webSocketHandler(_handleWebSocketConnect));

    sIo.serve(wsHandler, '0.0.0.0', servePort + 1).then((server) {
      _log.finest('Serving at ws://${server.address.host}:${server.port}');
    });

      

and received

Illegal argument(s): webSocketHandler may only be used with a server that supports request hijacking.

      

+3


source to share


1 answer


Your root handler is currently an http handler. You will need to set up a handler that conditionally sends requests to the ws handler or another handler for your HTTP requests. For example,

/ ws -> your ws handler

/ rest -> your other handler

The easiest way to do this is to use a router like shelf_route.

However, someone recently tried this and hit a shelf bug that stopped this working . Which, as you noted below, is fixed but not merged.



Once the problem is fixed, you should be able to do

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:shelf_route/shelf_route.dart' as route;
import 'package:shelf_web_socket/shelf_web_socket.dart' as sWs;
import 'package:shelf_auth/shelf_auth.dart' as sAuth;
import 'dart:async';
import 'package:option/option.dart';
import 'package:shelf_exception_response/exception_response.dart';

void main(List<String> arguments) {

  var authMiddleware = sAuth.authenticate(
        [new MyAuthenticator()],
        sessionHandler: new sAuth.JwtSessionHandler('bla', 'blub', new UserLookup()),
        allowHttp: true,
        allowAnonymousAccess: false);


  var router = (route.router()
      ..get('/rest', _handleHttpRequest)
      ..get('/ws', sWs.webSocketHandler(_handleWebSocketConnect)));

  var handler = const shelf.Pipeline()
      .addMiddleware(exceptionResponse())
      .addMiddleware(shelf.logRequests())
      .addMiddleware(authMiddleware)
      .addHandler(router.handler);

  route.printRoutes(router);

  io.serve(handler, '127.0.0.1', 8080).then((server) {
    print('Serving at http://${server.address.host}:${server.port}');
  });
}

      

Until the problem is resolved, you can replace router.handler with

var hackyRouterHandler = (shelf.Request request) {
  var path = request.url.path;
  if (path.startsWith('/rest')) {
    return _handleHttpRequest(request);
  }
  else if (path.startsWith('/ws')) {
    return sWs.webSocketHandler(_handleWebSocketConnect)(request);
  }
  else {
    throw new NotFoundException();
  }
};

      

+3


source







All Articles