Add 'packages/eventsource/' from commit 'bc079d37353d94d827290914523b2757fb392ff9'
git-subtree-dir: packages/eventsource git-subtree-mainline:c94bec26ec
git-subtree-split:bc079d3735
This commit is contained in:
commit
26afe42cb7
16 changed files with 324 additions and 0 deletions
65
packages/eventsource/.gitignore
vendored
Normal file
65
packages/eventsource/.gitignore
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Dart template
|
||||
# See https://www.dartlang.org/tools/private-files.html
|
||||
|
||||
# Files and directories created by pub
|
||||
.packages
|
||||
.pub/
|
||||
build/
|
||||
# If you're building an application, you may want to check-in your pubspec.lock
|
||||
pubspec.lock
|
||||
|
||||
# Directory created by dartdoc
|
||||
# If you don't generate documentation locally you can remove this line.
|
||||
doc/api/
|
||||
.dart_tool
|
6
packages/eventsource/.idea/misc.xml
Normal file
6
packages/eventsource/.idea/misc.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
packages/eventsource/.idea/modules.xml
Normal file
8
packages/eventsource/.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/eventsource.iml" filepath="$PROJECT_DIR$/eventsource.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="build.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/tool/build.dart" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="main.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/example/main.dart" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
|
@ -0,0 +1,7 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="watch.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
||||
<option name="filePath" value="$PROJECT_DIR$/tool/watch.dart" />
|
||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
6
packages/eventsource/.idea/vcs.xml
Normal file
6
packages/eventsource/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
21
packages/eventsource/LICENSE
Normal file
21
packages/eventsource/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017 The Angel Framework
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
33
packages/eventsource/README.md
Normal file
33
packages/eventsource/README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# eventsource
|
||||
Server-sent Events (SSE) plugin for Angel.
|
||||
|
||||
## Installation
|
||||
In your `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
angel_eventsource: ^1.0.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
SSE and WebSockets are somewhat similar in that they allow pushing of events from server
|
||||
to client. SSE is not bi-directional, but the same abstractions used for WebSockets can be
|
||||
applied to SSE easily.
|
||||
|
||||
For this reason, the `AngelEventSourcePublisher` class is a simple adapter that
|
||||
hands control of SSE requests to an existing `AngelWebSocket` driver.
|
||||
|
||||
So, using this is pretty straightforward. You can dispatch events
|
||||
via WebSocket as per usual, and have them propagated to SSE clients
|
||||
as well.
|
||||
|
||||
```dart
|
||||
var app = new Angel();
|
||||
var ws = new AngelWebSocket(app);
|
||||
var events = new AngelEventSourcePublisher(ws);
|
||||
|
||||
await app.configure(ws.configureServer);
|
||||
|
||||
app.all('/ws', ws.handleRequest);
|
||||
app.get('/events', events.handleRequest);
|
||||
```
|
3
packages/eventsource/analysis_options.yaml
Normal file
3
packages/eventsource/analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
14
packages/eventsource/eventsource.iml
Normal file
14
packages/eventsource/eventsource.iml
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Dart SDK" level="project" />
|
||||
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||
</component>
|
||||
</module>
|
50
packages/eventsource/example/main.dart
Normal file
50
packages/eventsource/example/main.dart
Normal file
|
@ -0,0 +1,50 @@
|
|||
import 'package:angel_eventsource/server.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_websocket/server.dart';
|
||||
import 'package:eventsource/eventsource.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'pretty_logging.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var ws = new AngelWebSocket(app);
|
||||
var events = new AngelEventSourcePublisher(ws);
|
||||
|
||||
await app.configure(ws.configureServer);
|
||||
|
||||
app.use('/api/todos', new MapService());
|
||||
app.all('/ws', ws.handleRequest);
|
||||
app.get('/events', events.handleRequest);
|
||||
|
||||
app.logger = new Logger('angel_eventsource')..onRecord.listen(prettyLog);
|
||||
|
||||
var http = new AngelHttp(app);
|
||||
var server = await http.startServer('127.0.0.1', 3000);
|
||||
var url = Uri.parse('http://${server.address.address}:${server.port}');
|
||||
print('Listening at $url');
|
||||
|
||||
/*
|
||||
var sock = await Socket.connect(server.address, server.port);
|
||||
sock
|
||||
..writeln('GET /sse HTTP/1.1')
|
||||
..writeln('Accept: text/event-stream')
|
||||
..writeln('Host: 127.0.0.1')
|
||||
..writeln()
|
||||
..flush();
|
||||
sock.transform(UTF8.decoder).transform(const LineSplitter()).listen(print);
|
||||
*/
|
||||
|
||||
/*
|
||||
var client = new HttpClient();
|
||||
var rq = await client.openUrl('GET', url);
|
||||
var rs = await rq.close();
|
||||
rs.transform(UTF8.decoder).transform(const LineSplitter()).listen(print);
|
||||
*/
|
||||
|
||||
var eventSource = await EventSource.connect(url);
|
||||
|
||||
await for (var event in eventSource) {
|
||||
print(event.data);
|
||||
}
|
||||
}
|
29
packages/eventsource/example/pretty_logging.dart
Normal file
29
packages/eventsource/example/pretty_logging.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
import 'package:console/console.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
/// Prints the contents of a [LogRecord] with pretty colors.
|
||||
prettyLog(LogRecord record) async {
|
||||
var pen = new TextPen();
|
||||
chooseLogColor(pen.reset(), record.level);
|
||||
pen(record.toString());
|
||||
|
||||
if (record.error != null) pen(record.error.toString());
|
||||
if (record.stackTrace != null) pen(record.stackTrace.toString());
|
||||
|
||||
pen();
|
||||
}
|
||||
|
||||
/// Chooses a color based on the logger [level].
|
||||
void chooseLogColor(TextPen pen, Level level) {
|
||||
if (level == Level.SHOUT)
|
||||
pen.darkRed();
|
||||
else if (level == Level.SEVERE)
|
||||
pen.red();
|
||||
else if (level == Level.WARNING)
|
||||
pen.yellow();
|
||||
else if (level == Level.INFO)
|
||||
pen.magenta();
|
||||
else if (level == Level.FINER)
|
||||
pen.blue();
|
||||
else if (level == Level.FINEST) pen.darkBlue();
|
||||
}
|
1
packages/eventsource/lib/angel_eventsource.dart
Normal file
1
packages/eventsource/lib/angel_eventsource.dart
Normal file
|
@ -0,0 +1 @@
|
|||
export 'package:angel_websocket/angel_websocket.dart';
|
51
packages/eventsource/lib/server.dart
Normal file
51
packages/eventsource/lib/server.dart
Normal file
|
@ -0,0 +1,51 @@
|
|||
import 'dart:async';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_websocket/server.dart';
|
||||
import 'package:eventsource/eventsource.dart';
|
||||
import 'package:eventsource/src/encoder.dart';
|
||||
import 'package:eventsource/publisher.dart';
|
||||
import 'package:stream_channel/stream_channel.dart';
|
||||
|
||||
class AngelEventSourcePublisher {
|
||||
final AngelWebSocket webSocketDriver;
|
||||
|
||||
final String channel;
|
||||
|
||||
int _count = 0;
|
||||
|
||||
AngelEventSourcePublisher(this.webSocketDriver, {this.channel: ''});
|
||||
|
||||
Future handleRequest(RequestContext req, ResponseContext res) async {
|
||||
if (!req.accepts('text/event-stream', strict: false))
|
||||
throw new AngelHttpException.badRequest();
|
||||
|
||||
res.headers.addAll({
|
||||
'cache-control': 'no-cache, no-store, must-revalidate',
|
||||
'content-type': 'text/event-stream',
|
||||
'connection': 'keep-alive',
|
||||
});
|
||||
|
||||
var acceptsGzip =
|
||||
(req.headers['accept-encoding']?.contains('gzip') == true);
|
||||
|
||||
if (acceptsGzip) res.headers['content-encoding'] = 'gzip';
|
||||
|
||||
var eventSink = new EventSourceEncoder(compressed: acceptsGzip)
|
||||
.startChunkedConversion(res);
|
||||
|
||||
// Listen for events.
|
||||
var ctrl = new StreamChannelController();
|
||||
|
||||
// Incoming events are strings, and should be sent via the eventSink.
|
||||
ctrl.local.stream.cast<String>().listen((data) {
|
||||
eventSink.add(new Event(
|
||||
id: (_count++).toString(),
|
||||
data: data,
|
||||
));
|
||||
});
|
||||
|
||||
// Create a new WebSocketContext, and hand it off to the driver.
|
||||
var socket = new WebSocketContext(ctrl.foreign, req, res);
|
||||
return await webSocketDriver.handleClient(socket);
|
||||
}
|
||||
}
|
16
packages/eventsource/pubspec.yaml
Normal file
16
packages/eventsource/pubspec.yaml
Normal file
|
@ -0,0 +1,16 @@
|
|||
name: angel_eventsource
|
||||
version: 1.0.0
|
||||
description: Server-sent Events (SSE) plugin for Angel.
|
||||
homepage: https://github.com/angel-dart/eventsource
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_websocket: ^2.0.0-alpha
|
||||
eventsource: ^0.2.0
|
||||
stream_channel: ^1.0.0
|
||||
dev_dependencies:
|
||||
console: ^3.0.0
|
||||
logging:
|
||||
test: ^1.0.0
|
Loading…
Reference in a new issue