library shelf_eventsource; import "dart:convert"; import "package:eventsource/publisher.dart"; import "package:eventsource/src/encoder.dart"; import "package:shelf/shelf.dart"; /// Create a shelf handler for the specified channel. /// This handler can be passed to the [shelf.serve] method. Handler eventSourceHandler( EventSourcePublisher publisher, { String channel = "", bool gzip = false, }) { // define the handler Response shelfHandler(Request request) { if (request.method != "GET") { return Response.notFound(null); } if (!request.canHijack) { throw ArgumentError("eventSourceHandler may only be used with a " "server that supports request hijacking."); } // set content encoding to gzip if we allow it and the request supports it bool useGzip = gzip && (request.headers["Accept-Encoding"] ?? "").contains("gzip"); // hijack the raw underlying channel request.hijack((untypedChannel) { var socketChannel = (untypedChannel).cast<List<int>>(); // create a regular UTF8 sink to write headers var sink = utf8.encoder.startChunkedConversion(socketChannel.sink); // write headers sink.add("HTTP/1.1 200 OK\r\n" "Content-Type: text/event-stream; charset=utf-8\r\n" "Cache-Control: no-cache, no-store, must-revalidate\r\n" "Connection: keep-alive\r\n"); if (useGzip) sink.add("Content-Encoding: gzip\r\n"); sink.add("\r\n"); // create encoder for this connection var encodedSink = EventSourceEncoder(compressed: useGzip) .startChunkedConversion(socketChannel.sink); // initialize the new subscription publisher.newSubscription( onEvent: encodedSink.add, onClose: encodedSink.close, channel: channel, lastEventId: request.headers["Last-Event-ID"]); }); } return shelfHandler; }