// Copyright (C) 2022 WYATT GROUP
// Please see the AUTHORS file for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
import 'package:wyatt_http_client/src/middleware.dart';
import 'package:wyatt_http_client/src/models/middleware_context.dart';
import 'package:wyatt_http_client/src/models/middleware_request.dart';
import 'package:wyatt_http_client/src/models/middleware_response.dart';
/// {@template pipeline}
/// A [Pipeline] is a list of [Middleware]s that are executed in order.
/// {@endtemplate}
class Pipeline {
/// {@macro pipeline}
Pipeline() : _middlewares = [];
/// {@macro pipeline}
Pipeline.fromIterable(Iterable middlewares)
: _middlewares = middlewares.toList();
final List _middlewares;
/// The length of the [Pipeline].
///
/// This is the number of [Middleware]s in the [Pipeline].
int get length => _middlewares.length;
/// Add a [Middleware] to this [Pipeline]
void addMiddleware(Middleware middleware) {
_middlewares.add(middleware);
}
/// Create new [Pipeline] from the start or end to a specified [Middleware].
Pipeline sub(
Middleware middleware, {
bool include = false,
bool fromEnd = false,
}) {
final nodes = [];
final list = fromEnd ? _middlewares.reversed : _middlewares;
for (final m in list) {
if (m != middleware) {
nodes.add(m);
}
if (m == middleware) {
if (include) {
nodes.add(m);
}
break;
}
}
return Pipeline.fromIterable(fromEnd ? nodes.reversed : nodes);
}
/// Call the [onRequest] method of all [OnRequestMiddleware]s in the
/// [Pipeline].
///
/// The [MiddlewareRequest] returned by the last [OnRequestMiddleware] is
/// returned.
Future onRequest(
MiddlewareContext context,
MiddlewareRequest request,
) async {
MiddlewareRequest req = request..apply();
MiddlewareContext ctx = context.copyWith(lastRequest: req);
for (final middleware in _middlewares) {
if (middleware is OnRequestMiddleware) {
req = await (middleware as OnRequestMiddleware).onRequest(ctx, request);
ctx = context.copyWith(lastRequest: req);
}
}
return req;
}
/// Call the [onResponse] method of all [OnResponseMiddleware]s in the
/// [Pipeline].
///
/// The [MiddlewareResponse] returned by the last [OnResponseMiddleware] is
/// returned.
Future onResponse(
MiddlewareContext context,
MiddlewareResponse response,
) async {
MiddlewareResponse res = response;
MiddlewareContext ctx = context.copyWith(lastResponse: res);
for (final middleware in _middlewares.reversed) {
if (middleware is OnResponseMiddleware) {
res = await (middleware as OnResponseMiddleware)
.onResponse(ctx, response);
ctx = context.copyWith(lastResponse: res);
}
}
return res;
}
@override
String toString() {
final req = [];
final res = [];
for (final middleware in _middlewares) {
if (middleware is OnRequestMiddleware) {
req.add(middleware.getName());
}
if (middleware is OnResponseMiddleware) {
res.insert(0, middleware.getName());
}
}
return '[Req] -> ${req.join(' -> ')}\n[Res] -> ${res.join(' -> ')}';
}
}