1.0.5
This commit is contained in:
parent
2479e8eaa7
commit
f2fcc48642
6 changed files with 126 additions and 46 deletions
|
@ -1,6 +1,6 @@
|
||||||
# angel_client
|
# angel_client
|
||||||
|
|
||||||
[![pub 1.0.4](https://img.shields.io/badge/pub-1.0.4-brightgreen.svg)](https://pub.dartlang.org/packages/angel_client)
|
[![pub 1.0.5](https://img.shields.io/badge/pub-1.0.5-brightgreen.svg)](https://pub.dartlang.org/packages/angel_client)
|
||||||
[![build status](https://travis-ci.org/angel-dart/client.svg)](https://travis-ci.org/angel-dart/client)
|
[![build status](https://travis-ci.org/angel-dart/client.svg)](https://travis-ci.org/angel-dart/client)
|
||||||
|
|
||||||
Client library for the Angel framework.
|
Client library for the Angel framework.
|
||||||
|
|
|
@ -22,6 +22,9 @@ abstract class Angel {
|
||||||
|
|
||||||
Angel(String this.basePath);
|
Angel(String this.basePath);
|
||||||
|
|
||||||
|
/// Fired whenever a WebSocket is successfully authenticated.
|
||||||
|
Stream<AngelAuthResult> get onAuthenticated;
|
||||||
|
|
||||||
Future<AngelAuthResult> authenticate(
|
Future<AngelAuthResult> authenticate(
|
||||||
{String type,
|
{String type,
|
||||||
credentials,
|
credentials,
|
||||||
|
@ -41,7 +44,7 @@ abstract class Angel {
|
||||||
/// Logs the current user out of the application.
|
/// Logs the current user out of the application.
|
||||||
Future logout();
|
Future logout();
|
||||||
|
|
||||||
Service service<T>(String path, {Type type, AngelDeserializer deserializer});
|
Service<T> service<T>(String path, {Type type, AngelDeserializer deserializer});
|
||||||
|
|
||||||
Future<http.Response> delete(String url, {Map<String, String> headers});
|
Future<http.Response> delete(String url, {Map<String, String> headers});
|
||||||
|
|
||||||
|
@ -87,10 +90,30 @@ class AngelAuthResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries a service on an Angel server, with the same API.
|
/// Queries a service on an Angel server, with the same API.
|
||||||
abstract class Service {
|
abstract class Service<T> {
|
||||||
|
/// Fired on `indexed` events.
|
||||||
|
Stream<T> get onIndexed;
|
||||||
|
|
||||||
|
/// Fired on `read` events.
|
||||||
|
Stream<T> get onRead;
|
||||||
|
|
||||||
|
/// Fired on `created` events.
|
||||||
|
Stream<T> get onCreated;
|
||||||
|
|
||||||
|
/// Fired on `modified` events.
|
||||||
|
Stream<T> get onModified;
|
||||||
|
|
||||||
|
/// Fired on `updated` events.
|
||||||
|
Stream<T> get onUpdated;
|
||||||
|
|
||||||
|
/// Fired on `removed` events.
|
||||||
|
Stream<T> get onRemoved;
|
||||||
|
|
||||||
/// The Angel instance powering this service.
|
/// The Angel instance powering this service.
|
||||||
Angel get app;
|
Angel get app;
|
||||||
|
|
||||||
|
Future close();
|
||||||
|
|
||||||
/// Retrieves all resources.
|
/// Retrieves all resources.
|
||||||
Future index([Map params]);
|
Future index([Map params]);
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,14 @@ AngelHttpException failure(http.Response response, {error, StackTrace stack}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class BaseAngelClient extends Angel {
|
abstract class BaseAngelClient extends Angel {
|
||||||
|
final StreamController<AngelAuthResult> _onAuthenticated =
|
||||||
|
new StreamController<AngelAuthResult>();
|
||||||
|
final List<Service> _services = [];
|
||||||
final http.BaseClient client;
|
final http.BaseClient client;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<AngelAuthResult> get onAuthenticated => _onAuthenticated.stream;
|
||||||
|
|
||||||
BaseAngelClient(this.client, String basePath) : super(basePath);
|
BaseAngelClient(this.client, String basePath) : super(basePath);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -87,7 +93,9 @@ abstract class BaseAngelClient extends Angel {
|
||||||
"Auth endpoint '$url' did not return a proper response.");
|
"Auth endpoint '$url' did not return a proper response.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AngelAuthResult.fromMap(json);
|
var r = new AngelAuthResult.fromMap(json);
|
||||||
|
_onAuthenticated.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +125,9 @@ abstract class BaseAngelClient extends Angel {
|
||||||
"Auth endpoint '$url' did not return a proper response.");
|
"Auth endpoint '$url' did not return a proper response.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AngelAuthResult.fromMap(json);
|
var r = new AngelAuthResult.fromMap(json);
|
||||||
|
_onAuthenticated.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -126,6 +136,10 @@ abstract class BaseAngelClient extends Angel {
|
||||||
|
|
||||||
Future close() async {
|
Future close() async {
|
||||||
client.close();
|
client.close();
|
||||||
|
_onAuthenticated.close();
|
||||||
|
Future.wait(_services.map((s) => s.close())).then((_) {
|
||||||
|
_services.clear();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future logout() async {
|
Future logout() async {
|
||||||
|
@ -161,10 +175,13 @@ abstract class BaseAngelClient extends Angel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Service service<T>(String path, {Type type, AngelDeserializer deserializer}) {
|
Service<T> service<T>(String path,
|
||||||
|
{Type type, AngelDeserializer deserializer}) {
|
||||||
String uri = path.toString().replaceAll(straySlashes, "");
|
String uri = path.toString().replaceAll(straySlashes, "");
|
||||||
return new BaseAngelService(client, this, '$basePath/$uri',
|
var s = new BaseAngelService<T>(client, this, '$basePath/$uri',
|
||||||
deserializer: deserializer);
|
deserializer: deserializer);
|
||||||
|
_services.add(s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _join(url) {
|
String _join(url) {
|
||||||
|
@ -208,13 +225,48 @@ abstract class BaseAngelClient extends Angel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseAngelService extends Service {
|
class BaseAngelService<T> extends Service<T> {
|
||||||
@override
|
@override
|
||||||
final BaseAngelClient app;
|
final BaseAngelClient app;
|
||||||
final String basePath;
|
final String basePath;
|
||||||
final http.BaseClient client;
|
final http.BaseClient client;
|
||||||
final AngelDeserializer deserializer;
|
final AngelDeserializer deserializer;
|
||||||
|
|
||||||
|
final StreamController<T> _onIndexed = new StreamController<T>(),
|
||||||
|
_onRead = new StreamController<T>(),
|
||||||
|
_onCreated = new StreamController<T>(),
|
||||||
|
_onModified = new StreamController<T>(),
|
||||||
|
_onUpdated = new StreamController<T>(),
|
||||||
|
_onRemoved = new StreamController<T>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onIndexed => _onIndexed.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onRead => _onRead.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onCreated => _onCreated.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onModified => _onModified.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onUpdated => _onUpdated.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<T> get onRemoved => _onRemoved.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future close() async {
|
||||||
|
_onIndexed.close();
|
||||||
|
_onRead.close();
|
||||||
|
_onCreated.close();
|
||||||
|
_onModified.close();
|
||||||
|
_onUpdated.close();
|
||||||
|
_onRemoved.close();
|
||||||
|
}
|
||||||
|
|
||||||
BaseAngelService(this.client, this.app, this.basePath, {this.deserializer});
|
BaseAngelService(this.client, this.app, this.basePath, {this.deserializer});
|
||||||
|
|
||||||
deserialize(x) {
|
deserialize(x) {
|
||||||
|
@ -244,8 +296,15 @@ class BaseAngelService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
final json = JSON.decode(response.body);
|
final json = JSON.decode(response.body);
|
||||||
if (json is! List) return json;
|
|
||||||
return json.map(deserialize).toList();
|
if (json is! List) {
|
||||||
|
_onIndexed.add(json);
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
var r = json.map(deserialize).toList();
|
||||||
|
_onIndexed.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +320,9 @@ class BaseAngelService extends Service {
|
||||||
throw failure(response);
|
throw failure(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deserialize(JSON.decode(response.body));
|
var r = deserialize(JSON.decode(response.body));
|
||||||
|
_onRead.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -277,7 +338,9 @@ class BaseAngelService extends Service {
|
||||||
throw failure(response);
|
throw failure(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deserialize(JSON.decode(response.body));
|
var r = deserialize(JSON.decode(response.body));
|
||||||
|
_onCreated.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -293,7 +356,9 @@ class BaseAngelService extends Service {
|
||||||
throw failure(response);
|
throw failure(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deserialize(JSON.decode(response.body));
|
var r = deserialize(JSON.decode(response.body));
|
||||||
|
_onModified.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -309,7 +374,9 @@ class BaseAngelService extends Service {
|
||||||
throw failure(response);
|
throw failure(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deserialize(JSON.decode(response.body));
|
var r = deserialize(JSON.decode(response.body));
|
||||||
|
_onUpdated.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
@ -325,7 +392,9 @@ class BaseAngelService extends Service {
|
||||||
throw failure(response);
|
throw failure(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return deserialize(JSON.decode(response.body));
|
var r = deserialize(JSON.decode(response.body));
|
||||||
|
_onRemoved.add(r);
|
||||||
|
return r;
|
||||||
} catch (e, st) {
|
} catch (e, st) {
|
||||||
throw failure(response, error: e, stack: st);
|
throw failure(response, error: e, stack: st);
|
||||||
}
|
}
|
||||||
|
|
44
lib/io.dart
44
lib/io.dart
|
@ -10,27 +10,40 @@ export 'angel_client.dart';
|
||||||
|
|
||||||
/// Queries an Angel server via REST.
|
/// Queries an Angel server via REST.
|
||||||
class Rest extends BaseAngelClient {
|
class Rest extends BaseAngelClient {
|
||||||
|
final List<Service> _services = [];
|
||||||
|
|
||||||
Rest(String path) : super(new http.Client(), path);
|
Rest(String path) : super(new http.Client(), path);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Service service<T>(String path, {Type type, AngelDeserializer deserializer}) {
|
Service<T> service<T>(String path, {Type type, AngelDeserializer deserializer}) {
|
||||||
String uri = path.replaceAll(straySlashes, "");
|
String uri = path.replaceAll(straySlashes, "");
|
||||||
return new RestService(
|
var s = new RestService<T>(
|
||||||
client, this, "$basePath/$uri", T != dynamic ? T : type);
|
client, this, "$basePath/$uri", T != dynamic ? T : type);
|
||||||
|
_services.add(s);
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<String> authenticateViaPopup(String url, {String eventName: 'token'}) {
|
Stream<String> authenticateViaPopup(String url, {String eventName: 'token'}) {
|
||||||
throw new UnimplementedError('Opening popup windows is not supported in the `dart:io` client.');
|
throw new UnimplementedError('Opening popup windows is not supported in the `dart:io` client.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future close() async {
|
||||||
|
super.close();
|
||||||
|
Future.wait(_services.map((s) => s.close())).then((_) {
|
||||||
|
_services.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queries an Angel service via REST.
|
/// Queries an Angel service via REST.
|
||||||
class RestService extends BaseAngelService {
|
class RestService<T> extends BaseAngelService<T> {
|
||||||
final Type type;
|
final Type type;
|
||||||
|
|
||||||
RestService(http.BaseClient client, Angel app, String url, this.type)
|
RestService(http.BaseClient client, Angel app, String url, this.type)
|
||||||
: super(client, app, url);
|
: super(client, app, url);
|
||||||
|
|
||||||
|
@override
|
||||||
deserialize(x) {
|
deserialize(x) {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
return x.runtimeType == type
|
return x.runtimeType == type
|
||||||
|
@ -49,29 +62,4 @@ class RestService extends BaseAngelService {
|
||||||
|
|
||||||
return super.makeBody(x);
|
return super.makeBody(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future index([Map params]) async {
|
|
||||||
final items = await super.index(params);
|
|
||||||
if (items is! List) return items;
|
|
||||||
return items.map(deserialize).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future read(id, [Map params]) => super.read(id, params).then(deserialize);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future create(data, [Map params]) =>
|
|
||||||
super.create(data, params).then(deserialize);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future modify(id, data, [Map params]) =>
|
|
||||||
super.modify(id, data, params).then(deserialize);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future update(id, data, [Map params]) =>
|
|
||||||
super.update(id, data, params).then(deserialize);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future remove(id, [Map params]) => super.remove(id, params).then(deserialize);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel_client
|
name: angel_client
|
||||||
version: 1.0.4
|
version: 1.0.5
|
||||||
description: Client library for the Angel framework.
|
description: Client library for the Angel framework.
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/angel_client
|
homepage: https://github.com/angel-dart/angel_client
|
||||||
|
|
|
@ -19,7 +19,7 @@ main() {
|
||||||
httpServer =
|
httpServer =
|
||||||
await serverApp.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
|
await serverApp.startServer(InternetAddress.LOOPBACK_IP_V4, 0);
|
||||||
url = "http://localhost:${httpServer.port}";
|
url = "http://localhost:${httpServer.port}";
|
||||||
serverApp.use("/postcards", new server.MemoryService<Postcard>());
|
serverApp.use("/postcards", new server.TypedService<Postcard>(new server.MapService()));
|
||||||
serverPostcards = serverApp.service("postcards");
|
serverPostcards = serverApp.service("postcards");
|
||||||
|
|
||||||
clientApp = new client.Rest(url);
|
clientApp = new client.Rest(url);
|
||||||
|
@ -94,7 +94,7 @@ main() {
|
||||||
|
|
||||||
test("modify/update", () async {
|
test("modify/update", () async {
|
||||||
var innerPostcards =
|
var innerPostcards =
|
||||||
serverPostcards.inner as server.MemoryService<Postcard>;
|
serverPostcards.inner as server.TypedService<Postcard>;
|
||||||
print(innerPostcards.items);
|
print(innerPostcards.items);
|
||||||
Postcard mecca = await clientTypedPostcards
|
Postcard mecca = await clientTypedPostcards
|
||||||
.create(new Postcard(location: "Mecca", message: "Pilgrimage"));
|
.create(new Postcard(location: "Mecca", message: "Pilgrimage"));
|
||||||
|
|
Loading…
Reference in a new issue