diff --git a/.gitignore b/.gitignore
index 0e47c8a9..d88b0dfb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,3 +87,4 @@ fabric.properties
logs/
*.pem
.DS_Store
+server_log.txt
diff --git a/.idea/angel.iml b/.idea/angel.iml
index d218f651..377564ba 100644
--- a/.idea/angel.iml
+++ b/.idea/angel.iml
@@ -4,20 +4,12 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Multi_Threaded_Server__PRODUCTION_.xml b/.idea/runConfigurations/Multi_Threaded_Server__PRODUCTION_.xml
deleted file mode 100644
index af4caad5..00000000
--- a/.idea/runConfigurations/Multi_Threaded_Server__PRODUCTION_.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Start_Server.xml b/.idea/runConfigurations/Start_Server.xml
deleted file mode 100644
index 10afb537..00000000
--- a/.idea/runConfigurations/Start_Server.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Start_Server__PRODUCTION_.xml b/.idea/runConfigurations/Start_Server__PRODUCTION_.xml
deleted file mode 100644
index 688eed83..00000000
--- a/.idea/runConfigurations/Start_Server__PRODUCTION_.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/Users_Tests.xml b/.idea/runConfigurations/Users_Tests.xml
deleted file mode 100644
index a5f788b5..00000000
--- a/.idea/runConfigurations/Users_Tests.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations/dev_dart.xml b/.idea/runConfigurations/dev_dart.xml
new file mode 100644
index 00000000..418187ff
--- /dev/null
+++ b/.idea/runConfigurations/dev_dart.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/Load_Balanced_Server__PRODUCTION_.xml b/.idea/runConfigurations/prod_dart.xml
similarity index 51%
rename from .idea/runConfigurations/Load_Balanced_Server__PRODUCTION_.xml
rename to .idea/runConfigurations/prod_dart.xml
index d6a3e0f0..e93c56a5 100644
--- a/.idea/runConfigurations/Load_Balanced_Server__PRODUCTION_.xml
+++ b/.idea/runConfigurations/prod_dart.xml
@@ -1,10 +1,10 @@
-
+
-
+
diff --git a/README.md b/README.md
index 370966cc..9b7ddb79 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
[![The Angel Framework](https://angel-dart.github.io/images/logo.png)](https://angel-dart.github.io)
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angel_dart/discussion)
-[![version: v1.0.0](https://img.shields.io/badge/pub-v1.0.0-brightgreen.svg)](https://pub.dartlang.org/packages/angel_common)
+[![Pub](https://img.shields.io/pub/v/angel_framework.svg)](https://pub.dartlang.org/packages/angel_framework)
**Fill out the [v1.0.0 survey](https://docs.google.com/forms/d/e/1FAIpQLSfEgBNsOoi_nYZMmg2IAGyMv1nNaa6B3kUk3QdNJU5987ucVA/viewform?usp=sf_link) now!!!**
@@ -46,7 +46,7 @@ angel init hello
You can even have your server run and be *live-reloaded* on file changes:
```bash
-dart bin/server.dart
+dart bin/dev.dart
```
Next, check out the [detailed documentation](https://github.com/angel-dart/angel/wiki) to learn to flesh out your project.
@@ -60,57 +60,4 @@ With features like the following, Angel is the all-in-one framework you should c
* And [much more](https://github.com/angel-dart)...
## Basic Example
-More examples and complete projects can be found in the [angel-example](https://github.com/angel-example) organization.
-
-The following is an [explosive application](https://github.com/angel-example/explode) complete with a REST API and
-WebSocket support. It interacts with a MongoDB database, and reads configuration automatically from a `config/.yaml` file. Templates are rendered with Mustache, and all responses are compressed via GZIP.
-
-**All in just about 20 lines of actual code.**
-
-```dart
-import 'dart:async';
-import 'package:angel_common/angel_common.dart';
-import 'package:angel_websocket/server.dart';
-import 'package:mongo_dart/mongo_dart.dart';
-
-main() async {
- var app = await createServer();
- var server = await app.startServer(InternetAddress.LOOPBACK_IP_V4, 8080);
- print('Angel listening at http://${server.address.address}:${server.port}');
-}
-
-Future createServer() async {
- // New instance...
- var app = new Angel();
-
- // Configuration
- await app.configure(loadConfigurationFile());
- await app.configure(mustache());
- Db db = new Db();
- await db.open(app.mongodb_url);
- app.container.singleton(db); // Add to DI
-
- // Routes
- app.get('/foo', (req, res) => res.render('hello'));
-
- app.post('/query', (Db db) async {
- // Db is an injected dependency here :)
- return await db.collection('foo').find().toList();
- });
-
- // Services (which build REST API's and are broadcasted over WS)
- app.use('/bombs', new MongoService(db.collection('bombs')));
- app.use('/users', new MongoService(db.collection('users')));
- app.use('/explosions', new AnonymousService(create: (data, [params]) => data));
-
-
- // Setup WebSockets, add GZIP, etc.
- await app.configure(new AngelWebSocket());
- app.responseFinalizers.add(gzip());
-
- return app;
-}
-```
-
-## Get Social
-Join an activate chat about the Angel Framework, or seek assistance: https://gitter.im/angel_dart/discussion
+Examples and complete projects can be found in the [angel-example](https://github.com/angel-example) organization.
\ No newline at end of file
diff --git a/.analysis-options b/analysis_options.yaml
similarity index 100%
rename from .analysis-options
rename to analysis_options.yaml
diff --git a/bin/cluster.dart b/bin/cluster.dart
deleted file mode 100644
index 14090b89..00000000
--- a/bin/cluster.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-/// This should be used with `multiserver` as an entry
-/// point for `spawnIsolates`.
-library angel.cluster;
-
-import 'dart:async';
-import 'common.dart';
-import 'dart:isolate';
-
-main(args, SendPort sendPort) async {
- runZoned(startServer(args, sendPort: sendPort), onError: onError);
-}
diff --git a/bin/common.dart b/bin/common.dart
deleted file mode 100644
index 87f1135e..00000000
--- a/bin/common.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-import 'dart:io';
-import 'dart:isolate';
-import 'package:angel/angel.dart';
-import 'package:angel_diagnostics/angel_diagnostics.dart';
-import 'package:angel_hot/angel_hot.dart';
-import 'package:intl/intl.dart';
-
-/// Start a single instance of this application.
-///
-/// If a [sendPort] is provided, then the URL of the mounted server will be sent through the port.
-/// Use this if you are starting multiple instances of your server.
-startServer(args, {SendPort sendPort}) {
- return () async {
- var app = await createServer();
- var dateFormat = new DateFormat("y-MM-dd");
- var logFile = new File("logs/${dateFormat.format(new DateTime.now())}.txt");
- InternetAddress host;
- int port;
-
- // Load the right host and port from application config.
- host = new InternetAddress(app.properties['host']);
-
- // Listen on port 0 if we are using the load balancer.
- port = sendPort != null ? 0 : app.properties['port'];
-
- // Log requests and errors to a log file.
- await app.configure(logRequests(logFile));
- HttpServer server;
-
- // Use `package:angel_hot` in any case, EXCEPT if starting in production mode.
- //
- // With hot-reloading, our server will automatically reload in-place on file changes,
- // for a faster development cycle. :)
- if (Platform.environment['ANGEL_ENV'] == 'production')
- server = await app.startServer(host, port);
- else {
- var hot = new HotReloader(() async {
- // If we are hot-reloading, we need to provide a callback
- // to use to start a fresh instance on-the-fly.
- var app = await createServer();
- await app.configure(logRequests(logFile));
- return app;
- },
- // Paths we might want to listen for changes on...
- [
- new Directory('config'),
- new Directory('lib'),
- new Directory('views')
- ]);
- server = await hot.startServer(host, port);
- }
-
- if (sendPort == null) {
- print('Listening at http://${server.address.address}:${server.port}');
- } else
- sendPort?.send([server.address.address, server.port]);
- };
-}
-
-onError(error, [StackTrace stackTrace]) {
- stderr.writeln("Unhandled error occurred: $error");
- if (stackTrace != null) {
- stderr.writeln(stackTrace);
- }
-}
diff --git a/bin/dev.dart b/bin/dev.dart
new file mode 100644
index 00000000..fbf194a4
--- /dev/null
+++ b/bin/dev.dart
@@ -0,0 +1,27 @@
+import 'dart:io';
+import 'package:angel/angel.dart';
+import 'package:angel_framework/angel_framework.dart';
+import 'package:angel_hot/angel_hot.dart';
+import 'package:logging/logging.dart';
+
+main() async {
+ // Watch the config/ and web/ directories for changes, and hot-reload the server.
+ var hot = new HotReloader(() async {
+ var app = new Angel()..lazyParseBodies = true;
+ await app.configure(configureServer);
+ app.logger = new Logger('angel')..onRecord.listen((rec) {
+ print(rec);
+ if (rec.error != null) {
+ print(rec.error);
+ print(rec.stackTrace);
+ }
+ });
+ return app;
+ }, [
+ new Directory('config'),
+ new Directory('lib'),
+ ]);
+
+ var server = await hot.startServer('127.0.0.1', 3000);
+ print('Listening at http://${server.address.address}:${server.port}');
+}
diff --git a/bin/multi_server.dart b/bin/multi_server.dart
deleted file mode 100644
index a33a28e6..00000000
--- a/bin/multi_server.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env dart
-/// This is intended to replace Nginx in your web stack.
-/// Either use this or another reverse proxy, but there is no real
-/// reason to use them together.
-///
-/// In most cases, you should run `scaled_server.dart` instead of this file.
-library angel.multi_server;
-
-import 'dart:io';
-import 'package:angel_compress/angel_compress.dart';
-import 'package:angel_multiserver/angel_multiserver.dart';
-
-final Uri cluster = Platform.script.resolve('cluster.dart');
-
-/// The number of isolates to spawn. You might consider starting one instance
-/// per processor core on your machine.
-final int nInstances = Platform.numberOfProcessors;
-
-main() async {
- var app = new LoadBalancer();
- // Or, for SSL:
- // var app = new LoadBalancer.secure('', '');
-
- // Response compression!
- app.responseFinalizers.add(gzip());
-
- // Cache static assets - just to lower response time
- await app.configure(cacheResponses(filters: [new RegExp(r'images/.*')]));
-
- // Start up multiple instances of our main application.
- await app.spawnIsolates(cluster, count: nInstances);
-
- app.onCrash.listen((_) async {
- // Boot up a new instance on crash
- await app.spawnIsolates(cluster);
- });
-
- var host = InternetAddress.ANY_IP_V4;
- var port = 3000;
- var server = await app.startServer(host, port);
- print('Listening at http://${server.address.address}:${server.port}');
- print('Load-balancing $nInstances instance(s)');
-}
diff --git a/bin/prod.dart b/bin/prod.dart
new file mode 100644
index 00000000..67932550
--- /dev/null
+++ b/bin/prod.dart
@@ -0,0 +1,45 @@
+import 'dart:io';
+import 'dart:isolate';
+import 'package:angel/angel.dart';
+import 'package:angel_framework/angel_framework.dart';
+import 'package:logging/logging.dart';
+
+const String hostname = '127.0.0.1';
+const int port = 3000;
+
+void main() {
+ // Start a server instance in multiple isolates.
+
+ for (int id = 0; id < Platform.numberOfProcessors; id++)
+ Isolate.spawn(isolateMain, id);
+
+ isolateMain(Platform.numberOfProcessors);
+}
+
+void isolateMain(int id) {
+ // Passing `startShared` to the constructor allows us to start multiple
+ // instances of our application concurrently, listening on a single port.
+ //
+ // This effectively lets us multi-thread the application.
+ var app = new Angel.custom(startShared);
+
+ app.configure(configureServer).then((_) async {
+ // In production, we'll want to log errors to a file.
+ // Alternatives include sending logs to a service like Sentry.
+ app.logger = new Logger('angel')
+ ..onRecord.listen((rec) {
+ if (rec.error != null) {
+ var sink =
+ new File('server_log.txt').openWrite(mode: FileMode.APPEND);
+ sink
+ ..writeln(rec.error)
+ ..writeln(rec.stackTrace)
+ ..close();
+ }
+ });
+
+ var server = await app.startServer(hostname, port);
+ print(
+ 'Instance #$id listening at http://${server.address.address}:${server.port}');
+ });
+}
diff --git a/bin/scaled_server.dart b/bin/scaled_server.dart
deleted file mode 100644
index 6e93f221..00000000
--- a/bin/scaled_server.dart
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env dart
-
-/// Most Angel applications will not need to use the load balancer.
-/// Instead, you can start up a multi-threaded cluster.
-library angel.scaled_server;
-
-import 'dart:io';
-import 'dart:isolate';
-import 'package:angel_compress/angel_compress.dart';
-import 'package:angel_diagnostics/angel_diagnostics.dart';
-import 'package:angel_multiserver/angel_multiserver.dart';
-import 'package:angel/angel.dart';
-
-/// The number of isolates to spawn. You might consider starting one instance
-/// per processor core on your machine.
-final int nInstances = Platform.numberOfProcessors;
-
-main() {
- var startupPort = new ReceivePort();
- List startupMessages = [];
-
- // Start up multiple instances of our application.
- for (int i = 0; i < nInstances; i++) {
- Isolate.spawn(isolateMain, [i, startupPort.sendPort]);
- }
-
- int nStarted = 0;
-
- // Listen for notifications of application startup...
- startupPort.listen((String startupMessage) {
- startupMessages.add(startupMessage);
-
- if (++nStarted == nInstances) {
- // Keep track of how many instances successfully started up,
- // and print a success message when they all boot.
- startupMessages.forEach(print);
- print('Spawned $nInstances instance(s) of Angel.');
- }
- });
-}
-
-void isolateMain(List args) {
- int instanceId = args[0];
- SendPort startupPort = args[1];
-
- createServer().then((app) async {
- // Response compression via GZIP.
- //
- // See the documentation here:
- // https://github.com/angel-dart/compress
- app.responseFinalizers.add(gzip());
-
- // Cache static assets - just to lower response time.
- //
- // See the documentation here:
- // https://github.com/angel-dart/multiserver
- //
- // Here is an example of response caching:
- // https://github.com/angel-dart/multiserver/blob/master/example/cache.dart
- await app.configure(cacheResponses(filters: [new RegExp(r'images/.*')]));
-
- var server = await app.startServer(
- InternetAddress.ANY_IP_V4, app.properties['port'] ?? 3000);
-
- // Print request and error information to the console.
- await app.configure(logRequests());
-
- // Send a notification back to the main isolate
- startupPort.send('Instance #$instanceId listening at http://${server.address.address}:${server.port}');
- });
-}
diff --git a/bin/server.dart b/bin/server.dart
deleted file mode 100755
index 88a206c1..00000000
--- a/bin/server.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/env dart
-import 'dart:async';
-import 'common.dart';
-
-main(args) async {
- runZoned(startServer(args), onError: onError);
-}
diff --git a/lib/angel.dart b/lib/angel.dart
index 28668abc..e7183f50 100644
--- a/lib/angel.dart
+++ b/lib/angel.dart
@@ -2,23 +2,20 @@
library angel;
import 'dart:async';
-import 'package:angel_common/angel_common.dart';
+import 'package:angel_cors/angel_cors.dart';
+import 'package:angel_framework/angel_framework.dart';
+import 'package:file/local.dart';
import 'src/config/config.dart' as configuration;
import 'src/routes/routes.dart' as routes;
import 'src/services/services.dart' as services;
-/// Creates and configures the server instance.
-Future createServer() async {
- /// Passing `startShared` to the constructor allows us to start multiple
- /// instances of our application concurrently, listening on a single port.
- ///
- /// This effectively lets us multi-thread the application.
- var app = new Angel.custom(startShared);
+/// Configures the server instance.
+Future configureServer(Angel app) async {
+ // Enable CORS
+ app.use(cors());
- /// Set up our application, using three plug-ins defined with this project.
- await app.configure(configuration.configureServer);
+ // Set up our application, using the plug-ins defined with this project.
+ await app.configure(configuration.configureServer(const LocalFileSystem()));
await app.configure(services.configureServer);
- await app.configure(routes.configureServer);
-
- return app;
+ await app.configure(routes.configureServer(const LocalFileSystem()));
}
diff --git a/lib/src/config/config.dart b/lib/src/config/config.dart
index 810f40db..ba224a7b 100644
--- a/lib/src/config/config.dart
+++ b/lib/src/config/config.dart
@@ -1,29 +1,33 @@
/// Configuration for this Angel instance.
-library angel.config;
+library angel.src.config;
-import 'dart:io';
-import 'package:angel_common/angel_common.dart';
+import 'package:angel_configuration/angel_configuration.dart';
+import 'package:angel_framework/angel_framework.dart';
+import 'package:angel_jael/angel_jael.dart';
+import 'package:file/file.dart';
import 'plugins/plugins.dart' as plugins;
/// This is a perfect place to include configuration and load plug-ins.
-configureServer(Angel app) async {
- // Load configuration from the `config/` directory.
- //
- // See: https://github.com/angel-dart/configuration
- await app.configure(loadConfigurationFile());
+AngelConfigurer configureServer(FileSystem fileSystem) {
+ return (Angel app) async {
+ // Load configuration from the `config/` directory.
+ //
+ // See: https://github.com/angel-dart/configuration
+ await app.configure(configuration(fileSystem));
- // Configure our application to render Mustache templates from the `views/` directory.
- //
- // See: https://github.com/angel-dart/mustache
- await app.configure(mustache(new Directory('views')));
+ // Configure our application to render Jael templates from the `views/` directory.
+ //
+ // See: https://github.com/angel-dart/jael
+ await app.configure(jael(fileSystem.directory('views')));
- // Apply another plug-ins, i.e. ones that *you* have written.
- //
- // Typically, the plugins in `lib/src/config/plugins/plugins.dart` are plug-ins
- // that add functionality specific to your application.
- //
- // If you write a plug-in that you plan to use again, or are
- // using one created by the community, include it in
- // `lib/src/config/config.dart`.
- await plugins.configureServer(app);
+ // Apply another plug-ins, i.e. ones that *you* have written.
+ //
+ // Typically, the plugins in `lib/src/config/plugins/plugins.dart` are plug-ins
+ // that add functionality specific to your application.
+ //
+ // If you write a plug-in that you plan to use again, or are
+ // using one created by the community, include it in
+ // `lib/src/config/config.dart`.
+ await plugins.configureServer(app);
+ };
}
diff --git a/lib/src/config/plugins/plugins.dart b/lib/src/config/plugins/plugins.dart
index 30bd9caf..5d9673d3 100644
--- a/lib/src/config/plugins/plugins.dart
+++ b/lib/src/config/plugins/plugins.dart
@@ -1,8 +1,8 @@
/// Custom plugins go here.
-library angel.config.plugins;
+library angel.src.config.plugins;
import 'dart:async';
-import 'package:angel_common/angel_common.dart';
+import 'package:angel_framework/angel_framework.dart';
Future configureServer(Angel app) async {
// Include any plugins you have made here.
diff --git a/lib/src/models/models.dart b/lib/src/models/models.dart
deleted file mode 100644
index 45dd7d2c..00000000
--- a/lib/src/models/models.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-library angel.models;
-
-export 'user.dart';
\ No newline at end of file
diff --git a/lib/src/models/user.dart b/lib/src/models/user.dart
deleted file mode 100644
index 52f4e11d..00000000
--- a/lib/src/models/user.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-library angel.models.user;
-
-import 'package:angel_framework/common.dart';
-
-// Model classes in Angel, as a convention, should extend the `Model`
-// class.
-//
-// Angel doesn't box you into using a specific ORM. In fact, you might not
-// need one at all.
-//
-// The out-of-the-box configuration for Angel is to assume
-// all data you handle is a Map. You might consider leaving it this way, and just
-// (de)serializing data when you need typing support.
-//
-// If you use a `TypedService`, then Angel will perform (de)serialization for you automatically:
-// https://github.com/angel-dart/angel/wiki/TypedService
-//
-// You also have the option of using a source-generated serialization library.
-// Consider `package:owl` (not affiliated with Angel):
-// https://github.com/agilord/owl
-//
-// The `Model` class has no server-side dependency, and thus you can use it as-is, cross-platform.
-// This is good for full-stack applications, as you do not have to maintain duplicate class files. ;)
-
-class User extends Model {
- @override
- String id;
- String email, username, password, salt;
- @override
- DateTime createdAt, updatedAt;
-
- User(
- {this.id,
- this.email,
- this.username,
- this.password,
- this.salt,
- this.createdAt,
- this.updatedAt});
-}
diff --git a/lib/src/routes/controllers/auth.dart b/lib/src/routes/controllers/auth.dart
deleted file mode 100644
index 1ca5a970..00000000
--- a/lib/src/routes/controllers/auth.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-library angel.routes.controllers.auth;
-
-import 'package:angel_common/angel_common.dart';
-import '../../services/user.dart';
-
-/// Configures the application to authenticate users securely.
-/// See the documentation for controllers:
-///
-/// https://github.com/angel-dart/angel/wiki/Controllers
-@Expose('/auth')
-class AuthController extends Controller {
- /// Controls application authentication.
- ///
- /// See the documentation:
- /// * https://medium.com/the-angel-framework/logging-users-in-to-angel-applications-ccf32aba0dac
- /// * https://github.com/angel-dart/auth
- AngelAuth auth;
-
- /// Clients will see the result of `deserializer`, so let's pretend to be a client.
- ///
- /// Our User service is already wired to remove sensitive data from serialized JSON.
- deserializer(String id) async =>
- app.service('api/users').read(id, {'provider': Providers.REST});
-
- serializer(User user) async => user.id;
-
- /// Attempts to log a user in.
- LocalAuthVerifier localVerifier(Service userService) {
- return (String username, String password) async {
- Iterable users = await userService.index({
- 'query': {'username': username}
- });
-
- if (users.isNotEmpty) {
- return users.firstWhere((user) {
- var hash = hashPassword(password, user.salt, app.jwt_secret);
- return user.username == username && user.password == hash;
- }, orElse: () => null);
- }
- };
- }
-
- @override
- call(Angel app) async {
- // Wire up local authentication, connected to our User service
- auth = new AngelAuth(jwtKey: app.jwt_secret)
- ..serializer = serializer
- ..deserializer = deserializer
- ..strategies
- .add(new LocalAuthStrategy(localVerifier(app.service('api/users'))));
-
- await super.call(app);
- await app.configure(auth);
- }
-
- @Expose('/local', method: 'POST')
- login() => auth.authenticate('local');
-}
diff --git a/lib/src/routes/controllers/controllers.dart b/lib/src/routes/controllers/controllers.dart
index db68c444..e23b375b 100644
--- a/lib/src/routes/controllers/controllers.dart
+++ b/lib/src/routes/controllers/controllers.dart
@@ -1,9 +1,8 @@
-library angel.routes.controllers;
+library angel.src.routes.controllers;
-import 'package:angel_common/angel_common.dart';
-import 'auth.dart';
+import 'dart:async';
+import 'package:angel_framework/angel_framework.dart';
-configureServer(Angel app) async {
+Future configureServer(Angel app) async {
/// Controllers will not function unless wired to the application!
- await app.configure(new AuthController());
}
diff --git a/lib/src/routes/routes.dart b/lib/src/routes/routes.dart
index 3a80b033..bbdd8ad5 100644
--- a/lib/src/routes/routes.dart
+++ b/lib/src/routes/routes.dart
@@ -1,138 +1,55 @@
/// This app's route configuration.
-library angel.routes;
+library angel.src.routes;
-import 'dart:io';
-import 'package:angel_common/angel_common.dart';
+import 'package:angel_framework/angel_framework.dart';
+import 'package:angel_static/angel_static.dart';
+import 'package:file/file.dart';
import 'controllers/controllers.dart' as controllers;
-/// Adds global middleware to the application.
-///
-/// Use these to apply functionality to requests before business logic is run.
-///
-/// More on the request lifecycle:
-/// https://github.com/angel-dart/angel/wiki/Request-Lifecycle
-configureBefore(Angel app) async {
- app.before.add(cors());
-}
-
/// Put your app routes here!
///
/// See the wiki for information about routing, requests, and responses:
/// * https://github.com/angel-dart/angel/wiki/Basic-Routing
/// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses
-configureRoutes(Angel app) async {
- // Render `views/hello.mustache` when a user visits the application root.
- app.get('/', (req, ResponseContext res) => res.render('hello'));
-}
+AngelConfigurer configureServer(FileSystem fileSystem) {
+ return (Angel app) async {
+ // Typically, you want to mount controllers first, after any global middleware.
+ await app.configure(controllers.configureServer);
-/// Configures fallback middleware.
-///
-/// Use these to run generic actions on requests that were not terminated by
-/// earlier request handlers.
-///
-/// Note that these middleware might not always run.
-///
-/// More on the request lifecycle: https://github.com/angel-dart/angel/wiki/Request-Lifecycle
-configureAfter(Angel app) async {
- // Uncomment this to proxy over `pub serve` while in development.
- // This is a useful feature for full-stack applications, especially if you
- // are using Angular2.
- //
- // For documentation, see `package:angel_proxy`:
- // https://github.com/angel-dart/proxy
- //
- // await app.configure(new PubServeLayer());
+ // Render `views/hello.jl` when a user visits the application root.
+ app.get(
+ '/', (RequestContext req, ResponseContext res) => res.render('hello'));
- // Mount static server at /web or /build/web, depending on if
- // you are running in production mode. `Cache-Control` headers will also be enabled.
- //
- // Read the following two sources for documentation:
- // * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae
- // * https://github.com/angel-dart/static
- await app.configure(new CachingVirtualDirectory());
-
- // Set our application up to handle different errors.
- //
- // Read the following two sources for documentation:
- // * https://github.com/angel-dart/angel/wiki/Error-Handling
- // * https://github.com/angel-dart/errors
- var errors = new ErrorHandler(handlers: {
- // Display a 404 page if no resource is found.
- 404: (req, res) async =>
- res.render('error', {'message': 'No file exists at ${req.path}.'}),
-
- // On generic errors, give information about why the application failed.
+ // Mount static server at web in development.
+ // This variant of `VirtualDirectory` also sends `Cache-Control` headers.
//
- // An `AngelHttpException` instance will be present in `req.properties`
- // as `error`.
- 500: (req, res) async => res.render('error', {'message': req.error.message})
- });
+ // In production, however, prefer serving static files through NGINX or a
+ // similar reverse proxy.
+ //
+ // Read the following two sources for documentation:
+ // * https://medium.com/the-angel-framework/serving-static-files-with-the-angel-framework-2ddc7a2b84ae
+ // * https://github.com/angel-dart/static
+ var vDir = new CachingVirtualDirectory(
+ app,
+ fileSystem,
+ source: fileSystem.directory('web'),
+ );
+ app.use(vDir.handleRequest);
- // Use a fatal error handler to attempt to resolve any issues that
- // result in Angel not being able to send the user a response.
- errors.fatalErrorHandler = (AngelFatalError e) async {
- try {
- // Manually create a request and response context.
- var req = await RequestContext.from(e.request, app);
- var res = new ResponseContext(e.request.response, app);
+ // Throw a 404 if no route matched the request.
+ app.use(() => throw new AngelHttpException.notFound());
- // *Attempt* to render an error page.
- res.render('error', {'message': 'Internal Server Error: ${e.error}'});
- await app.sendResponse(e.request, req, res);
- } catch (_) {
- // If execution fails here, there is nothing we can do.
- stderr..writeln('Fatal error: ${e.error}')..writeln(e.stack);
- }
+ // Set our application up to handle different errors.
+ //
+ // Read the following for documentation:
+ // * https://github.com/angel-dart/angel/wiki/Error-Handling
+ app.errorHandler = (e, req, res) async {
+ if (e.statusCode == 404) {
+ return await res
+ .render('error', {'message': 'No file exists at ${req.path}.'});
+ }
+
+ return await res.render('error', {'message': e.message});
+ };
};
-
- // Throw a 404 if no route matched the request.
- app.after.add(() => throw new AngelHttpException.notFound());
-
- // Handle errors when they occur, based on outgoing status code.
- // By default, requests will go through the 500 handler, unless
- // they have an outgoing 200, or their status code has a handler
- // registered.
- app.after.add(errors.middleware());
-
- // Pass AngelHttpExceptions through handler as well.
- //
- // Again, here is the error handling documentation:
- // * https://github.com/angel-dart/angel/wiki/Error-Handling
- // * https://github.com/angel-dart/errors
- await app.configure(errors);
-}
-
-/// Adds response finalizers to the application.
-///
-/// These run after every request.
-///
-/// See more on the request lifecycle here:
-/// https://github.com/angel-dart/angel/wiki/Request-Lifecycle
-configureFinalizers(Angel app) async {}
-
-/// Adds routes to our application.
-///
-/// See the wiki for information about routing, requests, and responses:
-/// * https://github.com/angel-dart/angel/wiki/Basic-Routing
-/// * https://github.com/angel-dart/angel/wiki/Requests-&-Responses
-configureServer(Angel app) async {
- // The order in which we run these plug-ins is relatively significant.
- // Try not to change it.
-
- // Add global middleware.
- await configureBefore(app);
-
- // Typically, you want to mount controllers first, after any global middleware.
- await app.configure(controllers.configureServer);
-
- // Next, you can add any supplemental routes.
- await configureRoutes(app);
-
- // Add handlers to run after requests are handled.
- //
- // See the request lifecycle docs to find out why these two
- // are separate:
- // https://github.com/angel-dart/angel/wiki/Request-Lifecycle
- await configureAfter(app);
- await configureFinalizers(app);
}
diff --git a/lib/src/services/services.dart b/lib/src/services/services.dart
index 62307100..86c3eb9b 100644
--- a/lib/src/services/services.dart
+++ b/lib/src/services/services.dart
@@ -1,8 +1,8 @@
/// Declare services here!
library angel.services;
-import 'package:angel_common/angel_common.dart';
-import 'user.dart' as user;
+import 'dart:async';
+import 'package:angel_framework/angel_framework.dart';
/// Configure our application to use *services*.
/// Services must be wired to the app via `app.use`.
@@ -12,6 +12,4 @@ import 'user.dart' as user;
///
/// Read more here:
/// https://github.com/angel-dart/angel/wiki/Service-Basics
-configureServer(Angel app) async {
- await app.configure(user.configureServer());
-}
+Future configureServer(Angel app) async {}
diff --git a/lib/src/services/user.dart b/lib/src/services/user.dart
deleted file mode 100644
index 45f15263..00000000
--- a/lib/src/services/user.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-import 'package:angel_common/angel_common.dart';
-import 'package:angel_framework/hooks.dart' as hooks;
-import 'package:crypto/crypto.dart' show sha256;
-import 'package:random_string/random_string.dart' as rs;
-import '../models/user.dart';
-import '../validators/user.dart';
-export '../models/user.dart';
-
-/// Sets up a service mounted at `api/users`.
-///
-/// In the real world, you will want to hook this up to a database.
-/// However, for the sake of the boilerplate, an in-memory service is used,
-/// so that users are not tied into using just one database. :)
-configureServer() {
- return (Angel app) async {
- // A TypedService can be used to serialize and deserialize data to a class, somewhat like an ORM.
- //
- // See here: https://github.com/angel-dart/angel/wiki/TypedService
- app.use('/api/users', new TypedService(new MapService()));
-
- // Configure hooks for the user service.
- // Hooks can be used to add additional functionality, or change the behavior
- // of services, and run on any service, regardless of which database you are using.
- //
- // If you have not already, *definitely* read the service hook documentation:
- // https://github.com/angel-dart/angel/wiki/Hooks
-
- var service = app.service('api/users') as HookedService;
-
- // Prevent clients from doing anything to the `users` service,
- // apart from reading a single user's data.
- service.before([
- HookedServiceEvent.INDEXED,
- HookedServiceEvent.CREATED,
- HookedServiceEvent.MODIFIED,
- HookedServiceEvent.UPDATED,
- HookedServiceEvent.REMOVED
- ], hooks.disable());
-
- // Validate new users, and also hash their passwords.
- service.beforeCreated
- // ..listen(validateEvent(CREATE_USER))
- ..listen((e) {
- var salt = rs.randomAlphaNumeric(12);
- e.data
- ..['password'] =
- hashPassword(e.data['password'], salt, app.jwt_secret)
- ..['salt'] = salt;
- });
-
- // Remove sensitive data from serialized JSON.
- service.afterAll(hooks.remove(['password', 'salt']));
- };
-}
-
-/// SHA-256 hash any string, particularly a password.
-String hashPassword(String password, String salt, String pepper) =>
- sha256.convert(('$salt:$password:$pepper').codeUnits).toString();
diff --git a/pubspec.yaml b/pubspec.yaml
index 8b226af3..aebc1f83 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -4,14 +4,21 @@ publish_to: none # Ensure we don't accidentally publish our private code! ;)
environment:
sdk: ">=1.19.0"
homepage: https://github.com/angel-dart/angel
-dependencies:
- angel_common: ^1.0.0 # Bundles the most commonly-used Angel packages.
- angel_configuration: ^1.0.0 # Included in `angel_common`, but also exposes a transformer
- angel_hot: ^1.0.0-rc.1 # Hot-reloading support. :)
- angel_multiserver: ^1.0.0 # Helpful for applications running a scale.
+dependencies:
+ angel_framework: ^1.1.0-alpha # The core server library.
+ angel_serialize: ^1.0.0-alpha # Model definition metadata.
+
+ angel_auth: ^1.1.0-alpha # Supports stateless authentication via JWT
+ angel_configuration: ^1.1.0-alpha # Loads application configuration, along with support for .env files.
+ angel_cors: ^1.0.0 # CORS support
+ angel_hot: ^1.1.0-alpha # Hot-reloading support. :)
+ angel_jael: ^1.0.0-alpha # Server-side templating engine
+ angel_static: ^1.3.0-alpha # Static file server
dev_dependencies:
+ angel_serialize_generator: ^1.0.0-alpha # Generates serialization code for models.
+ angel_test: ^1.1.0-alpha # Utilities for testing Angel servers.
+ build_runner: ^0.5.0
grinder: ^0.8.0
- http: ^0.11.3
test: ^0.12.13
transformers:
# Injects data from application configuration into Dart code.
diff --git a/test/services/users_test.dart b/test/all_test.dart
similarity index 75%
rename from test/services/users_test.dart
rename to test/all_test.dart
index 0ffdcd2a..c4cb2351 100644
--- a/test/services/users_test.dart
+++ b/test/all_test.dart
@@ -1,5 +1,5 @@
-import 'dart:io';
import 'package:angel/angel.dart';
+import 'package:angel_framework/angel_framework.dart';
import 'package:angel_test/angel_test.dart';
import 'package:test/test.dart';
@@ -23,7 +23,9 @@ main() async {
TestClient client;
setUp(() async {
- var app = await createServer();
+ var app = new Angel();
+ await app.configure(configureServer);
+
client = await connectTo(app);
});
@@ -31,12 +33,11 @@ main() async {
await client.close();
});
- test('index users', () async {
+ test('index returns 200', () async {
// Request a resource at the given path.
- var response = await client.get('/api/users');
+ var response = await client.get('/');
- // By default, we locked this away from the Internet...
- // Expect a 403 response.
- expect(response, hasStatus(HttpStatus.FORBIDDEN));
+ // Expect a 200 response.
+ expect(response, hasStatus(200));
});
}
diff --git a/views/error.jl b/views/error.jl
new file mode 100644
index 00000000..a3850ae5
--- /dev/null
+++ b/views/error.jl
@@ -0,0 +1,5 @@
+
+
+
{{ message }}
+
+
\ No newline at end of file
diff --git a/views/error.mustache b/views/error.mustache
deleted file mode 100644
index 1a689043..00000000
--- a/views/error.mustache
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
- Error
-
-
-
-
-
-
-
-
-
-
{{message}}
-
-
-
-
\ No newline at end of file
diff --git a/views/hello.jl b/views/hello.jl
new file mode 100644
index 00000000..aeb5867c
--- /dev/null
+++ b/views/hello.jl
@@ -0,0 +1,5 @@
+
+
+
Angel
+
+
\ No newline at end of file
diff --git a/views/hello.mustache b/views/hello.mustache
deleted file mode 100644
index 66b6687e..00000000
--- a/views/hello.mustache
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
- Angel
-
-
-
-
-
-
-
-
-
-
Angel
-
-
-
-
\ No newline at end of file
diff --git a/views/layout.jl b/views/layout.jl
new file mode 100644
index 00000000..ea0714bc
--- /dev/null
+++ b/views/layout.jl
@@ -0,0 +1,17 @@
+
+
+
+ {{ title ?? 'Angel' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/web/css/site.css b/web/css/site.css
new file mode 100644
index 00000000..9e40b8de
--- /dev/null
+++ b/web/css/site.css
@@ -0,0 +1,27 @@
+html, body {
+ height: 100%;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ display: table;
+ font-weight: 100;
+ font-family: 'Lato', sans-serif;
+}
+
+.container {
+ text-align: center;
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.content {
+ text-align: center;
+ display: inline-block;
+}
+
+.title {
+ font-size: 96px;
+}
\ No newline at end of file