Skip to content

Commit

Permalink
Merge #261: Televerse v1.19.1
Browse files Browse the repository at this point in the history
  • Loading branch information
HeySreelal authored Jun 23, 2024
2 parents 172d011 + 40a0a09 commit c84d75f
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 49 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 1.19.0
# 1.19.1

- 🆕 Support for Middlewares & Transformers
- Middlewares lets you attach handlers that are run before your main handler is
Expand All @@ -15,6 +15,15 @@
[#257](https://github.com/HeySreelal/televerse/pull/257) (Thanks to @devsdocs)
- ⚠️ Type of `Webhook.certificate` is changed to InputFile as described by the
official documentation.
- Added examples for
[Middleware](https://github.com/xooniverse/TeleverseExamples/blob/1c30d889d3a0b1d7bdceaad48d6cfd88208e87be/lib/middleware_example.dart)
and
[Transformer](https://github.com/xooniverse/TeleverseExamples/blob/1c30d889d3a0b1d7bdceaad48d6cfd88208e87be/lib/transformer_example.dart)
usage in Examples repo.

# 1.19.0

- [Retracted]

# 1.18.0

Expand Down
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,63 @@ bot.start((ctx) async {
Efficiently build inline query results with the InlineQueryResultBuilder,
simplifying the process of generating inline query results.

### 13. 🔌 Plugin Support

Televerse support Middlewares and Transformers in the library. These features
allow you to preprocess and manipulate API requests seamlessly.

#### Middlewares

Middlewares let you execute code before your main handler is run. This is useful
for tasks like logging, authentication, and more.

#### Example: Logging Middleware

```dart
class LoggingMiddleware implements Middleware {
@override
Future<void> handle(
Context ctx,
NextFunction next,
) async {
print('Received update: ${ctx.update}');
await next();
}
}
// Usage
bot.use(LoggingMiddleware());
```

#### Transformers

Transformers allow you to alter the request payloads directly, providing a more
flexible way to modify requests before they are sent to the API.

#### Example: Auto Replier Transformer

```dart
class AutoReplier implements Transformer {
@override
FutureOr<Map<String, dynamic>> transform(
APIMethod method,
Map<String, dynamic> payload,
Context? ctx,
) {
final isSendMethod = APIMethod.sendMethods.contains(method);
final isNotChatAction = method != APIMethod.sendChatAction;
if (isSendMethod && isNotChatAction) {
payload["reply_markup"] = ForceReply().toJson();
}
return payload;
}
}
// Usage
bot.use(AutoReplier());
```

---

## 🌟 Shoot a Star
Expand Down Expand Up @@ -380,3 +437,6 @@ clean, maintainable code that responds to messages and updates on Telegram. So,
what are you waiting for? Start building your Telegram bot with Televerse today!

[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-Say%20Thanks-blue?style=flat-square&logo=buy-me-a-coffee)](https://www.buymeacoffee.com/heysreelal)

```
```
2 changes: 1 addition & 1 deletion lib/src/televerse/bot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ class Bot {

if (index < _middlewares.length) {
try {
await _middlewares[index].fn(ctx, next);
await _middlewares[index].handle(ctx, next);
} catch (err, stack) {
final botErr = BotError(
err,
Expand Down
2 changes: 1 addition & 1 deletion lib/src/televerse/context/context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class Context {
/// Executes the middleware on the current context
Future<void> use(MiddlewareBase middleware) async {
if (middleware is Middleware) {
await middleware.fn(this, () async {});
await middleware.handle(this, () async {});
}

if (middleware is Transformer) {
Expand Down
136 changes: 92 additions & 44 deletions lib/src/televerse/middlewares/middleware.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,119 @@ part of '../../../televerse.dart';
/// Base class for the middlewares
sealed class MiddlewareBase {}

/// The next handler to be executed.
/// A typedef for the next function used in middleware.
///
/// Invoking this function basically means, you want the next handler to also run.
/// This function should be called within a middleware to pass control to the
/// next middleware in the stack. If it's not called, the subsequent middlewares
/// and the main handler won't be executed.
typedef NextFunction = FutureOr<void> Function();

/// Represents a Middleware.
/// Represents a Middlware that can be used to process requests
/// before they reach the main handler.
///
/// Middlewares are attached to the bot with the `bot.use` method. Middlewares act as an intermediate
/// handler before the actual handler.
/// This class should be implemented by any middleware that needs to perform
/// operations on the [Context] object or decide whether to pass control to
/// the next middleware or the main handler.
///
/// These intermediate functions can be used to process or modify the Context before it reaches the main handler.
/// Example usage:
/// ```dart
/// class Logger implements Middleware {
/// @override
/// FutureOr<void> handle(Context ctx, NextFunction next) async {
/// print('Request received: ${ctx.update}');
/// await next(); // Pass control to the next middleware or handler
/// print('Response sent');
/// }
/// }
/// ```
///
/// By using the `Middleware` class, you can create reusable components that
/// can be attached to the bot and executed in sequence.
abstract interface class Middleware implements MiddlewareBase {
/// The middleware function
/// The middleware function that processes the [Context] and optionally
/// passes control to the next middleware or main handler.
///
/// The [handle] function should call the [next] function to pass control
/// to the next middleware in the stack or to the main handler if there are
/// no more middlewares. If [next] is not called, the subsequent middlewares
/// and the main handler will not be executed.
///
/// - [ctx] - The current context where the middleware is operating on
/// Example usage:
/// ```dart
/// @override
/// FutureOr<void> handle(Context ctx, NextFunction next) async {
/// // Perform some pre-processing
/// print('Before main handler');
///
/// - [next] - The next handler method. Gives you ability to decide whether to run or skip the next handler.
FutureOr<void> fn(
/// // Pass control to the next middleware or the main handler
/// await next();
///
/// // Perform some post-processing
/// print('After main handler');
/// }
/// ```
FutureOr<void> handle(
Context ctx,
NextFunction next,
);

/// Constructs a Middleware
/// Constructs a [Middleware] instance.
const Middleware();
}

/// Represents a interceptor which can alter the API requests.
/// Represents a transformer that can alter API requests before they are sent.
///
/// This class should be implemented by any transformer that needs to modify
/// the request payload based on the API method being called, the provided
/// payload, or the context.
///
/// Example usage:
/// ```dart
/// class AutoReplier implements Transformer {
/// @override
/// FutureOr<Map<String, dynamic>> transform(
/// APIMethod method,
/// Map<String, dynamic> payload,
/// Context? ctx,
/// ) {
/// final isSendMethod = APIMethod.sendMethods.contains(method);
/// final isNotChatAction = method != APIMethod.sendChatAction;
///
/// if (isSendMethod && isNotChatAction) {
/// payload["reply_markup"] = ForceReply().toJson();
/// }
/// return payload;
/// }
/// }
/// ```
///
/// By using the `Transformer` class, you can create reusable components that
/// can be attached to the bot to modify the request payload dynamically.
abstract interface class Transformer implements MiddlewareBase {
/// The API interceptor function.
///
/// ## Available Arguments
/// Here are the different arugments available to the transfomer function.
///
/// ### 1. `APIMethod method`
///
/// This parameter tells which API Method is now being called. Let's you decide whether to
/// perform or not perform the transfomer on the payload.
/// The function that processes and alters the API request payload.
///
/// ### 2. `Map<String, dynamic> payload`
/// ## Parameters
/// - `APIMethod method`: Indicates which API method is being called. This allows
/// you to decide whether or not to transform the payload based on the method.
///
/// The payload is the actual JSON body object to be posted to the current method.
/// Check the [Telegram Bot API documentation](https://core.telegram.org/bots/api) to learn about all the possible
/// parameters that can be passed. In most fo the cases, you will be altering the payload with a transformer. So,
/// it is important to alter and return the valid JSON after transformation.
/// - `Map<String, dynamic> payload`: The actual JSON body object to be posted
/// to the current method. This payload can be altered and should be returned
/// as a valid JSON after transformation. Refer to the [Telegram Bot API documentation](https://core.telegram.org/bots/api)
/// to understand the possible parameters that can be passed.
///
/// ### 3. `Context? ctx`
/// The available context object. If the user is invoking RawAPI methods through the context object, such as
/// `ctx.reply` or `ctx.answerCallbackQuery` the particular context object can be accessed with this argument.
/// Having access to the Context object primarily lets you take control of the whole incoming update. This lets you
/// further enhance your transfomrmer.
///
/// Be aware that `ctx` can be `null`, this occurs when user is invoking the method directly through the `RawAPI` instance.
/// - `Context? ctx`: The context object, if available. This is accessible when
/// the user invokes `RawAPI` methods through the context object, such as `ctx.reply`
/// or `ctx.answerCallbackQuery`. Access to the context object allows you to further
/// enhance your transformer by leveraging the incoming update.
///
/// **Note**: `ctx` can be `null` if the method is invoked directly through the `RawAPI` instance.
///
/// ## Example
/// Here's a simple implementation of the `AutoReplier` transformer. The auto-replier transformer can be used to
/// automatically require users to reply to the current message the bot sent by passing the `ForceReply` reply markup with all the possible
/// send methods.
///
/// Here's a simple implementation of the `AutoReplier` transformer:
/// ```dart
/// class AutoReplier implements Transformer {
/// @override
/// FutureOr<Map<String, dynamic>> fn(
/// FutureOr<Map<String, dynamic>> transform(
/// APIMethod method,
/// Map<String, dynamic> payload,
/// Context? ctx,
Expand All @@ -81,19 +131,17 @@ abstract interface class Transformer implements MiddlewareBase {
/// }
/// ```
///
/// The above code, simply creates a auto replier transformer. Now users can use it as:
///
/// The above code creates an `AutoReplier` transformer. Users can attach it to the bot:
/// ```dart
/// bot.use(AutoReplier());
/// ```
///
/// That's it. Now whenever user makes a send method request, the force reply markup will be added to it.
FutureOr<Map<String, dynamic>> fn(
/// Now, whenever a send method request is made, the force reply markup will be added.
FutureOr<Map<String, dynamic>> transform(
APIMethod method,
Map<String, dynamic> payload,
Context? ctx,
);

/// Constructs a API Interceptor middleware
/// Constructs a `Transformer` instance.
const Transformer();
}
2 changes: 1 addition & 1 deletion lib/src/televerse/raw_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class RawAPI {
final ts = [..._transformers, ...(_context?._transfomers ?? [])];

while (i < ts.length) {
params = await ts[i].fn(method, params!, _context);
params = await ts[i].transform(method, params!, _context);
i++;
}

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: televerse
description: Televerse lets you create your own efficient Telegram bots with ease in Dart. Supports latest Telegram Bot API - 7.5!
version: 1.19.0
version: 1.19.1
homepage: https://github.com/HeySreelal/televerse
topics:
- telegram
Expand Down

0 comments on commit c84d75f

Please sign in to comment.