1.0.0-dev!

This commit is contained in:
regiostech 2016-06-21 18:56:04 -04:00
parent 267b696150
commit 80c6118544
15 changed files with 60 additions and 39 deletions

View file

@ -1,2 +1,5 @@
# angel_framework
Documentation in the works.
![version 1.0.0-dev](https://img.shields.io/badge/version-1.0.0--dev-red.svg)
Core libraries for the Angel Framework.

View file

@ -1,4 +1,4 @@
/// A controller-based MVC + WebSocket framework in Dart.
/// An easily-extensible web server framework in Dart.
library angel_framework;
export 'src/http/http.dart';

View file

@ -1,8 +1,11 @@
part of angel_framework.http;
class _AngelHttpExceptionBase implements Exception {
/// An HTTP status code this exception will throw.
int statusCode;
/// The cause of this exception.
String message;
/// A list of errors that occurred when this exception was thrown.
List<String> errors;
_AngelHttpExceptionBase.base() {}

View file

@ -1,6 +1,6 @@
part of angel_framework.http;
/// Basically an Expando whoops
/// Supports accessing members of a Map as though they were actual members.
class Extensible {
/// A set of custom properties that can be assigned to the server.
///

View file

@ -1,13 +1,13 @@
part of angel_framework.http;
/// Maps the given middleware(s) onto this handler.
/// Annotation to map middleware onto a handler.
class Middleware {
final List handlers;
const Middleware(List this.handlers);
}
/// This service will send an event after every action.
/// Annotation to set a service up to release hooks on every action.
class Hooked {
const Hooked();
}

View file

@ -1,15 +1,13 @@
part of angel_framework.http;
/// A function that asynchronously generates a view from the given path and data.
typedef Future<String> ViewGenerator(String path, {Map data});
typedef Future<String> ViewGenerator(String path, [Map data]);
/// A convenience wrapper around an outgoing HTTP request.
class ResponseContext extends Extensible {
/// The [Angel] instance that is sending a response.
Angel app;
God god = new God();
/// Can we still write to this response?
bool isOpen = true;

View file

@ -1,10 +1,16 @@
part of angel_framework.http;
/// Represents an endpoint open for connection via the Internet.
class Route {
/// A regular expression used to match URI's to this route.
RegExp matcher;
/// The HTTP method this route responds to.
String method;
/// An array of functions, Futures and objects that can respond to this route.
List handlers = [];
/// The path this route is mounted on.
String path;
/// (Optional) - A name for this route.
String name;
Route(String method, Pattern path, [List handlers]) {
@ -35,6 +41,7 @@ class Route {
return this;
}
/// Generates a URI to this route with the given parameters.
String makeUri([Map<String, dynamic> params]) {
String result = path;
if (params != null) {
@ -46,6 +53,7 @@ class Route {
return result;
}
/// Enables one or more handlers to be called whenever this route is visited.
Route middleware(handler) {
if (handler is Iterable)
handlers.addAll(handler);
@ -53,7 +61,8 @@ class Route {
return this;
}
parseParameters(String requestPath) {
/// Extracts route parameters from a given path.
Map parseParameters(String requestPath) {
Map result = {};
Iterable<String> values = _parseParameters(requestPath);

View file

@ -16,7 +16,7 @@ class Angel extends Routable {
(address, port) async => await HttpServer.bind(address, port);
/// Default error handler, show HTML error page
var _errorHandler = (AngelHttpException e, req, ResponseContext res) {
AngelErrorHandler _errorHandler = (AngelHttpException e, req, ResponseContext res) {
res.header(HttpHeaders.CONTENT_TYPE, ContentType.HTML.toString());
res.status(e.statusCode);
res.write("<DOCTYPE html><html><head><title>${e.message}</title>");
@ -28,8 +28,10 @@ class Angel extends Routable {
res.end();
};
var viewGenerator =
(String view, [Map data]) => "No view engine has been configured yet.";
/// A function that renders views.
///
/// Called by [ResponseContext]@`render`.
ViewGenerator viewGenerator = (String view, [Map data]) async => "No view engine has been configured yet.";
/// [RequestMiddleware] to be run before all requests.
List before = [];
@ -37,8 +39,12 @@ class Angel extends Routable {
/// [RequestMiddleware] to be run after all requests.
List after = [];
/// The native HttpServer running this instancce.
HttpServer httpServer;
/// Starts the server.
///
/// Returns false on failure; otherwise, returns the HttpServer.
startServer(InternetAddress address, int port) async {
var server =
await _serverGenerator(address ?? InternetAddress.LOOPBACK_IP_V4, port);
@ -193,7 +199,8 @@ class Angel extends Routable {
hooked: hooked, middlewareNamespace: middlewareNamespace);
}
onError(handler) {
/// Registers a callback to run upon errors.
onError(AngelErrorHandler handler) {
_errorHandler = handler;
}

View file

@ -1,16 +1,28 @@
part of angel_framework.http;
/// Indicates how the service was accessed.
///
/// This will be passed to the `params` object in a service method.
/// When requested on the server side, this will be null.
class Providers {
/// The transport through which the client is accessing this service.
final String via;
const Providers._base(String this.via);
const Providers(String this.via);
static final Providers SERVER = const Providers._base('server_side');
static final Providers REST = const Providers._base('rest');
static final Providers WEBSOCKET = const Providers._base('websocket');
static const String VIA_REST = "rest";
static const String VIA_WEBSOCKET = "websocket";
/// Represents a request via REST.
static final Providers REST = const Providers(VIA_REST);
/// Represents a request over WebSockets.
static final Providers WEBSOCKET = const Providers(VIA_WEBSOCKET);
}
/// A data store exposed to the Internet.
/// A front-facing interface that can present data to and operate on data on behalf of the user.
///
/// Heavily inspired by FeathersJS. <3
class Service extends Routable {
/// The [Angel] app powering this service.
Angel app;

View file

@ -2,6 +2,7 @@ part of angel_framework.http;
/// Wraps another service in a service that broadcasts events on actions.
class HookedService extends Service {
/// Tbe service that is proxied by this hooked one.
final Service inner;
HookedServiceEventDispatcher beforeIndexed =

View file

@ -2,12 +2,11 @@ part of angel_framework.http;
/// An in-memory [Service].
class MemoryService<T> extends Service {
God god = new God();
Map <int, T> items = {};
_makeJson(int index, T t) {
if (T == null || T == Map)
return mergeMap([god.serializeToMap(t), {'id': index}]);
return mergeMap([god.serializeObject(t), {'id': index}]);
else
return t;
}
@ -32,7 +31,7 @@ class MemoryService<T> extends Service {
Future create(data, [Map params]) async {
//try {
print("Data: $data");
var created = (data is Map) ? god.deserializeFromMap(data, T) : data;
var created = (data is Map) ? god.deserializeDatum(data, outputType: T) : data;
print("Created $created");
items[items.length] = created;
return _makeJson(items.length - 1, created);
@ -45,10 +44,10 @@ class MemoryService<T> extends Service {
int desiredId = int.parse(id.toString());
if (items.containsKey(desiredId)) {
try {
Map existing = god.serializeToMap(items[desiredId]);
Map existing = god.serializeObject(items[desiredId]);
data = mergeMap([existing, data]);
items[desiredId] =
(data is Map) ? god.deserializeFromMap(data, T) : data;
(data is Map) ? god.deserializeDatum(data, outputType: T) : data;
return _makeJson(desiredId, items[desiredId]);
} catch (e) {
throw new AngelHttpException.BadRequest(message: 'Invalid data.');
@ -61,7 +60,7 @@ class MemoryService<T> extends Service {
if (items.containsKey(desiredId)) {
try {
items[desiredId] =
(data is Map) ? god.deserializeFromMap(data, T) : data;
(data is Map) ? god.deserializeDatum(data, outputType: T) : data;
return _makeJson(desiredId, items[desiredId]);
} catch (e) {
throw new AngelHttpException.BadRequest(message: 'Invalid data.');

View file

@ -1,5 +1,5 @@
name: angel_framework
version: 0.0.0-dev.19
version: 1.0.0-dev
description: Core libraries for the Angel framework.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_framework

View file

@ -1,7 +1,6 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart';
import 'package:json_god/json_god.dart' as god;
import 'package:test/test.dart';
class Todo {
@ -18,13 +17,11 @@ main() {
Angel app;
String url;
http.Client client;
God god;
HookedService Todos;
setUp(() async {
app = new Angel();
client = new http.Client();
god = new God();
app.use('/todos', new MemoryService<Todo>());
Todos = app.service("todos");
@ -37,7 +34,6 @@ main() {
url = null;
client.close();
client = null;
god = null;
Todos = null;
});

View file

@ -1,7 +1,7 @@
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart';
import 'package:json_god/json_god.dart' as god;
import 'package:test/test.dart';
@Middleware(const ['interceptor'])
@ -16,10 +16,8 @@ main() {
Angel todos;
String url;
http.Client client;
God god;
setUp(() async {
god = new God();
angel = new Angel();
nested = new Angel();
todos = new Angel();
@ -58,7 +56,6 @@ main() {
client.close();
client = null;
url = null;
god = null;
});
test('Can match basic url', () async {

View file

@ -1,7 +1,6 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'package:http/http.dart' as http;
import 'package:json_god/json_god.dart';
import 'package:json_god/json_god.dart' as god;
import 'package:test/test.dart';
class Todo {
@ -18,12 +17,10 @@ main() {
Angel app;
String url;
http.Client client;
God god;
setUp(() async {
app = new Angel();
client = new http.Client();
god = new God();
Service todos = new MemoryService<Todo>();
app.use('/todos', todos);
print(app.service("todos"));
@ -36,7 +33,6 @@ main() {
url = null;
client.close();
client = null;
god = null;
});
group('memory', () {