Skip to content

Commit

Permalink
Merge pull request #82 from javad-zobeidi/dev
Browse files Browse the repository at this point in the history
0.3.0
  • Loading branch information
javad-zobeidi committed Jun 16, 2024
2 parents 35713f7 + fe58447 commit 931e6b5
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 172 deletions.
8 changes: 3 additions & 5 deletions lib/src/exception/base_http_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ class BaseHttpResponseException {
this.responseType = ResponseType.json,
});

Response call() => Response(
responseType == ResponseType.html ? message : {'message': message},
responseType,
code,
);
Response response(bool isJson) => isJson
? Response.json({'message': message}, code)
: Response.html(message);
}
2 changes: 1 addition & 1 deletion lib/src/exception/not_found_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ class NotFoundException extends BaseHttpResponseException {
super.message = 'Not Fount 404',
super.code = HttpStatus.notFound,
super.errorCode = 'Not found 404',
super.responseType = ResponseType.json,
super.responseType = ResponseType.html,
});
}
11 changes: 11 additions & 0 deletions lib/src/extensions/date_time_aws_format.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,14 @@ extension DateTimeAwsFormat on DateTime {
'${zeroPad(hour)}${zeroPad(minute)}${zeroPad(second)}Z';
}
}

extension DateTimeFormatting on DateTime {
String format() {
return '${year.toString().padLeft(4, '0')}-'
'${month.toString().padLeft(2, '0')}-'
'${day.toString().padLeft(2, '0')} '
'${hour.toString().padLeft(2, '0')}:'
'${minute.toString().padLeft(2, '0')}:'
'${second.toString().padLeft(2, '0')}';
}
}
107 changes: 34 additions & 73 deletions lib/src/http/controller/controller_handler.dart
Original file line number Diff line number Diff line change
@@ -1,90 +1,51 @@
import 'dart:convert';
import 'dart:io';
import 'package:vania/src/exception/invalid_argument_exception.dart';
import 'package:vania/src/exception/validation_exception.dart';
import 'package:vania/src/route/route_data.dart';
import 'package:vania/vania.dart';

class ControllerHandler {
final RouteData route;
final Request request;
ControllerHandler({required this.route, required this.request}) {
handler();
}

void handler() async {
void create({
required RouteData route,
required Request request,
}) async {
List<dynamic> positionalArguments = [];
Function? function;
if (route.action is Function) {
function = route.action;
}

if (function == null) {
request.response.statusCode = HttpStatus.internalServerError;
if (request.request.headers.contentType.toString() ==
"application/json") {
request.response.headers.contentType = ContentType.json;

request.response.write(jsonEncode({'message': 'Method not found'}));
} else {
request.response.headers.contentType = ContentType.html;
request.response.write('<b>Method not found</b>');
}
request.response.close();
return;
}

Map<String, dynamic> params = {};

params.addAll(route.params ?? {});

var argsList = extractFunctionArgs(function);

var requestArgIndex = argsList.indexOf("Request");

if (requestArgIndex > -1) {
argsList.removeAt(requestArgIndex);
}

if (argsList.isNotEmpty) {
positionalArguments = params.values
.map((item) => int.tryParse(item.toString()) ?? item)
if (route.params != null) {
positionalArguments = route.params!.values
.map((param) => int.tryParse(param) ?? param)
.toList();
}

if (requestArgIndex > -1) {
positionalArguments.insert(requestArgIndex, request);
if (route.hasRequest) {
positionalArguments.insert(0, request);
}

try {
Response data = await Function.apply(function, positionalArguments, {});
data.makeResponse(request.response);
} on BaseHttpResponseException catch (e) {
e.call().makeResponse(request.response);
} on InvalidArgumentException catch (_) {
rethrow;
}
}

List extractFunctionArgs(Function function) {
String functionString = function.toString();
String paramsString = functionString.split(RegExp(r'\(|\)'))[1].trim();

RegExp regex = RegExp(r'(.+?)\s*\{(.+?)\}');
Match? match =
regex.firstMatch(paramsString.replaceAll('[', '').replaceAll(']', ''));

if (match == null) {
return removeDynamicPart(paramsString)
.replaceAll('[', '')
.replaceAll(']', '')
.split(',');
} else {
return removeDynamicPart(match.group(1).toString()).split(',');
Response response = await Function.apply(
route.action,
positionalArguments,
{},
);

response.makeResponse(request.response);
} on ValidationException catch (error) {
error
.response(request.headers['accept'] == "application/json")
.makeResponse(request.response);
} catch (error) {
_response(request, error.toString());
}
}
}

String removeDynamicPart(String input) {
RegExp regExp = RegExp(r'\{[^\}]*\}');
return input.replaceAll(regExp, '');
void _response(Request req, message, [statusCode = 400]) {
if (req.headers['accept'] == "application/json") {
Response.json(
{
"message": message,
},
statusCode,
).makeResponse(req.response);
} else {
Response.html(message).makeResponse(req.response);
}
}
8 changes: 6 additions & 2 deletions lib/src/http/request/request.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import 'package:vania/vania.dart';
class Request {
final HttpRequest request;
final RouteData? route;
Request({required this.request, this.route});

Request.from({required this.request, this.route});

String? get ip => request.connectionInfo?.remoteAddress.address;

Expand Down Expand Up @@ -39,7 +40,10 @@ class Request {
}

Future<Request> extractBody() async {
if (request.method.toLowerCase() == 'post') {
final whereMethod = ['post', 'patch', 'put']
.where((method) => method == request.method.toLowerCase())
.toList();
if (whereMethod.isNotEmpty) {
body = await RequestBody.extractBody(request: request);
}
return this;
Expand Down
37 changes: 27 additions & 10 deletions lib/src/http/request/request_handler.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'dart:io';

import 'package:vania/src/config/http_cors.dart';
import 'package:vania/src/exception/invalid_argument_exception.dart';
import 'package:vania/src/http/controller/controller_handler.dart';
Expand All @@ -18,11 +17,9 @@ Future httpRequestHandler(HttpRequest req) async {
try {
/// Check if cors is enabled
HttpCors(req);

RouteData? route = httpRouteHandler(req);

Request request = await Request(request: req, route: route).extractBody();

Request request = Request.from(request: req, route: route);
await request.extractBody();
if (route == null) return;

/// check if pre middleware exist and call it
Expand All @@ -31,15 +28,35 @@ Future httpRequestHandler(HttpRequest req) async {
}

/// Controller and method handler
ControllerHandler(route: route, request: request);
} on BaseHttpResponseException catch (e) {
e.call().makeResponse(req.response);
ControllerHandler().create(
route: route,
request: request,
);
} on BaseHttpResponseException catch (error) {
error
.response(
req.headers.value('accept') == "application/json",
)
.makeResponse(req.response);
} on InvalidArgumentException catch (e) {
print(e.message);
Logger.log(e.message, type: Logger.ERROR);
_response(req, e.message);
} catch (e) {
print(e.toString());
Logger.log(e.toString(), type: Logger.ERROR);
_response(req, e.toString());
}
}
}

void _response(req, message) {
if (req.headers.value('accept') == "application/json") {
Response.json(
{
"message": message,
},
400,
).makeResponse(req.response);
} else {
Response.html(message).makeResponse(req.response);
}
}
6 changes: 3 additions & 3 deletions lib/src/redis/command/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:vania/src/redis/lowlevel/protocol_client.dart';
import 'package:vania/src/redis/lowlevel/resp.dart';
import 'package:vania/vania.dart';

class _MultiCodec {
class MultiCodec {
final List<RedisCodec> codecs = [
RedisCodec(encoder: StringEncoder(), decoder: StringDecoder()),
RedisCodec(encoder: IntEncoder(), decoder: IntDecoder()),
Expand Down Expand Up @@ -48,10 +48,10 @@ class CommandsClient<K, V> implements Commands<K, V> {
CommandsClient._(this._connection);

/// key type codecs
final _MultiCodec keyCodec = _MultiCodec();
final MultiCodec keyCodec = MultiCodec();

/// value type codecs
final _MultiCodec valueCodec = _MultiCodec();
final MultiCodec valueCodec = MultiCodec();

@override
Future<bool> del(K key) async {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/redis/lowlevel/resp.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class Resp {
/// serialize value implementation
String _serializeValue(dynamic value, {bool isBulkString = true}) {
if (value is String) {
if (!isBulkString && !value.contains(RegExp('\s'))) {
if (!isBulkString && !value.contains(RegExp('s'))) {
return '+$value$_CRLF';
}
return '\$${value.length}$_CRLF$value$_CRLF';
Expand Down
8 changes: 7 additions & 1 deletion lib/src/route/route_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import 'package:vania/vania.dart';
class RouteData {
final String method;
String path;
final dynamic action;
final Function action;
Map<String, dynamic>? params;
List<Middleware> preMiddleware;
String? domain;
final bool? corsEnabled;
final bool hasRequest;
final String? prefix;
Map<String, Type>? paramTypes;
Map<String, String>? regex;

RouteData({
required this.method,
Expand All @@ -19,5 +22,8 @@ class RouteData {
this.preMiddleware = const <Middleware>[],
this.domain,
this.prefix,
this.hasRequest = false,
this.paramTypes,
this.regex,
});
}

0 comments on commit 931e6b5

Please sign in to comment.