Added utils to connect to server.

master
blallo 2019-08-18 18:04:39 -03:00
parent 82f002998b
commit cdc04a3401
Signed by: blallo
GPG Key ID: 0CBE577C9B72DC3F
2 changed files with 189 additions and 84 deletions

View File

@ -1,84 +0,0 @@
import 'package:http/http.dart';
import 'package:logger/logger.dart';
import 'dart:convert';
final log = Logger();
class Connection {
// Connection constructor.
Connection(this.username, this.password, this.baseAddress);
// baseAddress contains the base address to the BotZ server
// assuming that the APIs are located at /api/.
final String baseAddress;
// Username is the username to autenticate against the foreign
// service.
final String username;
// Password is the password to autenticate against the foreign
// service.
final String password;
// _stateCookie is private. It contains the HTTP state cookie
// assigned by the server.
String _stateCookie = "";
bool _loggedIn = false;
void login() async {
// TODO: perform the login and obtain the cookie. Set the
// _loggedIn state accordingly.
}
void logout() async {
// TODO: perform the logout. If successful, empty the _stateCookie
// and set the _loggedIn state accordingly.
}
void checkin() async {
// TODO: perform the checkin if possible.
}
void checkout() async {
// TODO: perform the checkout if possible.
}
Future<Map<String, dynamic>> getMovements() async {
// TODO: query /api/movements and retrieve the list of movements.
return {};
}
}
class UnauthorizedException implements ClientException {
UnauthorizedException(this.uri);
final String message = "Unauthorized";
final Uri uri;
}
Response handleResponse(Response resp) {
final c = resp.statusCode;
if (c >= 200 && c < 400) {
} else if (c == 401) {
throw UnauthorizedException(resp.request.url);
} else if (c >=400 || c < 500) {
throw ClientException("Unexpected return code: $c", resp.request.url);
} else if (c >= 500) {
throw ClientException("Server error: $c", resp.request.url);
}
return resp;
}
class BotZContent {
BotZContent(this.response) {
this.response.then((resp) => handleResponse(resp))
.then((value) => this.initContent(value))
.catchError((err) => log.e(err));
}
final Future<Response> response;
Map<String, dynamic> body;
List<String> cookies;
void initContent(Response resp) {
this.cookies = resp.headers['cookies'].split(';');
this.body = jsonDecode(resp.body);
}
}

View File

@ -0,0 +1,189 @@
import 'package:http/http.dart';
import 'package:logger/logger.dart';
import 'dart:convert';
final log = Logger();
const defaultRoutes = {
"login": "/api/login",
"logout": "/api/logout",
"checkin": "/api/checkin",
"checkout": "/api/checkout",
"movements": "/api/movements",
"status": "/api/status",
"ping": "/api/ping",
};
class Connection {
// Connection constructor.
Connection(this.username, this.password, this.baseAddress, [this.routes = defaultRoutes]);
// baseAddress contains the base address to the BotZ server
final Uri baseAddress;
// Username is the username to autenticate against the foreign
// service.
final String username;
// Password is the password to autenticate against the foreign
// service.
final String password;
final Map<String, String> routes;
// _stateCookie is private. It contains the HTTP state cookie
// assigned by the server.
String _cookies = "";
bool _loggedIn = false;
bool _checkedIn = false;
void updateState(String cookies, bool loggedIn) {
this._cookies = loggedIn ? cookies : "";
this._loggedIn = loggedIn;
}
void updateMovement(bool checkedIn) => this._checkedIn = checkedIn;
bool isLoggedIn() => this._loggedIn;
bool isCheckedIn() => this._checkedIn;
// Perform the login and obtain the cookie.
void login() async {
var targetUri = this.baseAddress.toString() + this.routes['login'];
var payload = jsonEncode({
"username": this.username,
"password": this.password,
});
var resp = await post(
targetUri,
headers: {"Content-Type": "application/json"},
body: payload,
);
log.d("[login] Post sent to: $targetUri");
handleResponse(resp);
var body = jsonDecode(resp.body);
log.d("[login] Response: $body");
this.updateState(resp.headers['cookies'], body['logged_in']);
}
// Perform the logout.
void logout() async {
var targetUri = this.baseAddress.toString() + this.routes['logout'];
var resp = await post(
targetUri,
headers: {'cookies': this._cookies},
);
log.d("[logout] Post sent to: $targetUri");
handleResponse(resp);
var body = jsonDecode(resp.body);
log.d("[logout] Response: $body");
this.updateState(this._cookies, body['logged_in']);
}
// Perform the checkin if possible.
void checkin() async {
if (!this._loggedIn) {
throw UnacceptableInvocationException("Not logged in");
}
if (this._checkedIn) {
throw UnacceptableInvocationException("Yet checked in");
}
var targetUri = this.baseAddress.toString() + this.routes['checkin'];
var resp = await post(
targetUri,
headers: {'cookies': this._cookies},
);
handleResponse(resp);
var body = jsonDecode(resp.body);
log.d("[checkin] Response: $body");
this.updateMovement(body['checked_in']);
}
// Perform the checkout if possible.
void checkout() async {
if (!this._loggedIn) {
throw UnacceptableInvocationException("Not logged in");
}
if (!this._checkedIn) {
throw UnacceptableInvocationException("Not yet checked in");
}
var targetUri = this.baseAddress.toString() + this.routes['checkout'];
var resp = await post(
targetUri,
headers: {'cookies': this._cookies},
);
handleResponse(resp);
var body = jsonDecode(resp.body);
log.d("[checkout] Response: $body");
this.updateMovement(body['checked_in']);
}
// Query the server for the list of movements.
Future<Map<String, String>> getMovements() async {
if (!this._loggedIn) {
throw UnacceptableInvocationException("Not logged in");
}
if (!this._checkedIn) {
throw UnacceptableInvocationException("Not yet checked in");
}
var targetUri = this.baseAddress.toString() + this.routes['movements'];
var resp = await get(
targetUri,
headers: {'cookies': this._cookies},
);
try {
handleResponse(resp);
} on NotFoundException {
return {};
}
var body = jsonDecode(resp.body);
Map<String, String> movements;
for (var values in body['movements']) {
movements[values['time']] = values['type'];
}
return movements;
}
}
class UnauthorizedException implements ClientException {
UnauthorizedException(this.uri);
final String message = "Unauthorized";
final Uri uri;
}
class NotFoundException implements ClientException {
NotFoundException(this.uri);
final String message = "Resource not found";
final Uri uri;
}
class UnacceptableInvocationException implements Exception {
UnacceptableInvocationException(this.message);
final String message;
}
Response handleResponse(Response resp) {
final c = resp.statusCode;
if (c >= 200 && c < 400) {
} else if (c == 401) {
throw UnauthorizedException(resp.request.url);
} else if (c == 404) {
throw NotFoundException(resp.request.url);
}else if (c >=400 || c < 500) {
throw ClientException("Unexpected return code: $c", resp.request.url);
} else if (c >= 500) {
throw ClientException("Server error: $c", resp.request.url);
}
return resp;
}