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 wsHandler
gets called for WebSocket connects and handler
keeps handling HTTP requests (if possible on the same port) and if possible uses the configured authentication and session management.
I tried it on a different port but with the authentication/session middleware (no idea if this is supposed to 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 got
Illegal argument(s): webSocketHandler may only be used with a server that supports request hijacking.
At the moment your root handler is the http handler. You'll need to set up a handler that conditionally sends requests to the ws handler or another handler for your http requests. Eg
/ws -> your ws handler
/rest -> your other handler
The easiest way to do that is to use a router like shelf_route.
However someone recently tried this and hit a bug in shelf that stopped this working. Which as you noted below is fixed but not merged.
Once the issue 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 issue is fixed you can replace the 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();
}
};