Skip to content

Commit

Permalink
Added reflection helper class
Browse files Browse the repository at this point in the history
  • Loading branch information
sleipnir committed Oct 10, 2023
1 parent ed658c4 commit fc0a972
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 2 deletions.
2 changes: 1 addition & 1 deletion example/spawn_app_example/lib/joe_actor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:spawn_dart/spawn_dart.dart';
)
class JoeActor {
@Action()
Value setLanguage(Request request, Context ctx) {
Value setLanguage(Request request, Context<State> ctx) {
return Value();
}
}
10 changes: 9 additions & 1 deletion lib/src/actors/actor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ class Action {
const Action([this.name = '', this.inputType = Object]);
}

class Context {}
class Context<T> {
late T state;

Context(this.state);

T getState() {
return state;
}
}

class Value {}
124 changes: 124 additions & 0 deletions lib/src/reflect_helper.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import 'dart:mirrors';

import 'package:optional/optional_internal.dart';
import 'package:protobuf/protobuf.dart';
import 'package:spawn_dart/spawn_dart.dart';

import 'google/protobuf/any.pb.dart';

class ReflectHelper {
static final _logger = Logger(
filter: SpawnLogFilter(),
printer: LogfmtPrinter(),
output: SimpleConsoleOutput(),
);

static Object createInstance(Type type,
[Context? context,
Symbol? constructor,
List? arguments,
Map<Symbol, dynamic>? namedArguments]) {
arguments = [];
constructor = Symbol('');

var typeMirror = reflectType(type);

if (typeMirror is ClassMirror) {
var constructors =
List.from(typeMirror.declarations.values.where((declare) {
return declare is MethodMirror && declare.isConstructor;
}));

if (constructors.isEmpty) {
return typeMirror
.newInstance(constructor, arguments, namedArguments!)
.reflectee;
}

throw ArgumentError(
"Cannot create the instance of the Actor type '$type'.");
} else {
throw ArgumentError(
"Cannot create the instance of the Actor type '$type'.");
}
}

static Optional<Any> invoke(
Object instance, MethodMirror method, Any payload, Context context) {
if (payload == null) {
var instanceMirrorResult =
reflect(instance).invoke(method.simpleName, []);

var result = Any.pack(instanceMirrorResult.reflectee);
_logger.d('\nResult: $instanceMirrorResult.\nType result:\n$result');

return Optional.of(result);
}

if (method.parameters.isEmpty) {
_logger.d('Using $method!');

var instanceMirrorResult =
reflect(instance).invoke(method.simpleName, []);
var result = Any.pack(instanceMirrorResult.reflectee);
_logger.d('\nResult: $instanceMirrorResult.\nType result:\n$result');

return Optional.of(result);
} else {
_logger.d('Found Parameters on request method: $method');

var arguments = [];
for (var e in method.parameters) {
_logger.d('Parameter Type is: ${e.type}');
if (e.type.isAssignableTo(reflectType(GeneratedMessage))) {
_logger.d('Set parameter ${MirrorSystem.getName(e.simpleName)}');
var msg = ReflectHelper.createInstance(e.type.reflectedType);
arguments.add(payload.unpackInto(msg as GeneratedMessage));
_logger.d('Argument added!');
} else if (e.type.isAssignableTo(reflectType(Context))) {
_logger.d('Set parameter ${MirrorSystem.getName(e.simpleName)}');
arguments.add(context);
}
}

var instanceMirrorResult =
reflect(instance).invoke(method.simpleName, arguments);
_logger.d('Invoke response $instanceMirrorResult');
if (MirrorSystem.getName(instanceMirrorResult.type.simpleName) !=
'Null') {
_logger.d(
'InstanceMirrorResult not null. ${MirrorSystem.getName(instanceMirrorResult.type.simpleName)}');

var result = Any.pack(instanceMirrorResult.reflectee);
_logger.d('\nResult: $instanceMirrorResult.\nType result:\n$result');

return Optional.ofNullable(result);
} else {
//handle void or null responses
_logger.d('Handle void or null responses');
return Optional.empty();
}
}
}

static List<MethodMirror> getAllMethods(ClassMirror entityClassMirror) {
return entityClassMirror.declarations.values
.where((d) => d is MethodMirror && !d.isConstructor)
.map((f) => f as MethodMirror)
.toList();
}

static Map<String, MethodMirror> getMethodsByAnnotation(
List<MethodMirror> allDeclaredMethods, Type annotation) {
// ignore: omit_local_variable_types
final Map<String, MethodMirror> methods = {};
var annotationMirror = reflectClass(annotation);
allDeclaredMethods
.where((elem) =>
elem.metadata.where((test) => test.type == annotationMirror) !=
null)
.forEach(
(e) => methods[capitalize(MirrorSystem.getName(e.simpleName))] = e);
return methods;
}
}
39 changes: 39 additions & 0 deletions lib/src/spawn_dart_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,42 @@ class SpawnSystem {
_watch.start();
}
}

class SimpleConsoleOutput extends LogOutput {
@override
void output(OutputEvent event) {
for (var line in event.lines) {
printOutput(line);
}
}

void printOutput(String line) async {
stdout.writeln('${DateTime.now()}: $line');
}
}

class SpawnLogFilter extends LogFilter {
Level logLevel;

SpawnLogFilter([this.logLevel = Level.info]);

@override
bool shouldLog(LogEvent event) {
if (event.level.index >= logLevel.index) {
return true;
}
return false;
}
}

String capitalize(String string) {
if (string == null) {
throw ArgumentError('string: $string');
}

if (string.isEmpty) {
return string;
}

return string[0].toUpperCase() + string.substring(1);
}

0 comments on commit fc0a972

Please sign in to comment.