From 88bd12aaddbf3557f267957f17a8cdf6911321cd Mon Sep 17 00:00:00 2001 From: Rikitav Date: Mon, 9 Mar 2026 03:31:45 +0400 Subject: [PATCH] * Readme and docs updated --- README.md | 5 ++-- docs/GETTING_STARTED.md | 64 +++++++++++++++++++---------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index da9e099..54b2b14 100644 --- a/README.md +++ b/README.md @@ -91,13 +91,12 @@ bot.Handlers.AddHandler(); using Telegrator.Handlers; using Telegrator.Annotations; -[CommandHandler, CommandAlias("first"), NumericState(SpecialState.NoState)] +[CommandHandler, CommandAlias("first"), State(null)] public class StateKeepFirst : CommandHandler { public override async Task Execute(IHandlerContainer container, CancellationToken cancellation) { - container.CreateNumericState(); - container.ForwardNumericState(); + StateStorage.GetStateMachine().BysenderId().Advance(); await Reply("first state moved (1)", cancellationToken: cancellation); return Result.Ok(); } diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index 89fbfe7..53629ae 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -47,7 +47,7 @@ This guide will walk you through the core concepts and advanced features of **Te **Telegrator** is distributed as a NuGet package. You can install it using the .NET CLI, the NuGet Package Manager Console, or by managing NuGet packages in Visual Studio. ### Prerequisites -- .NET >= 5.0 `or` .NET Core >= 2.0 `or` Framework >= 4.6.1 (.NET Standard 2.0 compatible) +- .NET >= 5.0 `or` .NET Core >= 2.0 `or` Framework >= 4.6.1 (.NET Standard 2.1 compatible) - A Telegram Bot Token from [@BotFather](https://t.me/BotFather). ### .NET CLI @@ -61,7 +61,7 @@ Install-Package Telegrator ``` ### Hosting Integrations -- .NET Core >= 8.0 +- .NET Core >= 10.0 - `Telegrator.Hosting`: For console/background services - `Telegrator.Hosting.Web`: For ASP.NET Core/Webhook @@ -325,7 +325,7 @@ builder.Handlers.AddMethod(Option1Handler); ```csharp public enum UserState { - Start = SpecialState.NoState, + Start, WaitingForName, WaitingForAge } @@ -333,39 +333,40 @@ public enum UserState // Start conversation [CommandHandler] [CommandAlias("register")] -[EnumState(UserState.Start)] +[State(UserState.Start)] private static async Task StartRegistration(IHandlerContainer container, CancellationToken cancellationToken) { - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await container.Reply("Please enter your name:", cancellationToken: cancellationToken); return Ok; } // Handle name input [MessageHandler] -[EnumState(UserState.WaitingForName)] +[State(UserState.WaitingForName)] private static async Task HandleName(IHandlerContainer container, CancellationToken cancellationToken) { var name = container.Input.Text; - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await container.Reply($"Hello {name}! Please enter your age:", cancellationToken: cancellationToken); return Ok; } // Handle age input [MessageHandler] -[EnumState(UserState.WaitingForAge)] +[State(UserState.WaitingForAge)] private static async Task HandleAge(IHandlerContainer container, CancellationToken cancellationToken) { if (int.TryParse(container.Input.Text, out int age)) { - container.DeleteEnumState(); + StateStorage.GetStateMachine().BySenderId().Reset(); await container.Reply($"Registration complete! Name: {name}, Age: {age}", cancellationToken: cancellationToken); } else { await container.Reply("Please enter a valid age (number):", cancellationToken: cancellationToken); } + return Ok; } @@ -497,50 +498,43 @@ public class RestrictedHandler : MessageHandler ### 3.3. State Management -Telegrator provides built-in state management for multi-step conversations (wizards, forms, quizzes) without a database. +Telegrator provides built-in state management for multi-step conversations (wizards, forms, quizzes) with or without a database. > [!NOTE] -> Each type of `StateKeeper`'s (EnumStateKeeper, NumericStateKeeper) is shared between **EVERY** handler in project. - -**Types of State:** -- **NumericState**: Integer-based steps -- **StringState**: Named steps -- **EnumState**: Enum-based scenarios +> Each type of `StateKeeper`'s keys and states are shared between **EVERY** handler in project. **How to Use:** 1. Define your state (enum/int/string) 2. Use a state filter attribute on your handler: - - `[EnumState(MyEnum.Step1)]` - - `[NumericState(1)]` - - `[StringState("waiting_input")]` + - `[State(MyEnum.Step1)]` 3. Change state inside the handler using extension methods: - - `container.ForwardEnumState()` - - `container.ForwardNumericState()` - - `container.ForwardStringState()` - - `container.DeleteEnumState()` + - `StateStorage.GetStateMachine().BySenderId().Current()` + - `StateStorage.GetStateMachine().BySenderId().Advance()` + - `StateStorage.GetStateMachine().BySenderId().Retreat()` + - `StateStorage.GetStateMachine().BySenderId().Reset()` **Example:** ```csharp public enum QuizState { - Start = SpecialState.NoState, Q1, Q2 + Start, Q1, Q2 } [CommandHandler] [CommandAlias("quiz")] -[EnumState(QuizState.Start)] +[State(QuizState.Start)] public class StartQuizHandler : CommandHandler { public override async Task Execute(IHandlerContainer container, CancellationToken cancellation) { - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await Reply("Quiz started! Question 1: What is the capital of France?"); return Ok; } } [MessageHandler] -[EnumState(QuizState.Q1)] +[State(QuizState.Q1)] public class Q1Handler : MessageHandler { public override async Task Execute(IHandlerContainer container, CancellationToken cancellation) @@ -550,7 +544,7 @@ public class Q1Handler : MessageHandler else await Reply("Incorrect. The answer is Paris."); - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await Reply("Question 2: What is 2 + 2?"); return Ok; } @@ -559,8 +553,8 @@ public class Q1Handler : MessageHandler > **How is it working?** > 1. **Enum State Definition**: `QuizState` enum defines the conversation flow with `Start = SpecialState.NoState` indicating no initial state. -> 2. **State Filter**: `[EnumState(QuizState.Start)]` ensures the handler only runs when the user is in the "Start" state. -> 3. **State Transition**: `container.ForwardEnumState()` moves the user to the next state (Q1). +> 2. **State Filter**: `[State(QuizState.Start)]` ensures the handler only runs when the user is in the "Start" state. +> 3. **State Transition**: `StateStorage.GetStateMachine().BySenderId().Advance()` moves the user to the next state (Q1). > 4. **Next Handler**: The `Q1Handler` will only run when the user is in state `QuizState.Q1`. > 5. **State Management**: Each handler manages its own state transition, creating a clear conversation flow. @@ -1425,28 +1419,28 @@ public enum UserState // Start conversation [CommandHandler] [CommandAlias("register")] -[EnumState(UserState.Start)] +[State(UserState.Start)] private static async Task StartRegistration(IHandlerContainer container, CancellationToken cancellationToken) { - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await container.Reply("Please enter your name:", cancellationToken: cancellationToken); return Ok; } // Handle name input [MessageHandler] -[EnumState(UserState.WaitingForName)] +[State(UserState.WaitingForName)] private static async Task HandleName(IHandlerContainer container, CancellationToken cancellationToken) { var name = container.Input.Text; - container.ForwardEnumState(); + StateStorage.GetStateMachine().BySenderId().Advance(); await container.Reply($"Hello {name}! Please enter your age:", cancellationToken: cancellationToken); return Ok; } // Handle age input [MessageHandler] -[EnumState(UserState.WaitingForAge)] +[State(UserState.WaitingForAge)] private static async Task HandleAge(IHandlerContainer container, CancellationToken cancellationToken) { if (int.TryParse(container.Input.Text, out int age))