|
| 1 | +import 'package:dart_frog/dart_frog.dart'; |
| 2 | +import 'package:shelf_web_socket/shelf_web_socket.dart' as shelf_web_socket; |
| 3 | +import 'package:web_socket_channel/web_socket_channel.dart'; |
| 4 | + |
| 5 | +/// Creates a Dart Frog [Handler] that upgrades HTTP requests to WebSocket |
| 6 | +/// connections. |
| 7 | +/// |
| 8 | +/// ```dart |
| 9 | +/// import 'package:dart_frog_web_socket/dart_frog_web_socket.dart'; |
| 10 | +/// |
| 11 | +/// final onRequest = webSocketHandler( |
| 12 | +/// (channel, protocol) { |
| 13 | +/// // A new connection was established. |
| 14 | +/// print('connected'); |
| 15 | +/// // Subscribe to the stream of messages from the client. |
| 16 | +/// channel.stream.listen( |
| 17 | +/// (message) { |
| 18 | +/// // Handle incoming messages. |
| 19 | +/// print('received: $message'); |
| 20 | +/// // Send outgoing messages to the connected client. |
| 21 | +/// channel.sink.add('pong'); |
| 22 | +/// }, |
| 23 | +/// // The connection was terminated. |
| 24 | +/// onDone: () => print('disconnected'), |
| 25 | +/// ); |
| 26 | +/// }, |
| 27 | +/// ); |
| 28 | +/// ``` |
| 29 | +/// |
| 30 | +/// Only valid WebSocket upgrade requests are upgraded. If a request doesn't |
| 31 | +/// look like a WebSocket upgrade request, a 404 Not Found is returned; if a |
| 32 | +/// request looks like an upgrade request but is invalid, a 400 Bad Request is |
| 33 | +/// returned; and if a request is a valid upgrade request but has an origin that |
| 34 | +/// doesn't match [allowedOrigins] (see below), a 403 Forbidden is returned. |
| 35 | +/// |
| 36 | +/// The [onConnection] must take a [WebSocketChannel] as the first argument |
| 37 | +/// and a string for the [WebSocket subprotocol][] as the second |
| 38 | +/// argument. The subprotocol is determined by looking at the client's |
| 39 | +/// `Sec-WebSocket-Protocol` header and selecting the first entry that also |
| 40 | +/// appears in [protocols]. If no subprotocols are shared between the client and |
| 41 | +/// the server, `null` will be passed instead and no subprotocol header will be |
| 42 | +/// sent to the client which may cause it to disconnect. |
| 43 | +/// |
| 44 | +/// [WebSocket subprotocol]: https://tools.ietf.org/html/rfc6455#section-1.9 |
| 45 | +/// |
| 46 | +/// If [allowedOrigins] is passed, browser connections will only be accepted if |
| 47 | +/// they're made by a script from one of the given origins. This ensures that |
| 48 | +/// malicious scripts running in the browser are unable to fake a WebSocket |
| 49 | +/// handshake. Note that non-browser programs can still make connections freely. |
| 50 | +/// See also the WebSocket spec's discussion of [origin considerations][]. |
| 51 | +/// |
| 52 | +/// [origin considerations]: https://tools.ietf.org/html/rfc6455#section-10.2 |
| 53 | +/// |
| 54 | +/// If [pingInterval] is specified, it will get passed to the created |
| 55 | +/// channel instance, enabling round-trip disconnect detection. |
| 56 | +/// |
| 57 | +/// This method uses [`package:shelf_web_socket`](https://pub.dev/packages/shelf_web_socket) |
| 58 | +/// internally. |
| 59 | +Handler webSocketHandler( |
| 60 | + void Function(WebSocketChannel channel, String? protocol) onConnection, { |
| 61 | + Iterable<String>? protocols, |
| 62 | + Iterable<String>? allowedOrigins, |
| 63 | + Duration? pingInterval, |
| 64 | +}) { |
| 65 | + return fromShelfHandler( |
| 66 | + shelf_web_socket.webSocketHandler( |
| 67 | + onConnection, |
| 68 | + protocols: protocols, |
| 69 | + allowedOrigins: allowedOrigins, |
| 70 | + pingInterval: pingInterval, |
| 71 | + ), |
| 72 | + ); |
| 73 | +} |
0 commit comments