Last active
February 21, 2024 01:48
-
-
Save luo3house/4696f7c3994312d40aeea986c079214c to your computer and use it in GitHub Desktop.
Interceptor Pattern
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef Middleware<C> = dynamic Function(C context, Function() next); | |
class Interceptor<C> { | |
static _noop() {} | |
final List<Middleware<C>> middlewares = List.empty(growable: true); | |
Future<void> call<T>(C context, [Function() fn = _noop]) async { | |
if (middlewares.isEmpty) return fn(); | |
return middlewares.reduce((pre, cur) { | |
return (context, next) => pre(context, () => cur(context, next)); | |
})(context, fn); | |
} | |
Interceptor<C> use(Middleware<C> middleware) { | |
middlewares.add(middleware); | |
return this; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/foundation.dart'; | |
import 'package:flutter_test/flutter_test.dart'; | |
typedef Ctx = Map<String, dynamic>; | |
void main() { | |
test("empty", () async { | |
var text = ""; | |
await Interceptor<String>().call("luo", () async => text = "luo"); | |
expect(text, "luo"); | |
}); | |
test("basic", () async { | |
var text = ""; | |
final interceptor = Interceptor(); | |
interceptor.use((context, next) async { | |
text = "luo1"; | |
next(); | |
}).use((context, next) async { | |
text = "luo2"; | |
next(); | |
}).use((context, next) async { | |
text = "luo3"; | |
next(); | |
}); | |
interceptor.call(null, () async => text = "Hello $text"); | |
expect(text, "Hello luo3"); | |
}); | |
test("auth case", () async { | |
final interceptor = Interceptor<Ctx>(); | |
authMiddleware(context, next) async { | |
if (!context.containsKey('authorization')) { | |
context["status"] = 401; | |
return; | |
} | |
context["user"] = "User Luo"; | |
return next(); | |
} | |
cacheMiddleware(context, next) async { | |
await next(); | |
context["cache-control"] = "no-cache"; | |
} | |
emptyMiddleware(context, next) async { | |
await next(); | |
} | |
interceptor.use(authMiddleware).use(cacheMiddleware).use(emptyMiddleware); | |
Map<String, dynamic> context; | |
// no auth | |
context = <String, dynamic>{"req": "Greeting"}; | |
interceptor.call(context, () async { | |
final user = context["user"]; | |
final req = context["req"]; | |
context["status"] = 200; | |
context["rsp"] = "Hi $user, You're sending: $req"; | |
}); | |
expect(context["status"], 401); | |
expect(context["rsp"], null); | |
expect(context["user"], null); | |
// with auth | |
context = <String, dynamic>{"req": "Greeting", "authorization": "******"}; | |
interceptor.call(context, () async { | |
final user = context["user"]; | |
final req = context["req"]; | |
context["status"] = 200; | |
context["rsp"] = "Hi $user, You're sending: $req"; | |
}); | |
expect(context["status"], 200); | |
expect(context["rsp"], "Hi User Luo, You're sending: Greeting"); | |
expect(context["user"], "User Luo"); | |
}); | |
test("the mixed return value", () async { | |
final interceptor = Interceptor<ValueNotifier<int>>(); | |
interceptor.use((context, next) async { | |
await Future.delayed(const Duration(milliseconds: 20)); | |
context.value |= 0x01; | |
await next(); | |
}); | |
interceptor.use((context, next) { | |
context.value |= 0x02; | |
return next(); | |
}); | |
final context = ValueNotifier(0); | |
await interceptor.call(context); | |
expect(context.value, 0x03); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment