Merge pull request #87 from dukefirehawk/feature/fix-deprecated

Feature/fix deprecated
This commit is contained in:
Thomas Hii 2022-12-03 11:31:57 +08:00 committed by GitHub
commit a7c750e70f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
155 changed files with 164 additions and 5786 deletions

View file

@ -21,7 +21,7 @@ jobs:
- uses: dart-lang/setup-dart@v1
with:
sdk: "2.17.0"
sdk: "2.18.0"
- id: angel3_container_upgrade
name: angel3_container; Upgrade depedencies
@ -87,7 +87,7 @@ jobs:
- uses: dart-lang/setup-dart@v1
with:
sdk: "2.17.0"
sdk: "2.18.0"
# Angel3 ORM
- id: angel3_orm_upgrade

Binary file not shown.

View file

@ -1,65 +0,0 @@
# 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

View file

@ -1,21 +0,0 @@
MIT License (MIT)
Copyright (c) 2021 dukefirehawk.com
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.

View file

@ -1,33 +0,0 @@
# 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);
```

View file

@ -1,3 +0,0 @@
analyzer:
strong-mode:
implicit-casts: false

View file

@ -1,14 +0,0 @@
<?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>

View file

@ -1,50 +0,0 @@
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);
}
}

View file

@ -1,29 +0,0 @@
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();
}

View file

@ -1 +0,0 @@
export 'package:angel_websocket/angel_websocket.dart';

View file

@ -1,51 +0,0 @@
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);
}
}

View file

@ -1,26 +0,0 @@
name: angel_eventsource
version: 2.0.0
description: Server-sent Events (SSE) plugin for Angel.
homepage: https://github.com/angel-dart/eventsource
publish_to: none
environment:
sdk: ">=2.10.0 <3.0.0"
dependencies:
angel_framework:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x
path: packages/framework
angel_websocket:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x
path: packages/websocket
eventsource:
git:
url: https://github.com/dukefirehawk/dart-eventsource.git
stream_channel: ^2.0.0
dev_dependencies:
console: ^4.0.0
logging: ^1.0.0
test: ^1.16.5

BIN
archived_packages/orm.zip Normal file

Binary file not shown.

View file

@ -1,21 +0,0 @@
MIT License (MIT)
Copyright (c) 2021 dukefirehawk.com
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.

View file

@ -1,5 +0,0 @@
name: angel_orm_sqlite
environment:
sdk: ">=2.16.0 <3.0.0"
dependencies:
angel_orm: ^2.0.0-dev

BIN
archived_packages/poll.zip Normal file

Binary file not shown.

View file

@ -1,64 +0,0 @@
# 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/

View file

@ -1 +0,0 @@
language: dart

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,9 +0,0 @@
# Change Log
## 2.0.0
* Migrated to support Dart >= 2.12 NNBD
## 1.0.0
* Created package + tests

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,42 +0,0 @@
# poll
[![Pub](https://img.shields.io/pub/v/angel_poll.svg)](https://pub.dartlang.org/packages/angel_poll)
[![build status](https://travis-ci.org/angel-dart/poll.svg?branch=master)](https://travis-ci.org/angel-dart/poll)
`package:angel_client` support for "realtime" interactions with Angel via long polling.
Angel supports [WebSockets](https://github.com/angel-dart/websocket) on the server and client, which
makes it very straightforward to implement realtime collections. However, not every user's browser
supports WebSockets. In such a case, applications might *gracefully degrade* to long-polling
the server for changes.
A `PollingService` wraps a client-side `Service` (typically a REST-based one), and calls its
`index` method at a regular interval. After indexing, the `PollingService` performs a diff
and identifies whether items have been created, modified, or removed. The updates are sent out
through `onCreated`, `onModified`, etc., effectively managing a real-time collection of data.
A common use-case would be passing this service to `ServiceList`, a class that manages the state
of a collection managed in real-time.
```dart
import 'package:angel_client/io.dart';
import 'package:angel_poll/angel_poll.dart';
main() {
var app = new Rest('http://localhost:3000');
var todos = new ServiceList(
new PollingService(
// Typically, you'll pass a REST-based service instance here.
app.service('api/todos'),
// `index` called every 5 seconds
const Duration(seconds: 5),
),
);
todos.onChange.listen((_) {
// Something happened here.
// Maybe an item was created, modified, etc.
});
}
```

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,21 +0,0 @@
import 'package:angel_client/io.dart';
import 'package:angel_poll/angel_poll.dart';
void main() {
var app = Rest('http://localhost:3000');
var todos = ServiceList(
PollingService(
// Typically, you'll pass a REST-based service instance here.
app.service('api/todos'),
// `index` called every 5 seconds
const Duration(seconds: 5),
),
);
todos.onChange.listen((_) {
// Something happened here.
// Maybe an item was created, modified, etc.
});
}

View file

@ -1,265 +0,0 @@
import 'dart:async';
import 'package:collection/collection.dart';
import 'package:angel_client/angel_client.dart';
/// A [Service] that facilitates real-time updates via the long polling of an [inner] service.
///
/// Works well with [ServiceList].
class PollingService extends Service {
/// The underlying [Service] that does the actual communication with the server.
final Service inner;
/// Perform computations after polling to discern whether new items were created.
final bool checkForCreated;
/// Perform computations after polling to discern whether items were modified.
final bool checkForModified;
/// Perform computations after polling to discern whether items were removed.
final bool checkForRemoved;
/// An [EqualityBy] used to compare the ID's of two items.
///
/// Defaults to comparing the [idField] of two `Map` instances.
final EqualityBy compareId;
/// An [Equality] used to discern whether two items, with the same [idField], are the same item.
///
/// Defaults to [MapEquality], which deep-compares `Map` instances.
final Equality compareItems;
/// A [String] used as an index through which to compare `Map` instances.
///
/// Defaults to `id`.
final String idField;
/// If `true` (default: `false`), then `index` events will be handled as a [Map] containing a `data` field.
///
/// See https://github.com/angel-dart/paginate.
final bool asPaginated;
final List _items = [];
final List<StreamSubscription> _subs = [];
final StreamController<List<dynamic>> _onIndexed = StreamController(),
_onRead = StreamController(),
_onCreated = StreamController(),
_onModified = StreamController(),
_onUpdated = StreamController(),
_onRemoved = StreamController();
late Timer _timer;
@override
Angel get app => inner.app;
@override
Stream<List<dynamic>> get onIndexed => _onIndexed.stream;
@override
Stream get onRead => _onRead.stream;
@override
Stream get onCreated => _onCreated.stream;
@override
Stream get onModified => _onModified.stream;
@override
Stream get onUpdated => _onUpdated.stream;
@override
Stream get onRemoved => _onRemoved.stream;
PollingService(this.inner, Duration interval,
{this.checkForCreated = true,
this.checkForModified = true,
this.checkForRemoved = true,
this.idField = 'id',
this.asPaginated = false,
EqualityBy? compareId,
this.compareItems = const MapEquality()})
: compareId = compareId ?? EqualityBy((map) => map[idField]) {
_timer = Timer.periodic(interval, (_) {
index().catchError((error) {
_onIndexed.addError(error as Object);
});
});
var streams = <Stream, StreamController>{
inner.onRead: _onRead,
inner.onCreated: _onCreated,
inner.onModified: _onModified,
inner.onUpdated: _onUpdated,
inner.onRemoved: _onRemoved,
};
streams.forEach((stream, ctrl) {
_subs.add(stream.listen(ctrl.add, onError: ctrl.addError));
});
_subs.add(
inner.onIndexed.listen(
_handleIndexed,
onError: _onIndexed.addError,
),
);
}
@override
Future close() async {
_timer.cancel();
for (var s in _subs) {
s.cancel();
}
await _onIndexed.close();
await _onRead.close();
await _onCreated.close();
await _onModified.close();
await _onUpdated.close();
await _onRemoved.close();
}
// TODO: To revisit this logic
@override
Future<List<dynamic>> index([Map? params]) {
return inner.index().then((data) {
//return asPaginated == true ? data['data'] : data;
//return asPaginated == true ? data[0] : data;
return data;
});
}
/*
@override
Future index([Map params]) {
}
*/
@override
Future remove(id, [Map<String, dynamic>? params]) {
return inner.remove(id, params).then((result) {
_items.remove(result);
return result;
}).catchError(_onRemoved.addError);
}
dynamic _handleUpdate(result) {
var index = -1;
for (var i = 0; i < _items.length; i++) {
if (compareId.equals(_items[i], result)) {
index = i;
break;
}
}
if (index > -1) {
_items[index] = result;
}
return result;
}
@override
Future update(id, data, [Map<String, dynamic>? params]) {
return inner
.update(id, data, params)
.then(_handleUpdate)
.catchError(_onUpdated.addError);
}
@override
Future modify(id, data, [Map<String, dynamic>? params]) {
return inner
.modify(id, data, params)
.then(_handleUpdate)
.catchError(_onModified.addError);
}
@override
Future create(data, [Map<String, dynamic>? params]) {
return inner.create(data, params).then((result) {
_items.add(result);
return result;
}).catchError(_onCreated.addError);
}
@override
Future read(id, [Map<String, dynamic>? params]) {
return inner.read(id, params);
}
void _handleIndexed(List<dynamic> data) {
//var items = asPaginated == true ? data['data'] : data;
var items = data;
var changesComputed = false;
if (checkForCreated != false) {
var newItems = <int, dynamic>{};
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (!_items.any((i) => compareId.equals(i, item))) {
newItems[i] = item;
}
}
newItems.forEach((index, item) {
_items.insert(index, item);
_onCreated.add([item]);
});
changesComputed = newItems.isNotEmpty;
}
if (checkForRemoved != false) {
var removedItems = <int, dynamic>{};
for (var i = 0; i < _items.length; i++) {
var item = _items[i];
if (!items.any((i) => compareId.equals(i, item))) {
removedItems[i] = item;
}
}
removedItems.forEach((index, item) {
_items.removeAt(index);
_onRemoved.add([item]);
});
changesComputed = changesComputed || removedItems.isNotEmpty;
}
if (checkForModified != false) {
var modifiedItems = <int, dynamic>{};
for (var item in items) {
for (var i = 0; i < _items.length; i++) {
var localItem = _items[i];
if (compareId.equals(item, localItem)) {
if (!compareItems.equals(item, localItem)) {
modifiedItems[i] = item;
}
break;
}
}
}
modifiedItems.forEach((index, item) {
_onModified.add([_items[index] = item]);
});
changesComputed = changesComputed || modifiedItems.isNotEmpty;
}
if (!changesComputed) {
_items
..clear()
..add(items);
_onIndexed.add([items]);
}
}
}

View file

@ -1,14 +0,0 @@
<?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>

View file

@ -1,23 +0,0 @@
name: angel_poll
version: 2.0.0
description: package:angel_client support for "realtime" interactions with Angel via long polling.
publish_to: none
environment:
sdk: '>=2.12.0 <3.0.0'
homepage: https://github.com/angel-dart/poll
dependencies:
angel_client: # ^1.0.0
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/client
async: ^2.7.0
collection: ^1.15.0
dev_dependencies:
angel_test:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/test
test: ^1.17.8
lints: ^1.0.0

View file

@ -1,105 +0,0 @@
import 'package:angel_framework/angel_framework.dart' as srv;
import 'package:angel_container/mirrors.dart';
import 'package:angel_poll/angel_poll.dart';
import 'package:angel_test/angel_test.dart';
import 'package:async/async.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
void main() {
late srv.Service store;
late TestClient client;
late PollingService pollingService;
var created;
late StreamQueue onCreated;
late StreamQueue onModified;
late StreamQueue onRemoved;
setUp(() async {
var app = srv.Angel(reflector: MirrorsReflector());
app.logger = Logger.detached('angel_poll')
..onRecord.listen((rec) {
print(rec);
if (rec.error != null) {
print(rec.error);
print(rec.stackTrace);
}
});
store = app.use(
'/api/todos',
srv.MapService(
autoIdAndDateFields: false,
),
);
client = await connectTo(app);
pollingService = PollingService(
client.service('api/todos'),
const Duration(milliseconds: 100),
);
onCreated = StreamQueue(pollingService.onCreated);
onModified = StreamQueue(pollingService.onModified);
onRemoved = StreamQueue(pollingService.onRemoved);
created = await store.create({
'id': '0',
'text': 'Clean your room',
'completed': false,
});
});
tearDown(() {
onCreated.cancel();
onModified.cancel();
onRemoved.cancel();
client.close();
});
group('events', () {
test('fires indexed', () async {
var indexed = await pollingService.index();
print(indexed);
expect(await pollingService.onIndexed.first, indexed);
});
test('fires created', () async {
var result = await onCreated.next;
print(result);
expect(created, result);
});
test('fires modified', () async {
await pollingService.index();
await store.modify('0', {
'text': 'go to school',
});
var result = await onModified.next;
print(result);
expect(result, Map.from({'': created})..['text'] = 'go to school');
});
test('manual modify', () async {
await pollingService.index();
await pollingService.modify('0', {
'text': 'eat',
});
var result = await onModified.next;
print(result);
expect(result, Map.from({'': created})..['text'] = 'eat');
});
test('fires removed', () async {
await pollingService.index();
var removed = await store.remove('0');
var result = await onRemoved.next;
print(result);
expect(result, removed);
});
});
}

Binary file not shown.

View file

@ -1,93 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.buildlog
.packages
.project
.pub/
.scripts-bin/
build/
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
doc/api/
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
pubspec.lock
### Dart template
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
# SDK 1.20 and later (no longer creates packages directories)
# Older SDK versions
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
# Directory created by dartdoc
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
### 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
# 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
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

View file

@ -1 +0,0 @@
language: dart

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,9 +0,0 @@
# Change Log
## 2.0.0
* Migrated to support Dart >= 2.12 NNBD
## 1.0.0
* Initial checkin

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,25 +0,0 @@
# relations
[![version 1.0.1](https://img.shields.io/badge/pub-v1.0.1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_relations)
[![build status](https://travis-ci.org/angel-dart/relations.svg)](https://travis-ci.org/angel-dart/relations)
Database-agnostic relations between Angel services.
```dart
// Authors owning one book
app.service('authors').afterAll(
relations.hasOne('books', as: 'book', foreignKey: 'authorId'));
// Or multiple
app.service('authors').afterAll(
relations.hasMany('books', foreignKey: 'authorId'));
// Or, books belonging to authors
app.service('books').afterAll(relations.belongsTo('authors'));
```
Supports:
* `hasOne`
* `hasMany`
* `hasManyThrough`
* `belongsTo`
* `belongsToMany`

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,9 +0,0 @@
/// Hooks to populate data returned from services, in a fashion
/// reminiscent of a relational database.
library angel_relations;
export 'src/belongs_to_many.dart';
export 'src/belongs_to.dart';
export 'src/has_many.dart';
export 'src/has_many_through.dart';
export 'src/has_one.dart';

View file

@ -1,75 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
/// Represents a relationship in which the current [service] "belongs to"
/// a single member of the service at [servicePath]. Use [as] to set the name
/// on the target object.
///
/// Defaults:
/// * [localKey]: `userId`
/// * [foreignKey]: `id`
HookedServiceEventListener belongsTo(Pattern servicePath,
{String? as,
String? foreignKey,
String? localKey,
Function(dynamic obj)? getForeignKey,
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
var localId = localKey;
var foreignName =
as?.isNotEmpty == true ? as! : pluralize.singular(servicePath.toString());
localId ??= foreignName + 'Id';
return (HookedServiceEvent e) async {
var ref = e.getService(servicePath);
if (ref == null) throw noService(servicePath);
dynamic _getForeignKey(obj) {
if (getForeignKey != null) {
return getForeignKey(obj);
} else if (obj is Map) {
return obj[localId];
} else if (localId == null || localId == 'userId') {
return obj.userId;
} else {
return reflect(obj).getField(Symbol(localId)).reflectee;
}
}
dynamic _assignForeignObject(foreign, obj) {
if (assignForeignObject != null) {
return assignForeignObject(foreign, obj);
} else if (obj is Map) {
obj[foreignName] = foreign;
} else {
reflect(obj).setField(Symbol(foreignName), foreign);
}
}
Future _normalize(obj) async {
if (obj != null) {
var id = await _getForeignKey(obj);
var indexed = await ref.index({
'query': {foreignKey ?? 'id': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObject(null, obj);
} else {
var child = indexed.first;
await _assignForeignObject(child, obj);
}
}
}
if (e.result is Iterable) {
//await Future.wait(e.result.map(_normalize));
await e.result.map(_normalize);
} else {
await _normalize(e.result);
}
};
}

View file

@ -1,75 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
/// Represents a relationship in which the current [service] "belongs to"
/// multiple members of the service at [servicePath]. Use [as] to set the name
/// on the target object.
///
/// Defaults:
/// * [foreignKey]: `userId`
/// * [localKey]: `id`
HookedServiceEventListener belongsToMany(Pattern servicePath,
{String? as,
String? foreignKey,
String? localKey,
Function(dynamic obj)? getForeignKey,
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
var localId = localKey;
var foreignName =
as?.isNotEmpty == true ? as! : pluralize.plural(servicePath.toString());
localId ??= foreignName + 'Id';
return (HookedServiceEvent e) async {
var ref = e.getService(servicePath);
if (ref == null) throw noService(servicePath);
dynamic _getForeignKey(obj) {
if (getForeignKey != null) {
return getForeignKey(obj);
} else if (obj is Map) {
return obj[localId];
} else if (localId == null || localId == 'userId') {
return obj.userId;
} else {
return reflect(obj).getField(Symbol(localId)).reflectee;
}
}
dynamic _assignForeignObject(foreign, obj) {
if (assignForeignObject != null) {
return assignForeignObject(foreign as List?, obj);
} else if (obj is Map) {
obj[foreignName] = foreign;
} else {
reflect(obj).setField(Symbol(foreignName), foreign);
}
}
Future<void> _normalize(obj) async {
if (obj != null) {
var id = await _getForeignKey(obj);
var indexed = await ref.index({
'query': {foreignKey ?? 'id': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObject(null, obj);
} else {
var child = indexed is Iterable ? indexed.toList() : [indexed];
await _assignForeignObject(child, obj);
}
}
}
if (e.result is Iterable) {
//await Future.wait(e.result.map(_normalize));
await e.result.map(_normalize);
} else {
await _normalize(e.result);
}
};
}

View file

@ -1,70 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
/// Represents a relationship in which the current [service] "owns"
/// members of the service at [servicePath]. Use [as] to set the name
/// on the target object.
///
/// Defaults:
/// * [foreignKey]: `userId`
/// * [localKey]: `id`
HookedServiceEventListener hasMany(Pattern servicePath,
{String? as,
String? foreignKey,
String? localKey,
Function(dynamic obj)? getLocalKey,
Function(dynamic foreign, dynamic obj)? assignForeignObjects}) {
return (HookedServiceEvent e) async {
var ref = e.getService(servicePath);
var foreignName =
as?.isNotEmpty == true ? as : pluralize.plural(servicePath.toString());
if (ref == null) throw noService(servicePath);
dynamic _getLocalKey(obj) {
if (getLocalKey != null) {
return getLocalKey(obj);
} else if (obj is Map) {
return obj[localKey ?? 'id'];
} else if (localKey == null || localKey == 'id') {
return obj.id;
} else {
return reflect(obj).getField(Symbol(localKey)).reflectee;
}
}
dynamic _assignForeignObjects(foreign, obj) {
if (assignForeignObjects != null) {
return assignForeignObjects(foreign, obj);
} else if (obj is Map) {
obj[foreignName] = foreign;
} else {
reflect(obj).setField(Symbol(foreignName!), foreign);
}
}
Future _normalize(obj) async {
if (obj != null) {
var id = await _getLocalKey(obj);
var indexed = await ref.index({
'query': {foreignKey ?? 'userId': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObjects([], obj);
} else {
await _assignForeignObjects(indexed, obj);
}
}
}
if (e.result is Iterable) {
//await Future.wait(e.result.map(_normalize));
await e.result.map(_normalize);
} else {
await _normalize(e.result);
}
};
}

View file

@ -1,97 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
HookedServiceEventListener hasManyThrough(String servicePath, String pivotPath,
{String? as,
String? localKey,
String? pivotKey,
String? foreignKey,
Function(dynamic obj)? getLocalKey,
Function(dynamic obj)? getPivotKey,
Function(dynamic obj)? getForeignKey,
Function(dynamic foreign, dynamic obj)? assignForeignObjects}) {
var foreignName =
as?.isNotEmpty == true ? as : pluralize.plural(servicePath.toString());
return (HookedServiceEvent e) async {
var pivotService = e.getService(pivotPath);
var foreignService = e.getService(servicePath);
if (pivotService == null) {
throw noService(pivotPath);
} else if (foreignService == null) throw noService(servicePath);
dynamic _assignForeignObjects(foreign, obj) {
if (assignForeignObjects != null) {
return assignForeignObjects(foreign, obj);
} else if (obj is Map) {
obj[foreignName] = foreign;
} else {
reflect(obj).setField(Symbol(foreignName!), foreign);
}
}
dynamic _getLocalKey(obj) {
if (getLocalKey != null) {
return getLocalKey(obj);
} else if (obj is Map) {
return obj[localKey ?? 'id'];
} else if (localKey == null || localKey == 'id') {
return obj.id;
} else {
return reflect(obj).getField(Symbol(localKey)).reflectee;
}
}
dynamic _getPivotKey(obj) {
if (getPivotKey != null) {
return getPivotKey(obj);
} else if (obj is Map) {
return obj[pivotKey ?? 'id'];
} else if (pivotKey == null || pivotKey == 'id') {
return obj.id;
} else {
return reflect(obj).getField(Symbol(pivotKey)).reflectee;
}
}
Future _normalize(obj) async {
// First, resolve pivot
var id = await _getLocalKey(obj);
var indexed = await pivotService.index({
'query': {pivotKey ?? 'userId': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObjects([], obj);
} else {
// Now, resolve from foreign service
var mapped = await Future.wait(indexed.map((pivot) async {
var id = await _getPivotKey(obj);
var indexed = await foreignService.index({
'query': {foreignKey ?? 'postId': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObjects([], pivot);
} else {
await _assignForeignObjects(indexed, pivot);
}
return pivot;
}));
await _assignForeignObjects(mapped, obj);
}
}
if (e.result is Iterable) {
//await Future.wait(e.result.map(_normalize));
await e.result.map(_normalize);
} else {
await _normalize(e.result);
}
};
}

View file

@ -1,73 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
/// Represents a relationship in which the current [service] "owns"
/// a single member of the service at [servicePath]. Use [as] to set the name
/// on the target object.
///
/// Defaults:
/// * [foreignKey]: `userId`
/// * [localKey]: `id`
HookedServiceEventListener hasOne(Pattern servicePath,
{String? as,
String? foreignKey,
String? localKey,
Function(dynamic obj)? getLocalKey,
Function(dynamic foreign, dynamic obj)? assignForeignObject}) {
return (HookedServiceEvent e) async {
var ref = e.getService(servicePath);
var foreignName = as?.isNotEmpty == true
? as
: pluralize.singular(servicePath.toString());
if (ref == null) throw noService(servicePath);
dynamic _getLocalKey(obj) {
if (getLocalKey != null) {
return getLocalKey(obj);
} else if (obj is Map) {
return obj[localKey ?? 'id'];
} else if (localKey == null || localKey == 'id') {
return obj.id;
} else {
return reflect(obj).getField(Symbol(localKey)).reflectee;
}
}
dynamic _assignForeignObject(foreign, obj) {
if (assignForeignObject != null) {
return assignForeignObject(foreign, obj);
} else if (obj is Map) {
obj[foreignName] = foreign;
} else {
reflect(obj).setField(Symbol(foreignName!), foreign);
}
}
Future _normalize(obj) async {
if (obj != null) {
var id = await _getLocalKey(obj);
var indexed = await ref.index({
'query': {foreignKey ?? 'userId': id}
});
if (indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObject(null, obj);
} else {
var child = indexed.first;
await _assignForeignObject(child, obj);
}
}
}
if (e.result is Iterable) {
//await Future.wait(e.result.map(_normalize));
await e.result.map(_normalize);
} else {
await _normalize(e.result);
}
};
}

View file

@ -1,2 +0,0 @@
ArgumentError noService(Pattern path) =>
ArgumentError("No service exists at path '$path'.");

View file

@ -1,23 +0,0 @@
String singular(String path) {
var str = path.trim().split('/').where((str) => str.isNotEmpty).last;
if (str.endsWith('ies')) {
return str.substring(0, str.length - 3) + 'y';
} else if (str.endsWith('s')) {
return str.substring(0, str.length - 1);
} else {
return str;
}
}
String plural(String path) {
var str = path.trim().split('/').where((str) => str.isNotEmpty).last;
if (str.endsWith('y')) {
return str.substring(0, str.length - 1) + 'ies';
} else if (str.endsWith('s')) {
return str;
} else {
return str + 's';
}
}

View file

@ -1,21 +0,0 @@
name: angel_relations
version: 2.0.0
description: Database-agnostic relations between Angel services.
homepage: "https://github.com/angel-dart/relations.git"
publish_to: none
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
angel_framework:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/framework
dev_dependencies:
angel_seeder:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/seeder
test: ^1.17.8
lints: ^1.0.0

View file

@ -1,54 +0,0 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_seeder/angel_seeder.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
late Angel app;
setUp(() async {
app = Angel()..use('/authors', MapService())..use('/books', MapService());
await app.configure(seed(
'authors',
SeederConfiguration<Map>(
count: 10,
template: {'name': (Faker faker) => faker.person.name()},
callback: (Map author, seed) {
return seed(
'books',
SeederConfiguration(delete: false, count: 10, template: {
'authorId': author['id'],
'title': (Faker faker) =>
'I love to eat ${faker.food.dish()}'
}));
})));
// TODO: Missing method afterAll
//app.findService ('books').afterAll(relations.belongsTo('authors'));
});
test('index', () async {
var books = await app.findService('books')!.index();
print(books);
expect(books, allOf(isList, isNotEmpty));
for (var book in books.whereType<Map>()) {
expect(book.keys, contains('author'));
var author = book['author'] as Map;
expect(author['id'], equals(book['authorId']));
}
});
test('create', () async {
var warAndPeace = await app
.findService('books')!
.create(Book(title: 'War and Peace').toJson());
print(warAndPeace);
expect(warAndPeace.keys, contains('author'));
expect(warAndPeace['author'], isNull);
});
}

View file

@ -1,69 +0,0 @@
import 'dart:convert';
import 'package:angel_framework/angel_framework.dart';
//import 'package:json_god/json_god.dart' as god;
@deprecated
class CustomMapService extends Service {
final List<Map> _items = [];
Iterable<Map> tailor(Iterable<Map> items, Map? params) {
if (params == null) return items;
var r = items;
if (params['query'] is Map) {
var query = params['query'] as Map;
for (var key in query.keys) {
r = r.where((m) => m[key] == query[key]);
}
}
return r;
}
@override
Future<List<Map>> index([params]) async => tailor(_items, params).toList();
@override
Future<Map> read(id, [Map? params]) async {
return tailor(_items, params).firstWhere((m) => m['id'] == id,
orElse: (() => throw AngelHttpException.notFound()));
}
@override
Future<Map> create(data, [params]) async {
var d = data is Map ? data : (jsonDecode(data as String) as Map?)!;
d['id'] = _items.length.toString();
_items.add(d);
return d;
}
@override
Future remove(id, [params]) async {
if (id == null) _items.clear();
}
}
class Author {
String? id, name;
Author({this.id, this.name});
Map toJson() => {'id': id, 'name': name};
}
class Book {
String? authorId, title;
Book({this.authorId, this.title});
Map toJson() => {'authorId': authorId, 'title': title};
}
class Chapter {
String? bookId, title;
int? pageCount;
Chapter({this.bookId, this.title, this.pageCount});
}

View file

@ -1,60 +0,0 @@
import 'package:angel_framework/angel_framework.dart';
//import 'package:angel_relations/angel_relations.dart' as relations;
import 'package:angel_seeder/angel_seeder.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
late Angel app;
setUp(() async {
app = Angel()..use('/authors', MapService())..use('/books', MapService());
await app.configure(seed(
'authors',
SeederConfiguration<Map>(
count: 10,
template: {'name': (Faker faker) => faker.person.name()},
callback: (Map author, seed) {
return seed(
'books',
SeederConfiguration(delete: false, count: 10, template: {
'authorId': author['id'],
'title': (Faker faker) =>
'I love to eat ${faker.food.dish()}'
}));
})));
// TODO: Missing afterAll method
// app
// .findService('authors')
// .afterAll(relations.hasMany('books', foreignKey: 'authorId'));
});
test('index', () async {
var authors = await app.findService('authors')!.index();
print(authors);
expect(authors, allOf(isList, isNotEmpty));
for (var author in authors.whereType<Map>()) {
expect(author.keys, contains('books'));
var books = author['books'] as List<Map>;
for (var book in books) {
expect(book['authorId'], equals(author['id']));
}
}
});
test('create', () async {
var tolstoy = await app
.findService('authors')!
.create(Author(name: 'Leo Tolstoy').toJson());
print(tolstoy);
expect(tolstoy.keys, contains('books'));
expect(tolstoy['books'], allOf(isList, isEmpty));
});
}

View file

@ -1,57 +0,0 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_seeder/angel_seeder.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
late Angel app;
setUp(() async {
app = Angel()..use('/authors', MapService())..use('/books', MapService());
await app.configure(seed(
'authors',
SeederConfiguration<Map>(
count: 10,
template: {'name': (Faker faker) => faker.person.name()},
callback: (Map author, seed) {
return seed(
'books',
SeederConfiguration(delete: false, count: 10, template: {
'authorId': author['id'],
'title': (Faker faker) =>
'I love to eat ${faker.food.dish()}'
}));
})));
// TODO: Missing afterAll method
// app.findService('authors').afterAll(
// relations.hasOne('books', as: 'book', foreignKey: 'authorId'));
});
test('index', () async {
var authors = await app.findService('authors')!.index();
print(authors);
expect(authors, allOf(isList, isNotEmpty));
for (var author in authors.whereType<Map>()) {
expect(author.keys, contains('book'));
var book = author['book'] as Map;
print('Author: $author');
print('Book: $book');
expect(book['authorId'], equals(author['id']));
}
});
test('create', () async {
var tolstoy = await app
.findService('authors')!
.create(Author(name: 'Leo Tolstoy').toJson());
print(tolstoy);
expect(tolstoy.keys, contains('book'));
expect(tolstoy['book'], isNull);
});
}

Binary file not shown.

View file

@ -1,31 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.buildlog
.packages
.project
.pub/
build/
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
doc/api/
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
pubspec.lock
rethinkdb_data/
.idea
.dart_tool

View file

@ -1,4 +0,0 @@
language: dart
addons:
rethinkdb: '2.3'
before_script: 'dart test/bootstrap.dart'

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,10 +0,0 @@
# Change Log
## 2.0.0
* Migrated to support Dart >= 2.12 NNBD
## 1.1.0
* Moved to `package:rethinkdb_driver`
* Fixed references to old hooked event names

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,87 +0,0 @@
# rethink
[![version 1.0.7](https://img.shields.io/badge/pub-1.0.7-brightgreen.svg)](https://pub.dartlang.org/packages/angel_rethink)
[![build status](https://travis-ci.org/angel-dart/rethink.svg?branch=master)](https://travis-ci.org/angel-dart/rethink)
RethinkDB-enabled services for the Angel framework.
# Installation
Add the following to your `pubspec.yaml`:
```yaml
dependencies:
angel_rethink: ^1.0.0
```
`package:rethinkdb_driver2` will be installed as well.
# Usage
This library exposes one class: `RethinkService`. By default, these services will even
listen to [changefeeds](https://www.rethinkdb.com/docs/changefeeds/ruby/) from the database,
which makes them very suitable for WebSocket use.
However, only `CREATED`, `UPDATED` and `REMOVED` events will be fired. This is technically not
a problem, as it lowers the numbers of events you have to handle on the client side. ;)
## Model
`Model` is class with no real functionality; however, it represents a basic document, and your services should host inherited classes.
Other Angel service providers host `Model` as well, so you will easily be able to modify your application if you ever switch databases.
```dart
class User extends Model {
String username;
String password;
}
main() async {
var r = new RethinkDb();
var conn = await r.connect();
app.use('/api/users', new RethinkService(conn, r.table('users')));
// Add type de/serialization if you want
app.use('/api/users', new TypedService<User>(new RethinkService(conn, r.table('users'))));
// You don't have to even use a table...
app.use('/api/pro_users', new RethinkService(conn, r.table('users').filter({'membership': 'pro'})));
app.service('api/users').afterCreated.listen((event) {
print("New user: ${event.result}");
});
}
```
## RethinkService
This class interacts with a `Query` (usually a table) and serializes data to and from Maps.
## RethinkTypedService<T>
Does the same as above, but serializes to and from a target class using `package:json_god` and its support for reflection.
## Querying
You can query these services as follows:
/path/to/service?foo=bar
The above will query the database to find records where 'foo' equals 'bar'.
The former will sort result in ascending order of creation, and so will the latter.
You can use advanced queries:
```dart
// Pass an actual query...
service.index({'query': r.table('foo').filter(...)});
// Or, a function that creates a query from a table...
service.index({'query': (table) => table.getAll('foo')});
// Or, a Map, which will be transformed into a `filter` query:
service.index({'query': {'foo': 'bar', 'baz': 'quux'}});
```
You can also apply sorting by adding a `reql` parameter on the server-side.
```dart
service.index({'reql': (query) => query.sort(...)});
```
See the tests for more usage examples.

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1 +0,0 @@
export 'src/rethink_service.dart';

View file

@ -1,251 +0,0 @@
import 'dart:async';
//import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:json_god/json_god.dart' as god;
import 'package:rethinkdb_dart/rethinkdb_dart.dart';
// Extends a RethinkDB query.
typedef QueryCallback = RqlQuery Function(RqlQuery query);
/// Queries a single RethinkDB table or query.
class RethinkService extends Service {
/// If set to `true`, clients can remove all items by passing a `null` `id` to `remove`.
///
/// `false` by default.
final bool allowRemoveAll;
/// If set to `true`, parameters in `req.query` are applied to the database query.
final bool allowQuery;
final bool debug;
/// If set to `true`, then a HookedService mounted over this instance
/// will fire events when RethinkDB pushes events.
///
/// Good for scaling. ;)
final bool listenForChanges;
final Connection connection;
/// Doesn't actually have to be a table, just a RethinkDB query.
///
/// However, a table is the most common usecase.
final RqlQuery table;
RethinkService(this.connection, this.table,
{this.allowRemoveAll = false,
this.allowQuery = true,
this.debug = false,
this.listenForChanges = true})
: super();
RqlQuery buildQuery(RqlQuery initialQuery, Map params) {
if (params != null) {
params['broadcast'] = params.containsKey('broadcast')
? params['broadcast']
: (listenForChanges != true);
}
var q = _getQueryInner(initialQuery, params);
if (params?.containsKey('reql') == true &&
params['reql'] is QueryCallback) {
q = params['reql'](q) as RqlQuery;
}
return q ?? initialQuery;
}
RqlQuery _getQueryInner(RqlQuery query, Map params) {
if (params == null || !params.containsKey('query')) {
return query;
} else {
if (params['query'] is RqlQuery) {
return params['query'] as RqlQuery;
} else if (params['query'] is QueryCallback) {
return params['query'](table) as RqlQuery;
} else if (params['query'] is! Map || allowQuery != true) {
return query;
} else {
var q = params['query'] as Map;
return q.keys.fold<RqlQuery>(query, (out, key) {
var val = q[key];
if (val is RequestContext ||
val is ResponseContext ||
key == 'provider' ||
val is Providers) {
return out;
} else {
return out.filter({key.toString(): val});
}
});
}
}
}
Future _sendQuery(RqlQuery query) async {
var result = await query.run(connection);
if (result is Cursor) {
return await result.toList();
} else if (result is Map && result['generated_keys'] is List) {
if (result['generated_keys'].length == 1) {
return await read(result['generated_keys'].first);
}
//return await Future.wait(result['generated_keys'].map(read));
return await result['generated_keys'].map(read);
} else {
return result;
}
}
dynamic _serialize(data) {
if (data is Map) {
return data;
} else if (data is Iterable) {
return data.map(_serialize).toList();
} else {
return god.serializeObject(data);
}
}
dynamic _squeeze(data) {
if (data is Map) {
return data.keys.fold<Map>({}, (map, k) => map..[k.toString()] = data[k]);
} else if (data is Iterable) {
return data.map(_squeeze).toList();
} else {
return data;
}
}
@override
void onHooked(HookedService hookedService) {
if (listenForChanges == true) {
listenToQuery(table, hookedService);
}
}
Future listenToQuery(RqlQuery query, HookedService hookedService) async {
var feed =
await query.changes({'include_types': true}).run(connection) as Feed;
feed.listen((Map event) {
var type = event['type']?.toString();
var newVal = event['new_val'], oldVal = event['old_val'];
if (type == 'add') {
// Create
hookedService.fireEvent(
hookedService.afterCreated,
HookedServiceEvent(
true, null, null, this, HookedServiceEvent.created,
result: newVal));
} else if (type == 'change') {
// Update
hookedService.fireEvent(
hookedService.afterCreated,
HookedServiceEvent(
true, null, null, this, HookedServiceEvent.updated,
result: newVal, id: oldVal['id'], data: newVal));
} else if (type == 'remove') {
// Remove
hookedService.fireEvent(
hookedService.afterCreated,
HookedServiceEvent(
true, null, null, this, HookedServiceEvent.removed,
result: oldVal, id: oldVal['id']));
}
});
}
// TODO: Invalid override method
/*
@override
Future index([Map params]) async {
var query = buildQuery(table, params);
return await _sendQuery(query);
}
*/
@override
Future read(id, [Map params]) async {
var query = buildQuery(table.get(id?.toString()), params);
var found = await _sendQuery(query);
//print('Found for $id: $found');
if (found == null) {
throw AngelHttpException.notFound(message: 'No record found for ID $id');
} else {
return found;
}
}
@override
Future create(data, [Map params]) async {
if (table is! Table) throw AngelHttpException.methodNotAllowed();
var d = _serialize(data);
var q = table as Table;
var query = buildQuery(q.insert(_squeeze(d)), params);
return await _sendQuery(query);
}
@override
Future modify(id, data, [Map params]) async {
var d = _serialize(data);
if (d is Map && d.containsKey('id')) {
try {
await read(d['id'], params);
} on AngelHttpException catch (e) {
if (e.statusCode == 404) {
return await create(data, params);
} else {
rethrow;
}
}
}
var query = buildQuery(table.get(id?.toString()), params).update(d);
await _sendQuery(query);
return await read(id, params);
}
@override
Future update(id, data, [Map params]) async {
var d = _serialize(data);
if (d is Map && d.containsKey('id')) {
try {
await read(d['id'], params);
} on AngelHttpException catch (e) {
if (e.statusCode == 404) {
return await create(data, params);
} else {
rethrow;
}
}
}
if (d is Map && !d.containsKey('id')) d['id'] = id.toString();
var query = buildQuery(table.get(id?.toString()), params).replace(d);
await _sendQuery(query);
return await read(id, params);
}
@override
Future remove(id, [Map params]) async {
if (id == null ||
id == 'null' &&
(allowRemoveAll == true ||
params?.containsKey('provider') != true)) {
return await _sendQuery(table.delete());
} else {
var prior = await read(id, params);
var query = buildQuery(table.get(id), params).delete();
await _sendQuery(query);
return prior;
}
}
}

View file

@ -1,35 +0,0 @@
name: angel_rethink
version: 2.0.0
description: RethinkDB-enabled services for the Angel framework.
publish_to: none
environment:
sdk: ">=2.10.0 <3.0.0"
homepage: https://github.com/angel-dart/rethink
dependencies:
angel_framework:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/framework
json_god:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/json_god
rethinkdb_dart: ^2.3.2+6
dev_dependencies:
angel_client:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/client
angel_test:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/test
logging: ^1.0.0
test: ^1.15.7
lints: ^1.0.0
dependency_overrides:
crypto: ^3.0.0

View file

@ -1,6 +0,0 @@
# Tests
The tests expect you to have installed RethinkDB. You must have a `test` database
available, and a server ready at the default port.
Also, the tests expect a table named `todos`.

View file

@ -1,11 +0,0 @@
import 'dart:io';
import 'package:rethinkdb_dart/rethinkdb_dart.dart';
void main() async {
var r = Rethinkdb();
await r.connect().then((conn) {
r.tableCreate('todos').run(conn);
print('Done');
exit(0);
});
}

View file

@ -1,10 +0,0 @@
class Todo {
String title;
bool completed;
Todo({this.title, this.completed = false});
Map toJson() {
return {'title': title, 'completed': completed == true};
}
}

View file

@ -1,85 +0,0 @@
import 'package:angel_client/angel_client.dart' as c;
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_rethink/angel_rethink.dart';
import 'package:angel_test/angel_test.dart';
import 'package:logging/logging.dart';
import 'package:rethinkdb_dart/rethinkdb_dart.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
Angel app;
TestClient client;
Rethinkdb r;
c.Service todoService;
setUp(() async {
r = Rethinkdb();
var conn = await r.connect();
app = Angel();
app.use('/todos', RethinkService(conn, r.table('todos')));
app.errorHandler = (e, req, res) async {
print('Whoops: $e');
};
app.logger = Logger.detached('angel')..onRecord.listen(print);
client = await connectTo(app);
todoService = client.service('todos');
});
tearDown(() => client.close());
test('index', () async {
var result = await todoService.index();
print('Response: $result');
expect(result, isList);
});
test('create+read', () async {
var todo = Todo(title: 'Clean your room');
var creation = await todoService.create(todo.toJson());
print('Creation: $creation');
var id = creation['id'];
var result = await todoService.read(id);
print('Response: $result');
expect(result, isMap);
expect(result['id'], equals(id));
expect(result['title'], equals(todo.title));
expect(result['completed'], equals(todo.completed));
});
test('modify', () async {
var todo = Todo(title: 'Clean your room');
var creation = await todoService.create(todo.toJson());
print('Creation: $creation');
var id = creation['id'];
var result = await todoService.modify(id, {'title': 'Eat healthy'});
print('Response: $result');
expect(result, isMap);
expect(result['id'], equals(id));
expect(result['title'], equals('Eat healthy'));
expect(result['completed'], equals(todo.completed));
});
test('remove', () async {
var todo = Todo(title: 'Clean your room');
var creation = await todoService.create(todo.toJson());
print('Creation: $creation');
var id = creation['id'];
var result = await todoService.remove(id);
print('Response: $result');
expect(result, isMap);
expect(result['id'], equals(id));
expect(result['title'], equals(todo.title));
expect(result['completed'], equals(todo.completed));
});
}

Binary file not shown.

View file

@ -1,27 +0,0 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.buildlog
.packages
.project
.pub/
build/
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
doc/api/
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
pubspec.lock

View file

@ -1 +0,0 @@
language: dart

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,9 +0,0 @@
# Change Log
## 2.0.0
* Migrated to support Dart >= 2.12 NNBD
## 1.0.0
* Initial checkin

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,25 +0,0 @@
# angel_seeder
[![version 1.0.](https://img.shields.io/pub/v/angel_seeder.svg)](https://pub.dartlang.org/packages/angel_seeder)
[![build status](https://travis-ci.org/angel-dart/seeder.svg?branch=master)](https://travis-ci.org/angel-dart/seeder)
Straightforward data seeder for Angel services.
This is an almost exact port of [feathers-seeder](https://github.com/thosakwe/feathers-seeder),
so its documentation should almost exactly match up here.
Fortunately, I was also the one who made `feathers-seeder`, so if you ever need assistance,
file an issue.
# Example
```dart
var app = new Angel()..use('/todos', new TodoService());
await app.configure(seed(
'todos',
new SeederConfiguration<Todo>(delete: false, count: 10, template: {
'text': (Faker faker) => 'Clean your room, ${faker.person.name()}!',
'completed': false
})));
```
**NOTE**: Don't *await* seeding at application startup; that's too slow.
Instead, run it asynchronously.

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,141 +0,0 @@
import 'dart:math';
import 'package:angel_framework/angel_framework.dart';
import 'package:faker/faker.dart';
export 'package:faker/faker.dart';
/// Generates data using a [Faker].
typedef FakerCallback = Function(Faker faker);
/// Used to seed nested objects.
typedef SeederCallback<T> = Function(T created,
Function(Pattern path, SeederConfiguration configuration, {bool? verbose}));
/// Seeds the given service in development.
AngelConfigurer seed<T>(
Pattern servicePath,
SeederConfiguration<T> configuration, {
bool verbose = false,
}) {
return (Angel app) async {
if (configuration.runInProduction != true) return;
if (!app.services.containsKey(servicePath)) {
throw ArgumentError(
"App does not contain a service at path '$servicePath'.");
}
if (configuration.disabled == true) {
print("Service '$servicePath' will not be seeded.");
return;
}
var service = app.findService(servicePath);
var faker = Faker();
Map _buildTemplate(Map data) {
return data.keys.fold({}, (map, key) {
var value = data[key];
if (value is FakerCallback) {
return map..[key] = value(faker);
} else if (value is Function) {
return map..[key] = value();
} else if (value is Map) {
return map..[key] = _buildTemplate(value);
} else {
return map..[key] = value;
}
});
}
Future<Null> Function(SeederConfiguration configuration) _buildSeeder(
Service? service,
{bool? verbose}) {
return (SeederConfiguration configuration) async {
if (configuration.delete == true) await service!.remove(null);
var count = configuration.count;
var rnd = Random();
if (count < 1) count = 1;
for (var i = 0; i < count; i++) {
Future _gen(template) async {
var data = template;
if (data is Map) {
data = _buildTemplate(data);
} else if (data is Faker) {
data = template(faker);
}
var params = <String, dynamic>{}..addAll(configuration.params);
var result = await service!.create(data, params);
if (configuration.callback != null) {
await configuration.callback!(result,
(Pattern path, SeederConfiguration configuration,
{bool? verbose}) {
return _buildSeeder(app.findService(path),
verbose: verbose == true)(configuration);
});
}
}
if (configuration.template != null) {
await _gen(configuration.template);
} else if (configuration.templates.isNotEmpty == true) {
var template = configuration.templates
.elementAt(rnd.nextInt(configuration.templates.length));
await _gen(template);
} else {
throw ArgumentError(
'Configuration for service \'$servicePath\' must define at least one template.');
}
}
if (verbose == true) {
print('Created $count object(s) in service \'$servicePath\'.');
}
};
}
await _buildSeeder(service, verbose: verbose == true)(configuration);
};
}
/// Configures the seeder.
class SeederConfiguration<T> {
/// Optional callback on creation.
final SeederCallback<T>? callback;
/// Number of objects to seed.
final int count;
/// If `true`, all records in the service are deleted before seeding.
final bool delete;
/// If `true`, seeding will not occur.
final bool disabled;
/// Optional service parameters to be passed.
final Map<String, dynamic> params;
/// Unless this is `true`, the seeder will not run in production.
final bool runInProduction;
/// A data template to build from.
final template;
/// A set of templates to choose from.
final Iterable templates;
SeederConfiguration(
{this.callback,
this.count = 1,
this.delete = true,
this.disabled = false,
this.params = const {},
this.runInProduction = false,
this.template,
this.templates = const []});
}

View file

@ -1,17 +0,0 @@
name: angel_seeder
version: 2.0.0
description: Straightforward data seeder for Angel services.
publish_to: none
environment:
sdk: '>=2.12.0 <3.0.0'
homepage: https://github.com/angel-dart/seeder
dependencies:
angel_framework:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/framework
faker: ^2.0.0
dev_dependencies:
test: ^1.17.8
lints: ^1.0.0

View file

@ -1,69 +0,0 @@
import 'dart:async';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_container/mirrors.dart';
import 'package:angel_seeder/angel_seeder.dart';
import 'package:test/test.dart';
void main() {
test('create one', () async {
var app = Angel(reflector: MirrorsReflector())
..use('/todos', TodoService());
await app.configure(seed(
'todos',
SeederConfiguration<Todo>(delete: false, count: 10, template: {
'text': (Faker faker) => 'Clean your room, ${faker.person.name()}!',
'completed': false
})));
var todos = await app.findService('todos')!.index();
print('Todos: \n${todos.map((todo) => " - $todo").join("\n")}');
expect(todos, isList);
expect(todos, hasLength(10));
});
}
class TodoService extends Service {
final List<Todo> todos = [];
@override
Future<List<Todo>> index([params]) => myData();
Future<List<Todo>> myData() {
var completer = Completer<List<Todo>>();
completer.complete(todos);
return completer.future;
}
@override
Future<Object> create(data, [params]) async {
if (data is Todo) {
todos.add(data..id = todos.length.toString());
return data;
} else if (data is Map) {
todos.add(Todo.fromJson(data)..id = todos.length.toString());
return data;
} else {
throw AngelHttpException.badRequest();
}
}
}
class Todo extends Model {
final String? text;
final bool? completed;
Todo({String? id, this.text, this.completed = false}) {
this.id = id;
}
factory Todo.fromJson(Map data) => Todo(
id: data['id'] as String?,
text: data['text'] as String?,
completed: data['completed'] as bool?);
@override
String toString() => '${completed! ? "Complete" : "Incomplete"}: $text';
}

Binary file not shown.

View file

@ -1,13 +0,0 @@
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.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/

View file

@ -1,12 +0,0 @@
Primary Authors
===============
* __[Thomas Hii](dukefirehawk.apps@gmail.com)__
Thomas is the current maintainer of the code base. He has refactored and migrated the
code base to support NNBD.
* __[Tobe O](thosakwe@gmail.com)__
Tobe has written much of the original code prior to NNBD migration. He has moved on and
is no longer involved with the project.

View file

@ -1,16 +0,0 @@
# Change Log
## 2.0.0
* Migrated to support Dart >= 2.12 NNBD
## 1.0.1
* Explicitly extend `Service<Id, T>`.
* Override `readData`.
* Use `Service<Id, Map<String, dynamic>>` for `inner`, instead of just
`Service<Id, Map>`.
## 1.0.0
* Initial version.

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,29 +0,0 @@
# typed_service
Angel services that use reflection (via mirrors or codegen) to (de)serialize PODO's.
Useful for quick prototypes.
Typically, [`package:angel_serialize`](https://github.com/angel-dart/serialize)
is recommended.
## Brief Example
```dart
main() async {
var app = Angel();
var http = AngelHttp(app);
var service = TypedService<String, Todo>(MapService());
hierarchicalLoggingEnabled = true;
app.use('/api/todos', service);
app
..serializer = god.serialize
..logger = Logger.detached('typed_service')
..logger.onRecord.listen((rec) {
print(rec);
if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace);
});
await http.startServer('127.0.0.1', 3000);
print('Listening at ${http.uri}');
}
```

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,5 +0,0 @@
Command:
```bash
curl -X POST -d '@example/data.json' -H 'content-type: application/json' http://localhost:3000/api/todos; echo
```

View file

@ -1,22 +0,0 @@
[
{
"id": "0",
"createdAt": null,
"updatedAt": null,
"idAsInt": null,
"text": "Yes",
"completed": false,
"created_at": "2019-04-26T09:51:27.494884",
"updated_at": "2019-04-26T09:51:27.494884"
},
{
"id": "1",
"createdAt": null,
"updatedAt": null,
"idAsInt": null,
"text": "nOPE",
"completed": false,
"created_at": "2019-04-26T09:51:37.847741",
"updated_at": "2019-04-26T09:51:37.847741"
}
]

View file

@ -1,42 +0,0 @@
import 'dart:io';
import 'package:angel_file_service/angel_file_service.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_typed_service/angel_typed_service.dart';
import 'package:file/local.dart';
import 'package:json_god/json_god.dart' as god;
import 'package:logging/logging.dart';
void main() async {
var app = Angel();
var http = AngelHttp(app);
var fs = LocalFileSystem();
var exampleDir = fs.file(Platform.script).parent;
var dataJson = exampleDir.childFile('data.json');
var service = TypedService<String, Todo>(JsonFileService(dataJson));
hierarchicalLoggingEnabled = true;
app.use('/api/todos', service);
app
..serializer = god.serialize
..logger = Logger.detached('typed_service')
..logger!.onRecord.listen((rec) {
print(rec);
if (rec.error != null) print(rec.error);
if (rec.stackTrace != null) print(rec.stackTrace);
});
await http.startServer('127.0.0.1', 3000);
print('Listening at ${http.uri}');
}
class Todo extends Model {
String? text;
bool? completed;
@override
DateTime? createdAt, updatedAt;
Todo({String? id, this.text, this.completed, this.createdAt, this.updatedAt})
: super(id: id);
}

View file

@ -1,100 +0,0 @@
import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'package:json_god/json_god.dart' as god;
/// An Angel service that uses reflection to (de)serialize Dart objects.
class TypedService<Id, T> extends Service<Id, T?> {
/// The inner service.
final Service<Id, Map<String, dynamic>> inner;
TypedService(this.inner) : super() {
if (!reflectType(T).isAssignableTo(reflectType(Model))) {
throw Exception(
'If you specify a type for TypedService, it must extend Model.');
}
}
@override
FutureOr<T>? Function(RequestContext, ResponseContext) get readData =>
_readData;
T? _readData(RequestContext req, ResponseContext res) =>
deserialize(req.bodyAsMap);
/// Attempts to deserialize [x] into an instance of [T].
T? deserialize(x) {
// print('DESERIALIZE: $x (${x.runtimeType})');
if (x is T) {
return x;
} else if (x is Map) {
var data = x.keys.fold({}, (dynamic map, key) {
var value = x[key];
if ((key == 'createdAt' ||
key == 'updatedAt' ||
key == 'created_at' ||
key == 'updated_at') &&
value is String) {
return map..[key] = DateTime.parse(value);
} else {
return map..[key] = value;
}
});
var result = god.deserializeDatum(data, outputType: T);
if (data['createdAt'] is DateTime) {
result.createdAt = data['createdAt'] as DateTime?;
} else if (data['created_at'] is DateTime) {
result.createdAt = data['created_at'] as DateTime?;
}
if (data['updatedAt'] is DateTime) {
result.updatedAt = data['updatedAt'] as DateTime?;
} else if (data['updated_at'] is DateTime) {
result.updatedAt = data['updated_at'] as DateTime?;
}
// print('x: $x\nresult: $result');
return result as T?;
} else {
throw ArgumentError('Cannot convert $x to $T');
}
}
/// Serializes [x] into a [Map].
Map<String, dynamic> serialize(x) {
if (x is Model) {
return (god.serializeObject(x) as Map).cast<String, dynamic>();
} else if (x is Map) {
return x.cast<String, dynamic>();
} else {
throw ArgumentError('Cannot serialize ${x.runtimeType}');
}
}
@override
Future<List<T?>> index([Map<String, dynamic>? params]) =>
inner.index(params).then((it) => it.map(deserialize).toList());
@override
Future<T> create(data, [Map<String, dynamic>? params]) =>
inner.create(serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
@override
Future<T> read(Id id, [Map<String, dynamic>? params]) =>
inner.read(id, params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
@override
Future<T> modify(Id id, T? data, [Map<String, dynamic>? params]) =>
inner.modify(id, serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
@override
Future<T> update(Id id, T? data, [Map<String, dynamic>? params]) =>
inner.update(id, serialize(data), params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
@override
Future<T> remove(Id id, [Map<String, dynamic>? params]) =>
inner.remove(id, params).then(deserialize as FutureOr<T> Function(Map<String, dynamic>));
}

View file

@ -1,29 +0,0 @@
name: angel_typed_service
version: 2.0.0
description: Angel services that use reflection to (de)serialize Dart objects.
homepage: https://github.com/angel-dart/typed_service
publish_to: none
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
angel_framework:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/framework
json_god:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/json_god
dev_dependencies:
angel_file_service:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/file_service
file: ^6.0.0
logging: ^1.0.0
lints: ^1.0.0
test: ^1.15.7

View file

@ -1,57 +0,0 @@
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_typed_service/angel_typed_service.dart';
import 'package:test/test.dart';
void main() {
var svc = TypedService<String?, Todo>(MapService());
test('force model', () {
expect(() => TypedService<String?, int>(MapService()), throwsException);
});
test('serialize', () {
expect(svc.serialize({'foo': 'bar'}), {'foo': 'bar'});
expect(() => svc.serialize(2), throwsArgumentError);
var now = DateTime.now();
var t = Todo(
id: '3', text: 'a', completed: false, createdAt: now, updatedAt: now);
var m = svc.serialize(t);
print(m);
expect(m..remove('_identityHashCode')..remove('idAsInt'), {
'id': '3',
'createdAt': now.toIso8601String(),
'updatedAt': now.toIso8601String(),
'text': 'a',
'completed': false
});
});
test('deserialize date', () {
var now = DateTime.now();
var m = svc.deserialize({
'createdAt': now.toIso8601String(),
'updatedAt': now.toIso8601String()
})!;
expect(m, const TypeMatcher<Todo>());
expect(m.createdAt!.millisecondsSinceEpoch, now.millisecondsSinceEpoch);
});
test('deserialize date w/ underscore', () {
var now = DateTime.now();
var m = svc.deserialize({
'created_at': now.toIso8601String(),
'updated_at': now.toIso8601String()
})!;
expect(m, const TypeMatcher<Todo>());
expect(m.createdAt!.millisecondsSinceEpoch, now.millisecondsSinceEpoch);
});
}
class Todo extends Model {
String? text;
bool? completed;
@override
DateTime? createdAt, updatedAt;
Todo({String? id, this.text, this.completed, this.createdAt, this.updatedAt})
: super(id: id);
}

BIN
archived_packages/wings.zip Normal file

Binary file not shown.

View file

@ -1,121 +0,0 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
...

View file

@ -1,67 +0,0 @@
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
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/
# Avoid committing generated Javascript files:
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map
*.o
# *.dylib
*.a
# *.so
*.lib
*.obj
.vscode/
.idea/
# Created by https://www.gitignore.io/api/cmake
# Edit at https://www.gitignore.io/?templates=cmake
### CMake ###
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
### CMake Patch ###
# External projects
*-prefix/
# End of https://www.gitignore.io/api/cmake
# Created by https://www.gitignore.io/api/vagrant
# Edit at https://www.gitignore.io/?templates=vagrant
### Vagrant ###
# General
.vagrant/
# Log files (if you are creating logs in debug mode, uncomment this)
# *.log
### Vagrant Patch ###
*.box
# End of https://www.gitignore.io/api/vagrant

View file

@ -1,6 +0,0 @@
[submodule "cmake_dart_utils"]
path = cmake_dart_utils
url = https://github.com/thosakwe/cmake_dart_utils.git
[submodule "lib/src/http-parser"]
path = lib/src/http-parser
url = https://github.com/nodejs/http-parser.git

View file

@ -1,6 +0,0 @@
cmake_minimum_required(VERSION 3.0)
project(angel_wings)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_dart_utils/cmake")
find_package(Dart REQUIRED)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(lib/src)

View file

@ -1,29 +0,0 @@
BSD 3-Clause License
Copyright (c) 2021, dukefirehawk.com
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,51 +0,0 @@
# wings
Native HTTP driver for Angel, for a nice speed boost.
Not ready for production.
## How does it work?
Typically, Angel uses the `AngelHttp` driver, which is wrapper over the `HttpServer` functionality in
`dart:io`, which in turns uses the `ServerSocket` and `Socket` functionality. This is great - Dart's standard
library comes with an HTTP server, which saves a lot of difficult in implementation.
However, abstraction tends to come with a cost. Wings seeks to minimize abstraction entirely. Rather than
using the built-in Dart network stack, Wings' HTTP server is implemented in C++ as a Dart native extension,
and the `AngelWings` driver listens to events from the extension and converts them directly into
`RequestContext` objects, without any additional abstraction within. This reduces the amount of computation
performed on each request, and helps to minimize response latency. Sending data from the response buffer in plain
Dart surprisingly is the most expensive operation, as is revealed by the Observatory.
By combining Dart's powerful VM with a native code server based on
[the same one used in Node.js](https://github.com/nodejs/http-parser),
`AngelWings` trims several milliseconds off every request, both saving resources and reducing
load times for high-traffic applications.
## How can I use it?
The intended way to use `AngelWings` is via
[`package:build_native`](https://github.com/thosakwe/build_native);
however, the situation surrounding distributing native extensions is yet far from ideal,
so this package includes pre-built binaries out-of-the-box.
Thanks to this, you can use it like any other Dart package, by installing it via Pub.
## Brief example
Using `AngelWings` is almost identical to using `AngelHttp`; however, it does
not support SSL, and therefore should be placed behind a reverse proxy like `nginx` in production.
```dart
main() async {
var app = new Angel();
var wings = new AngelWings(app, shared: true, useZone: false);
app.injectEncoders({'gzip': gzip.encoder, 'deflate': zlib.encoder});
app.get('/hello', 'Hello, native world! This is Angel WINGS.');
var fs = const LocalFileSystem();
var vDir = new VirtualDirectory(app, fs, source: fs.directory('web'));
app.use(vDir.handleRequest);
await wings.startServer('127.0.0.1', 3000);
print('Listening at http://${wings.address.address}:${wings.port}');
}
```

View file

@ -1,6 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/bionic64"
config.vm.provision "shell", path: "provision.sh"
end

View file

@ -1 +0,0 @@
include: package:lints/recommended.yaml

View file

@ -1,23 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'util.dart';
const AngelBenchmark emptyBenchmark = _EmptyBenchmark();
void main() => runBenchmarks([emptyBenchmark]);
class _EmptyBenchmark implements AngelBenchmark {
const _EmptyBenchmark();
@override
String get name => 'empty';
@override
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res) {
return res.close();
}
@override
void setupAngel(Angel app) {}
}

View file

@ -1,112 +0,0 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_wings/angel_wings.dart';
import 'package:io/ansi.dart';
import 'package:tuple/tuple.dart';
Future<Process> _runWrk(
{ProcessStartMode mode = ProcessStartMode.inheritStdio}) async {
return await Process.start('wrk', ['http://localhost:$testPort'], mode: mode);
}
Future<void> _warmUp() async {
var wrk = await _runWrk();
await wrk.exitCode;
// await wrk.stderr.drain();
// await wrk.stdout.drain();
}
Future _10s() => Future.delayed(Duration(seconds: 10));
const testPort = 8877;
Future<void> runBenchmarks(Iterable<AngelBenchmark> benchmarks,
{Iterable<String> factories = const [
// 'angel_http',
'angel_wings',
]}) async {
for (var benchmark in benchmarks) {
print(magenta.wrap('Entering benchmark: ${benchmark.name}'));
// // Run dart:io
// print(lightGray.wrap('Booting dart:io server (waiting 10s)...'));
// var isolates = <Isolate>[];
// for (int i = 0; i < Platform.numberOfProcessors; i++) {
// isolates.add(await Isolate.spawn(_httpIsolate, benchmark));
// }
// await _10s();
// print(lightGray.wrap('Warming up dart:io server...'));
// await _warmUp();
// stdout
// ..write(lightGray.wrap('Now running `wrk` for '))
// ..write(cyan.wrap(benchmark.name))
// ..writeln(lightGray.wrap(' (waiting 10s)...'));
// var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
// await wrk.exitCode;
// isolates.forEach((i) => i.kill(priority: Isolate.immediate));
// Run Angel HTTP, Wings
for (var fac in factories) {
print(lightGray.wrap('Booting $fac server...'));
var isolates = <Isolate>[];
for (var i = 0; i < Platform.numberOfProcessors; i++) {
isolates
.add(await Isolate.spawn(_angelIsolate, Tuple2(benchmark, fac)));
}
await _10s();
print(lightGray.wrap('Warming up $fac server...'));
await _warmUp();
stdout
..write(lightGray.wrap('Now running `wrk` for '))
..write(cyan.wrap(benchmark.name))
..writeln(lightGray.wrap('...'));
var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
await wrk.exitCode;
}
}
exit(0);
}
/*
void _httpIsolate(AngelBenchmark benchmark) {
Future(() async {
var raw = await HttpServer.bind(InternetAddress.loopbackIPv4, testPort,
shared: true);
raw.listen((r) => benchmark.rawHandler(r, r.response));
});
}
*/
void _angelIsolate(Tuple2<AngelBenchmark, String> args) {
Future(() async {
var app = Angel();
late Driver driver;
if (args.item2 == 'angel_http') {
driver = AngelHttp.custom(app, startShared);
} else if (args.item2 == 'angel_wings') {
driver = AngelWings.custom(app, startSharedWings);
}
await app.configure(args.item1.setupAngel);
await driver.startServer(InternetAddress.loopbackIPv4, testPort);
});
}
abstract class AngelBenchmark {
const AngelBenchmark();
String get name;
FutureOr<void> setupAngel(Angel app);
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res);
}

View file

@ -1,34 +0,0 @@
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_static/angel_static.dart';
import 'package:angel_wings/angel_wings.dart';
import 'package:file/local.dart';
import 'package:logging/logging.dart';
import 'package:pretty_logging/pretty_logging.dart';
void main() async {
hierarchicalLoggingEnabled = true;
var logger = Logger.detached('wings')
..level = Level.ALL
..onRecord.listen(prettyLog);
var app = Angel(logger: logger);
var wings = AngelWings(app);
var fs = LocalFileSystem();
var vDir = CachingVirtualDirectory(app, fs,
source: fs.currentDirectory, allowDirectoryListing: true);
app.mimeTypeResolver.addExtension('yaml', 'text/x-yaml');
app.get('/', (req, res) => 'WINGS!!!');
app.post('/', (req, res) async {
await req.parseBody();
return req.bodyAsMap;
});
app.fallback(vDir.handleRequest);
app.fallback((req, res) => throw AngelHttpException.notFound());
await wings.startServer(InternetAddress.loopbackIPv4, 3000);
print('Listening at ${wings.uri}');
}

Some files were not shown because too many files have changed in this diff Show more