Updated websocket
This commit is contained in:
parent
0d294adb20
commit
62336e0d53
25 changed files with 158 additions and 223 deletions
|
@ -52,7 +52,7 @@ abstract class BaseAngelClient extends Angel {
|
||||||
final List<Service> _services = [];
|
final List<Service> _services = [];
|
||||||
final http.BaseClient client;
|
final http.BaseClient client;
|
||||||
|
|
||||||
final _p = Context(style: Style.url);
|
final Context _p = Context(style: Style.url);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<AngelAuthResult> get onAuthenticated => _onAuthenticated.stream;
|
Stream<AngelAuthResult> get onAuthenticated => _onAuthenticated.stream;
|
||||||
|
@ -212,7 +212,7 @@ class BaseAngelService<Id, Data> extends Service<Id, Data?> {
|
||||||
final http.BaseClient client;
|
final http.BaseClient client;
|
||||||
final AngelDeserializer<Data>? deserializer;
|
final AngelDeserializer<Data>? deserializer;
|
||||||
|
|
||||||
final _p = Context(style: Style.url);
|
final Context _p = Context(style: Style.url);
|
||||||
|
|
||||||
final StreamController<List<Data?>> _onIndexed = StreamController();
|
final StreamController<List<Data?>> _onIndexed = StreamController();
|
||||||
final StreamController<Data?> _onRead = StreamController(),
|
final StreamController<Data?> _onRead = StreamController(),
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
||||||
</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>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptLibraryMappings">
|
|
||||||
<includedPredefinedLibrary name="ECMAScript 6" />
|
|
||||||
<includedPredefinedLibrary name="Node.js Core" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,28 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="JavaScriptSettings">
|
|
||||||
<option name="languageLevel" value="ES6" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectInspectionProfilesVisibleTreeState">
|
|
||||||
<entry key="Project Default">
|
|
||||||
<profile-state>
|
|
||||||
<expanded-state>
|
|
||||||
<State>
|
|
||||||
<id />
|
|
||||||
</State>
|
|
||||||
<State>
|
|
||||||
<id>General</id>
|
|
||||||
</State>
|
|
||||||
<State>
|
|
||||||
<id>XPath</id>
|
|
||||||
</State>
|
|
||||||
</expanded-state>
|
|
||||||
<selected-state>
|
|
||||||
<State>
|
|
||||||
<id>AngularJS</id>
|
|
||||||
</State>
|
|
||||||
</selected-state>
|
|
||||||
</profile-state>
|
|
||||||
</entry>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/angel_proxy.iml" filepath="$PROJECT_DIR$/.idea/angel_proxy.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
|
@ -1,8 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="All Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="scope" value="FOLDER" />
|
|
||||||
<option name="testRunnerOptions" value="-j 4" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Basic Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/test/basic_test.dart" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="Pub Serve Tests" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/test/pub_serve_test.dart" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,7 +0,0 @@
|
||||||
<component name="ProjectRunConfigurationManager">
|
|
||||||
<configuration default="false" name="multiple.dart" type="DartCommandLineRunConfigurationType" factoryName="Dart Command Line Application" singleton="true" nameIsGenerated="true">
|
|
||||||
<option name="filePath" value="$PROJECT_DIR$/example/multiple.dart" />
|
|
||||||
<option name="workingDirectory" value="$PROJECT_DIR$" />
|
|
||||||
<method />
|
|
||||||
</configuration>
|
|
||||||
</component>
|
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
11
packages/proxy/.vscode/launch.json
vendored
11
packages/proxy/.vscode/launch.json
vendored
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Multiple Proxies",
|
|
||||||
"type": "dart-cli",
|
|
||||||
"request": "launch",
|
|
||||||
"program": "${workspaceRoot}/example/multiple.dart"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,32 +1,43 @@
|
||||||
# 4.0.0
|
# Change Log
|
||||||
|
|
||||||
|
## 4.0.1
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
* Migrated to support Dart SDK 2.12.x NNBD
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 3.0.0
|
## 3.0.0
|
||||||
|
|
||||||
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
||||||
|
|
||||||
# 2.2.0
|
## 2.2.0
|
||||||
|
|
||||||
* Use `http.Client` instead of `http.BaseClient`, and make it an
|
* Use `http.Client` instead of `http.BaseClient`, and make it an
|
||||||
optional parameter.
|
optional parameter.
|
||||||
* Allow `baseUrl` to accept `Uri` or `String`.
|
* Allow `baseUrl` to accept `Uri` or `String`.
|
||||||
* Add `Proxy.pushState`.
|
* Add `Proxy.pushState`.
|
||||||
|
|
||||||
# 2.1.2
|
## 2.1.2
|
||||||
|
|
||||||
* Apply lints.
|
* Apply lints.
|
||||||
|
|
||||||
# 2.1.1
|
## 2.1.1
|
||||||
|
|
||||||
* Update for framework@2.0.0-alpha.15
|
* Update for framework@2.0.0-alpha.15
|
||||||
|
|
||||||
# 2.1.0
|
## 2.1.0
|
||||||
|
|
||||||
- Use `Uri` instead of archaic `host`, `port`, and `mapTo`. Also cleaner + safer + easier.
|
* Use `Uri` instead of archaic `host`, `port`, and `mapTo`. Also cleaner + safer + easier.
|
||||||
|
|
||||||
* Enable WebSocket proxying.
|
* Enable WebSocket proxying.
|
||||||
|
|
||||||
# 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
- Updates for Angel 2. Big thanks to @denkuy!
|
* Updates for Angel 2. Big thanks to @denkuy!
|
||||||
- Use `package:path` for better path resolution.
|
* Use `package:path` for better path resolution.
|
||||||
|
|
||||||
# 1.1.1
|
## 1.1.1
|
||||||
|
|
||||||
- Removed reference to `io`; now works with HTTP/2. Thanks to @daniel-v!
|
* Removed reference to `io`; now works with HTTP/2. Thanks to @daniel-v!
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
# angel3_proxy
|
# Angel3 Proxy
|
||||||
[![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_proxy)
|
|
||||||
|
[![version](https://img.shields.io/badge/pub-v4.0.1-brightgreen)](https://pub.dartlang.org/packages/angel3_proxy)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy/LICENSE)
|
||||||
|
|
||||||
Angel middleware to forward requests to another server (i.e. `webdev serve`).
|
Angel middleware to forward requests to another server (i.e. `webdev serve`). Also supports WebSockets.
|
||||||
Also supports WebSockets.
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'package:angel3_proxy/angel3_proxy.dart';
|
import 'package:angel3_proxy/angel3_proxy.dart';
|
||||||
|
@ -23,11 +23,13 @@ void main() async {
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also restrict the proxy to serving only from a specific root:
|
You can also restrict the proxy to serving only from a specific root:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Proxy(baseUrl, publicPath: '/remote');
|
Proxy(baseUrl, publicPath: '/remote');
|
||||||
```
|
```
|
||||||
|
|
||||||
Also, you can map requests to a root path on the remote server:
|
Also, you can map requests to a root path on the remote server:
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
Proxy(baseUrl.replace(path: '/path'));
|
Proxy(baseUrl.replace(path: '/path'));
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel3_framework/http.dart';
|
import 'package:angel3_framework/http.dart';
|
||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart';
|
||||||
|
|
||||||
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
||||||
final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
||||||
|
@ -16,6 +16,8 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
||||||
class Proxy {
|
class Proxy {
|
||||||
String? _prefix;
|
String? _prefix;
|
||||||
|
|
||||||
|
final Context _p = Context(style: Style.url);
|
||||||
|
|
||||||
/// The underlying [Client] to use.
|
/// The underlying [Client] to use.
|
||||||
final http.Client httpClient;
|
final http.Client httpClient;
|
||||||
|
|
||||||
|
@ -82,12 +84,12 @@ class Proxy {
|
||||||
Future<bool> handleRequest(RequestContext req, ResponseContext res) {
|
Future<bool> handleRequest(RequestContext req, ResponseContext res) {
|
||||||
var path = req.path.replaceAll(_straySlashes, '');
|
var path = req.path.replaceAll(_straySlashes, '');
|
||||||
|
|
||||||
if (_prefix!.isNotEmpty) {
|
if (_prefix?.isNotEmpty == true) {
|
||||||
if (!p.isWithin(_prefix!, path) && !p.equals(_prefix!, path)) {
|
if (!_p.isWithin(_prefix!, path) && !_p.equals(_prefix!, path)) {
|
||||||
return Future<bool>.value(true);
|
return Future<bool>.value(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
path = p.relative(path, from: _prefix);
|
path = _p.relative(path, from: _prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
return servePath(path, req, res);
|
return servePath(path, req, res);
|
||||||
|
@ -98,7 +100,7 @@ class Proxy {
|
||||||
String path, RequestContext req, ResponseContext res) async {
|
String path, RequestContext req, ResponseContext res) async {
|
||||||
http.StreamedResponse rs;
|
http.StreamedResponse rs;
|
||||||
|
|
||||||
var uri = baseUrl.replace(path: p.join(baseUrl.path, path));
|
var uri = baseUrl.replace(path: _p.join(baseUrl.path, path));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (req is HttpRequestContext &&
|
if (req is HttpRequestContext &&
|
||||||
|
@ -123,13 +125,13 @@ class Proxy {
|
||||||
var headers = <String, String>{
|
var headers = <String, String>{
|
||||||
'host': uri.authority,
|
'host': uri.authority,
|
||||||
'x-forwarded-for': req.remoteAddress.address,
|
'x-forwarded-for': req.remoteAddress.address,
|
||||||
'x-forwarded-port': req.uri!.port.toString(),
|
'x-forwarded-port': req.uri?.port.toString() ?? '',
|
||||||
'x-forwarded-host':
|
'x-forwarded-host':
|
||||||
req.headers!.host ?? req.headers!.value('host') ?? 'none',
|
req.headers?.host ?? req.headers?.value('host') ?? 'none',
|
||||||
'x-forwarded-proto': uri.scheme,
|
'x-forwarded-proto': uri.scheme,
|
||||||
};
|
};
|
||||||
|
|
||||||
req.headers!.forEach((name, values) {
|
req.headers?.forEach((name, values) {
|
||||||
headers[name] = values.join(',');
|
headers[name] = values.join(',');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,8 +141,8 @@ class Proxy {
|
||||||
List<int>? body;
|
List<int>? body;
|
||||||
|
|
||||||
if (!req.hasParsedBody) {
|
if (!req.hasParsedBody) {
|
||||||
body = await req.body!
|
body = await req.body
|
||||||
.fold<BytesBuilder>(BytesBuilder(), (bb, buf) => bb..add(buf))
|
?.fold<BytesBuilder>(BytesBuilder(), (bb, buf) => bb..add(buf))
|
||||||
.then((bb) => bb.takeBytes());
|
.then((bb) => bb.takeBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,13 +151,17 @@ class Proxy {
|
||||||
rq.headers['host'] = rq.url.host;
|
rq.headers['host'] = rq.url.host;
|
||||||
rq.encoding = Utf8Codec(allowMalformed: true);
|
rq.encoding = Utf8Codec(allowMalformed: true);
|
||||||
|
|
||||||
if (body != null) rq.bodyBytes = body;
|
if (body != null) {
|
||||||
|
rq.bodyBytes = body;
|
||||||
|
}
|
||||||
|
|
||||||
return httpClient.send(rq);
|
return httpClient.send(rq);
|
||||||
}
|
}
|
||||||
|
|
||||||
var future = accessRemote();
|
var future = accessRemote();
|
||||||
if (timeout != null) future = future.timeout(timeout!);
|
if (timeout != null) {
|
||||||
|
future = future.timeout(timeout!);
|
||||||
|
}
|
||||||
rs = await future;
|
rs = await future;
|
||||||
} on TimeoutException catch (e, st) {
|
} on TimeoutException catch (e, st) {
|
||||||
if (recoverFromDead) return true;
|
if (recoverFromDead) return true;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
name: angel3_proxy
|
name: angel3_proxy
|
||||||
version: 4.0.0
|
version: 4.0.1
|
||||||
description: Angel middleware to forward requests to another server (i.e. pub serve).
|
description: Angel middleware to forward requests to another server (i.e. pub serve).
|
||||||
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy
|
homepage: https://angel3-framework.web.app/
|
||||||
|
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/proxy
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -9,7 +9,7 @@ import 'package:test/test.dart';
|
||||||
import 'common.dart';
|
import 'common.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
Angel? app;
|
late Angel app;
|
||||||
var client = http.IOClient();
|
var client = http.IOClient();
|
||||||
//late HttpServer server;
|
//late HttpServer server;
|
||||||
late HttpServer testServer;
|
late HttpServer testServer;
|
||||||
|
@ -17,7 +17,7 @@ void main() {
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
app = Angel();
|
app = Angel();
|
||||||
var appHttp = AngelHttp(app!);
|
var appHttp = AngelHttp(app);
|
||||||
|
|
||||||
testServer = await startTestServer();
|
testServer = await startTestServer();
|
||||||
|
|
||||||
|
@ -33,15 +33,15 @@ void main() {
|
||||||
print('Proxy 1 on: ${proxy1.baseUrl}');
|
print('Proxy 1 on: ${proxy1.baseUrl}');
|
||||||
print('Proxy 2 on: ${proxy2.baseUrl}');
|
print('Proxy 2 on: ${proxy2.baseUrl}');
|
||||||
|
|
||||||
app!.all('/proxy/*', proxy1.handleRequest);
|
app.all('/proxy/*', proxy1.handleRequest);
|
||||||
app!.all('*', proxy2.handleRequest);
|
app.all('*', proxy2.handleRequest);
|
||||||
|
|
||||||
app!.fallback((req, res) {
|
app.fallback((req, res) {
|
||||||
print('Intercepting empty from ${req.uri}');
|
print('Intercepting empty from ${req.uri}');
|
||||||
res.write('intercept empty');
|
res.write('intercept empty');
|
||||||
});
|
});
|
||||||
|
|
||||||
app!.logger = Logger('angel');
|
app.logger = Logger('angel');
|
||||||
|
|
||||||
Logger.root.onRecord.listen((rec) {
|
Logger.root.onRecord.listen((rec) {
|
||||||
print(rec);
|
print(rec);
|
||||||
|
@ -56,7 +56,6 @@ void main() {
|
||||||
tearDown(() async {
|
tearDown(() async {
|
||||||
await testServer.close(force: true);
|
await testServer.close(force: true);
|
||||||
//await server.close(force: true);
|
//await server.close(force: true);
|
||||||
app = null;
|
|
||||||
url = null;
|
url = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
name: angel3_static
|
name: angel3_static
|
||||||
description: This library provides a virtual directory to serve static files for Angel3 framework.
|
description: This library provides a virtual directory to serve static files for Angel3 framework.
|
||||||
version: 4.0.2
|
version: 4.0.2
|
||||||
homepage: https://github.com/dukefirehawk/angel
|
homepage: https://angel3-framework.web.app/
|
||||||
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/static
|
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/static
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
|
@ -1,63 +1,88 @@
|
||||||
# 4.0.0
|
# Change Log
|
||||||
|
|
||||||
|
## 4.0.1
|
||||||
|
|
||||||
|
* Updated README
|
||||||
|
* Fixed NNBD issues
|
||||||
|
|
||||||
|
## 4.0.0
|
||||||
|
|
||||||
* Migrated to support Dart SDK 2.12.x NNBD
|
* Migrated to support Dart SDK 2.12.x NNBD
|
||||||
|
|
||||||
# 3.0.0
|
## 3.0.0
|
||||||
|
|
||||||
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
* Migrated to work with Dart SDK 2.12.x Non NNBD
|
||||||
|
|
||||||
# 2.0.3
|
## 2.0.3
|
||||||
|
|
||||||
* Remove `WebSocketController.plugin`.
|
* Remove `WebSocketController.plugin`.
|
||||||
* Remove any unawaited futures.
|
* Remove any unawaited futures.
|
||||||
|
|
||||||
# 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
* Update `stream_channel` to `2.0.0`.
|
* Update `stream_channel` to `2.0.0`.
|
||||||
* Use `angel_framework^@2.0.0-rc.0`.
|
* Use `angel_framework^@2.0.0-rc.0`.
|
||||||
|
|
||||||
# 2.0.1
|
## 2.0.1
|
||||||
|
|
||||||
* Add `reconnectOnClose` and `reconnectinterval` parameters in top-level `WebSockets` constructors.
|
* Add `reconnectOnClose` and `reconnectinterval` parameters in top-level `WebSockets` constructors.
|
||||||
* Close `WebSocketExtraneousEventHandler`.
|
* Close `WebSocketExtraneousEventHandler`.
|
||||||
* Add onAuthenticated to server-side.
|
* Add onAuthenticated to server-side.
|
||||||
|
|
||||||
# 2.0.0
|
## 2.0.0
|
||||||
|
|
||||||
* Update to work with `client@2.0.0`.
|
* Update to work with `client@2.0.0`.
|
||||||
|
|
||||||
# 2.0.0-alpha.8
|
## 2.0.0-alpha.8
|
||||||
|
|
||||||
* Support for WebSockets over HTTP/2 (though in practice this doesn't often happen, if ever).
|
* Support for WebSockets over HTTP/2 (though in practice this doesn't often happen, if ever).
|
||||||
|
|
||||||
# 2.0.0-alpha.7
|
## 2.0.0-alpha.7
|
||||||
|
|
||||||
* Replace `WebSocketSynchronizer` with `StreamChannel<WebSocketEvent>`.
|
* Replace `WebSocketSynchronizer` with `StreamChannel<WebSocketEvent>`.
|
||||||
|
|
||||||
# 2.0.0-alpha.6
|
## 2.0.0-alpha.6
|
||||||
|
|
||||||
* Explicit import of `import 'package:http/io_client.dart' as http;`
|
* Explicit import of `import 'package:http/io_client.dart' as http;`
|
||||||
|
|
||||||
# 2.0.0-alpha.5
|
## 2.0.0-alpha.5
|
||||||
|
|
||||||
* Update `http` dependency.
|
* Update `http` dependency.
|
||||||
|
|
||||||
# 2.0.0-alpha.4
|
## 2.0.0-alpha.4
|
||||||
|
|
||||||
* Remove `package:json_god`.
|
* Remove `package:json_god`.
|
||||||
* Make `WebSocketContext` take any `StreamChannel`.
|
* Make `WebSocketContext` take any `StreamChannel`.
|
||||||
* Strong typing updates.
|
* Strong typing updates.
|
||||||
|
|
||||||
# 2.0.0-alpha.3
|
## 2.0.0-alpha.3
|
||||||
|
|
||||||
* Directly import Angel HTTP.
|
* Directly import Angel HTTP.
|
||||||
|
|
||||||
# 2.0.0-alpha.2
|
## 2.0.0-alpha.2
|
||||||
|
|
||||||
* Updated for the next version of `angel_client`.
|
* Updated for the next version of `angel_client`.
|
||||||
|
|
||||||
# 2.0.0-alpha.1
|
## 2.0.0-alpha.1
|
||||||
|
|
||||||
* Refactorings for updated Angel 2 versions.
|
* Refactorings for updated Angel 2 versions.
|
||||||
* Remove `package:dart2_constant`.
|
* Remove `package:dart2_constant`.
|
||||||
|
|
||||||
# 2.0.0-alpha
|
## 2.0.0-alpha
|
||||||
|
|
||||||
* Depend on Dart 2 and Angel 2.
|
* Depend on Dart 2 and Angel 2.
|
||||||
|
|
||||||
# 1.1.2
|
## 1.1.2
|
||||||
|
|
||||||
* Dart 2 updates.
|
* Dart 2 updates.
|
||||||
* Added `handleClient`, which is nice for external implementations
|
* Added `handleClient`, which is nice for external implementations
|
||||||
that plug into `AngelWebSocket`.
|
that plug into `AngelWebSocket`.
|
||||||
|
|
||||||
# 1.1.1
|
## 1.1.1
|
||||||
|
|
||||||
* Deprecated `unwrap`.
|
* Deprecated `unwrap`.
|
||||||
* Service streams now pump out `e.data`, rather than the actual event.
|
* Service streams now pump out `e.data`, rather than the actual event.
|
||||||
|
|
||||||
# 1.1.0+1
|
## 1.1.0+1
|
||||||
|
|
||||||
* Added `unwrap`.
|
* Added `unwrap`.
|
|
@ -1,29 +1,24 @@
|
||||||
# angel3_websocket
|
# Angel3 Websocket Library
|
||||||
[![version](https://img.shields.io/badge/pub-v4.0.0-brightgreen)](https://pub.dartlang.org/packages/angel3_websocket)
|
|
||||||
|
[![version](https://img.shields.io/badge/pub-v4.0.1-brightgreen)](https://pub.dartlang.org/packages/angel3_websocket)
|
||||||
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
|
||||||
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
|
||||||
|
|
||||||
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/websocket/LICENSE)
|
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/websocket/LICENSE)
|
||||||
|
|
||||||
WebSocket plugin for Angel.
|
WebSocket plugin for Angel3. This plugin broadcasts events from hooked services via WebSockets. In addition, it adds itself to the app's IoC container as `AngelWebSocket`, so that it can be used in controllers as well.
|
||||||
|
|
||||||
This plugin broadcasts events from hooked services via WebSockets.
|
|
||||||
|
|
||||||
In addition, it adds itself to the app's IoC container as `AngelWebSocket`, so that it can be used
|
|
||||||
in controllers as well.
|
|
||||||
|
|
||||||
WebSocket contexts are add to `req.properties` as `'socket'`.
|
WebSocket contexts are add to `req.properties` as `'socket'`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
# Usage
|
### Server-side
|
||||||
|
|
||||||
**Server-side**
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import "package:angel3_framework/angel3_framework.dart";
|
import "package:angel3_framework/angel3_framework.dart";
|
||||||
import "package:angel3_websocket/server.dart";
|
import "package:angel3_websocket/server.dart";
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
var app = Angel();
|
var app = Angel();
|
||||||
|
|
||||||
var ws = AngelWebSocket();
|
var ws = AngelWebSocket();
|
||||||
|
@ -38,8 +33,7 @@ main() async {
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Filtering events is easy with hooked services. Just return a `bool`, whether
|
Filtering events is easy with hooked services. Just return a `bool`, whether synchronously or asynchronously.
|
||||||
synchronously or asynchronously.
|
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
myService.properties['ws:filter'] = (HookedServiceEvent e, WebSocketContext socket) async {
|
myService.properties['ws:filter'] = (HookedServiceEvent e, WebSocketContext socket) async {
|
||||||
|
@ -51,14 +45,14 @@ myService.index({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
**Adding Handlers within a Controller**
|
#### Adding Handlers within a Controller
|
||||||
|
|
||||||
`WebSocketController` extends a normal `Controller`, but also listens to WebSockets.
|
`WebSocketController` extends a normal `Controller`, but also listens to WebSockets.
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import "package:angel_framework/angel_framework.dart";
|
import "package:angel3_framework/angel3_framework.dart";
|
||||||
import "package:angel_websocket/server.dart";
|
import "package:angel3_websocket/server.dart";
|
||||||
|
|
||||||
@Expose("/")
|
@Expose("/")
|
||||||
class MyController extends WebSocketController {
|
class MyController extends WebSocketController {
|
||||||
|
@ -86,25 +80,22 @@ class MyController extends WebSocketController {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Client Use**
|
### Client Use
|
||||||
|
|
||||||
This repo also provides two client libraries `browser` and `io` that extend the base
|
This repo also provides two client libraries `browser` and `io` that extend the base `angel3_client` interface, and allow you to use a very similar API on the client to that of the server.
|
||||||
`angel3_client` interface, and allow you to use a very similar API on the client to that of
|
|
||||||
the server.
|
|
||||||
|
|
||||||
The provided clients also automatically try to reconnect their WebSockets when disconnected,
|
The provided clients also automatically try to reconnect their WebSockets when disconnected, which means you can restart your development server without having to reload browser windows.
|
||||||
which means you can restart your development server without having to reload browser windows.
|
|
||||||
|
|
||||||
They also provide streams of data that pump out filtered data as it comes in from the server.
|
They also provide streams of data that pump out filtered data as it comes in from the server.
|
||||||
|
|
||||||
Clients can even perform authentication over WebSockets.
|
Clients can even perform authentication over WebSockets.
|
||||||
|
|
||||||
**In the Browser**
|
#### In the Browser
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import "package:angel3_websocket/browser.dart";
|
import "package:angel3_websocket/browser.dart";
|
||||||
|
|
||||||
main() async {
|
void main() async {
|
||||||
Angel app = WebSockets("/ws");
|
Angel app = WebSockets("/ws");
|
||||||
await app.connect();
|
await app.connect();
|
||||||
|
|
||||||
|
@ -127,7 +118,7 @@ main() async {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**CLI Client**
|
#### CLI Client
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
import "package:angel3_framework/common.dart";
|
import "package:angel3_framework/common.dart";
|
||||||
|
|
|
@ -241,7 +241,7 @@ abstract class BaseWebSocketClient extends BaseAngelClient {
|
||||||
if (_socket == null) {
|
if (_socket == null) {
|
||||||
_queue.addLast(action);
|
_queue.addLast(action);
|
||||||
} else {
|
} else {
|
||||||
socket!.sink.add(serialize(action));
|
socket?.sink.add(serialize(action));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ class WebSockets extends BaseWebSocketClient {
|
||||||
StreamSubscription<Event>? sub;
|
StreamSubscription<Event>? sub;
|
||||||
t = Timer.periodic(Duration(milliseconds: 500), (timer) {
|
t = Timer.periodic(Duration(milliseconds: 500), (timer) {
|
||||||
if (!ctrl.isClosed) {
|
if (!ctrl.isClosed) {
|
||||||
if (wnd.closed!) {
|
if (wnd.closed == true) {
|
||||||
ctrl.addError(AngelHttpException.notAuthenticated(
|
ctrl.addError(AngelHttpException.notAuthenticated(
|
||||||
message:
|
message:
|
||||||
errorMessage ?? 'Authentication via popup window failed.'));
|
errorMessage ?? 'Authentication via popup window failed.'));
|
||||||
|
@ -60,7 +60,7 @@ class WebSockets extends BaseWebSocketClient {
|
||||||
ctrl.add((e as CustomEvent).detail.toString());
|
ctrl.add((e as CustomEvent).detail.toString());
|
||||||
t.cancel();
|
t.cancel();
|
||||||
ctrl.close();
|
ctrl.close();
|
||||||
sub!.cancel();
|
sub?.cancel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:angel3_framework/angel3_framework.dart';
|
||||||
HookedServiceEventListener doNotBroadcast([provider]) {
|
HookedServiceEventListener doNotBroadcast([provider]) {
|
||||||
return (HookedServiceEvent e) {
|
return (HookedServiceEvent e) {
|
||||||
if (e.params != null && e.params!.containsKey('provider')) {
|
if (e.params != null && e.params!.containsKey('provider')) {
|
||||||
|
var eParam = e.params!;
|
||||||
var deny = false;
|
var deny = false;
|
||||||
var providers = provider is Iterable ? provider : [provider];
|
var providers = provider is Iterable ? provider : [provider];
|
||||||
|
|
||||||
|
@ -14,18 +15,15 @@ HookedServiceEventListener doNotBroadcast([provider]) {
|
||||||
if (deny) break;
|
if (deny) break;
|
||||||
|
|
||||||
if (p is Providers) {
|
if (p is Providers) {
|
||||||
deny = deny ||
|
deny = deny || p == eParam['provider'] || eParam['provider'] == p.via;
|
||||||
p == e.params!['provider'] ||
|
|
||||||
e.params!['provider'] == p.via;
|
|
||||||
} else if (p == null) {
|
} else if (p == null) {
|
||||||
deny = true;
|
deny = true;
|
||||||
} else {
|
} else {
|
||||||
deny =
|
deny = deny || (eParam['provider'] as Providers).via == p.toString();
|
||||||
deny || (e.params!['provider'] as Providers).via == p.toString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.params!['broadcast'] = false;
|
eParam['broadcast'] = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:stream_channel/stream_channel.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
import 'package:web_socket_channel/io.dart';
|
||||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
import 'package:collection/collection.dart' show IterableExtension;
|
import 'package:collection/collection.dart' show IterableExtension;
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'angel3_websocket.dart';
|
import 'angel3_websocket.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
export 'angel3_websocket.dart';
|
export 'angel3_websocket.dart';
|
||||||
|
@ -26,6 +27,8 @@ typedef WebSocketResponseSerializer = String Function(dynamic data);
|
||||||
|
|
||||||
/// Broadcasts events from [HookedService]s, and handles incoming [WebSocketAction]s.
|
/// Broadcasts events from [HookedService]s, and handles incoming [WebSocketAction]s.
|
||||||
class AngelWebSocket {
|
class AngelWebSocket {
|
||||||
|
final _log = Logger('AngelWebSocket');
|
||||||
|
|
||||||
final List<WebSocketContext> _clients = <WebSocketContext>[];
|
final List<WebSocketContext> _clients = <WebSocketContext>[];
|
||||||
final List<String> _servicesAlreadyWired = [];
|
final List<String> _servicesAlreadyWired = [];
|
||||||
|
|
||||||
|
@ -258,6 +261,7 @@ class AngelWebSocket {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
|
_log.severe('Unable to handle unknown action');
|
||||||
catchError(e, st, socket);
|
catchError(e, st, socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,15 +270,15 @@ class AngelWebSocket {
|
||||||
Future handleAuth(WebSocketAction action, WebSocketContext socket) async {
|
Future handleAuth(WebSocketAction action, WebSocketContext socket) async {
|
||||||
if (allowAuth != false &&
|
if (allowAuth != false &&
|
||||||
action.eventName == authenticateAction &&
|
action.eventName == authenticateAction &&
|
||||||
action.params!['query'] is Map &&
|
action.params?['query'] is Map &&
|
||||||
action.params!['query']['jwt'] is String) {
|
action.params?['query']['jwt'] is String) {
|
||||||
try {
|
try {
|
||||||
var auth = socket.request.container!.make<AngelAuth>()!;
|
var auth = socket.request.container!.make<AngelAuth>()!;
|
||||||
var jwt = action.params!['query']['jwt'] as String;
|
var jwt = action.params!['query']['jwt'] as String;
|
||||||
AuthToken token;
|
AuthToken token;
|
||||||
|
|
||||||
token = AuthToken.validate(jwt, auth.hmac);
|
token = AuthToken.validate(jwt, auth.hmac);
|
||||||
var user = await auth.deserializer!(token.userId as Object);
|
var user = await auth.deserializer(token.userId as Object);
|
||||||
socket.request
|
socket.request
|
||||||
..container!.registerSingleton<AuthToken>(token)
|
..container!.registerSingleton<AuthToken>(token)
|
||||||
..container!.registerSingleton(user, as: user.runtimeType);
|
..container!.registerSingleton(user, as: user.runtimeType);
|
||||||
|
@ -282,6 +286,7 @@ class AngelWebSocket {
|
||||||
socket.send(authenticatedEvent,
|
socket.send(authenticatedEvent,
|
||||||
{'token': token.serialize(auth.hmac), 'data': user});
|
{'token': token.serialize(auth.hmac), 'data': user});
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
|
_log.severe('Authentication failed');
|
||||||
catchError(e, st, socket);
|
catchError(e, st, socket);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -345,6 +350,7 @@ class AngelWebSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
|
_log.severe('Invalid data');
|
||||||
catchError(e, st, socket);
|
catchError(e, st, socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -353,16 +359,16 @@ class AngelWebSocket {
|
||||||
// Send an error
|
// Send an error
|
||||||
if (e is AngelHttpException) {
|
if (e is AngelHttpException) {
|
||||||
socket.sendError(e);
|
socket.sendError(e);
|
||||||
app!.logger?.severe(e.message, e.error ?? e, e.stackTrace);
|
app?.logger?.severe(e.message, e.error ?? e, e.stackTrace);
|
||||||
} else if (sendErrors) {
|
} else if (sendErrors) {
|
||||||
var err = AngelHttpException(e,
|
var err = AngelHttpException(e,
|
||||||
message: e.toString(), stackTrace: st, errors: [st.toString()]);
|
message: e.toString(), stackTrace: st, errors: [st.toString()]);
|
||||||
socket.sendError(err);
|
socket.sendError(err);
|
||||||
app!.logger?.severe(err.message, e, st);
|
app?.logger?.severe(err.message, e, st);
|
||||||
} else {
|
} else {
|
||||||
var err = AngelHttpException(e);
|
var err = AngelHttpException(e);
|
||||||
socket.sendError(err);
|
socket.sendError(err);
|
||||||
app!.logger?.severe(e.toString(), e, st);
|
app?.logger?.severe(e.toString(), e, st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,10 +389,10 @@ class AngelWebSocket {
|
||||||
|
|
||||||
/// Configures an [Angel] instance to listen for WebSocket connections.
|
/// Configures an [Angel] instance to listen for WebSocket connections.
|
||||||
Future configureServer(Angel app) async {
|
Future configureServer(Angel app) async {
|
||||||
app.container!.registerSingleton(this);
|
app.container?.registerSingleton(this);
|
||||||
|
|
||||||
if (runtimeType != AngelWebSocket) {
|
if (runtimeType != AngelWebSocket) {
|
||||||
app.container!.registerSingleton<AngelWebSocket>(this);
|
app.container?.registerSingleton<AngelWebSocket>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up services
|
// Set up services
|
||||||
|
@ -397,7 +403,7 @@ class AngelWebSocket {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (synchronizationChannel != null) {
|
if (synchronizationChannel != null) {
|
||||||
synchronizationChannel!.stream
|
synchronizationChannel?.stream
|
||||||
.listen((e) => batchEvent(e, notify: false));
|
.listen((e) => batchEvent(e, notify: false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +412,7 @@ class AngelWebSocket {
|
||||||
|
|
||||||
/// Handles an incoming [WebSocketContext].
|
/// Handles an incoming [WebSocketContext].
|
||||||
Future<void> handleClient(WebSocketContext socket) async {
|
Future<void> handleClient(WebSocketContext socket) async {
|
||||||
var origin = socket.request.headers!.value('origin');
|
var origin = socket.request.headers?.value('origin');
|
||||||
if (allowedOrigins != null && !allowedOrigins!.contains(origin)) {
|
if (allowedOrigins != null && !allowedOrigins!.contains(origin)) {
|
||||||
throw AngelHttpException.forbidden(
|
throw AngelHttpException.forbidden(
|
||||||
message:
|
message:
|
||||||
|
@ -418,7 +424,7 @@ class AngelWebSocket {
|
||||||
|
|
||||||
_onConnection.add(socket);
|
_onConnection.add(socket);
|
||||||
|
|
||||||
socket.request.container!.registerSingleton<WebSocketContext>(socket);
|
socket.request.container?.registerSingleton<WebSocketContext>(socket);
|
||||||
|
|
||||||
socket.channel.stream.listen(
|
socket.channel.stream.listen(
|
||||||
(data) {
|
(data) {
|
||||||
|
@ -451,11 +457,11 @@ class AngelWebSocket {
|
||||||
return false;
|
return false;
|
||||||
} else if (req is Http2RequestContext && res is Http2ResponseContext) {
|
} else if (req is Http2RequestContext && res is Http2ResponseContext) {
|
||||||
var connection =
|
var connection =
|
||||||
req.headers!['connection']?.map((s) => s.toLowerCase().trim());
|
req.headers?['connection']?.map((s) => s.toLowerCase().trim());
|
||||||
var upgrade = req.headers!.value('upgrade')?.toLowerCase();
|
var upgrade = req.headers?.value('upgrade')?.toLowerCase();
|
||||||
var version = req.headers!.value('sec-websocket-version');
|
var version = req.headers?.value('sec-websocket-version');
|
||||||
var key = req.headers!.value('sec-websocket-key');
|
var key = req.headers?.value('sec-websocket-key');
|
||||||
var protocol = req.headers!.value('sec-websocket-protocol');
|
var protocol = req.headers?.value('sec-websocket-protocol');
|
||||||
|
|
||||||
if (connection == null) {
|
if (connection == null) {
|
||||||
throw AngelHttpException.badRequest(
|
throw AngelHttpException.badRequest(
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
name: angel3_websocket
|
name: angel3_websocket
|
||||||
description: Support for using pkg:angel_client with WebSockets. Designed for Angel.
|
description: This library provides WebSockets support for Angel3 framework.
|
||||||
version: 4.0.0
|
version: 4.0.1
|
||||||
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/websocket
|
homepage: https://angel3-framework.web.app/
|
||||||
|
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/websocket
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -15,10 +16,10 @@ dependencies:
|
||||||
stream_channel: ^2.1.0
|
stream_channel: ^2.1.0
|
||||||
web_socket_channel: ^2.1.0
|
web_socket_channel: ^2.1.0
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
|
logging: ^1.0.1
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
angel3_container: ^3.0.0
|
angel3_container: ^3.0.0
|
||||||
angel3_model: ^3.0.0
|
angel3_model: ^3.0.0
|
||||||
logging: ^1.0.1
|
|
||||||
pedantic: ^1.11.0
|
pedantic: ^1.11.0
|
||||||
test: ^1.17.4
|
test: ^1.17.4
|
||||||
|
|
|
@ -18,10 +18,8 @@ void main() {
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
app = Angel();
|
app = Angel();
|
||||||
http = AngelHttp(app, useZone: false);
|
http = AngelHttp(app, useZone: false);
|
||||||
var auth = AngelAuth();
|
var auth = AngelAuth(
|
||||||
|
serializer: (_) async => 'baz', deserializer: (_) async => USER);
|
||||||
auth.serializer = (_) async => 'baz';
|
|
||||||
auth.deserializer = (_) async => USER;
|
|
||||||
|
|
||||||
auth.strategies['local'] = LocalAuthStrategy(
|
auth.strategies['local'] = LocalAuthStrategy(
|
||||||
(username, password) async {
|
(username, password) async {
|
||||||
|
|
Loading…
Reference in a new issue