Wolfringo Wolfringo
Wolfringo Wolfringo
Wolfringo (c) 2020 TehGM
DocFX, DiscordFX theme.
Search Results for

    Wolfringo v2.0

    Wolfringo 2.0 brought some significant changes - most notably introduction of WolfClient and CommandsService builders, separation of cache and client logic, help commands support. Command requirements also got a little overhaul. And of course, it also includes numerous smaller changes.

    WolfClient and CommandsService builders

    In previous versions of Wolfringo, creating WolfClient and CommandsService could get a bit confusing due to the requirement of manual service collection populating. To address this, Wolfringo 2.0 introduces WolfClientBuilder and CommandsServiceBuilder.

    Note: the most commonly used constructors for WolfClient and CommandsService are now marked as obsolete, and will be removed in future versions. More complex constructors were removed completely, and need to be replaces with builders.

    WolfClientBuilder

    Creating WolfClient with logging enabled looked like this:

    ILoggerFactory logFactory = CreateLoggerFactory();
    IServiceCollection services = new ServiceCollection()
        .AddSingleton<ILoggerFactory>(logFactory);
    
    _client = new WolfClient(logFactory.CreateLogger<WolfClient>()); 
    _client.AddMessageListener<WelcomeEvent>(OnWelcome);
    

    Now to do the same, create your WolfClient as follows:

    _client = new WolfClientBuilder()
        .WithLogging(CreateLoggerFactory())
        .Build();
    _client.AddMessageListener<WelcomeEvent>(OnWelcome);
    

    CommandsServiceBuilder

    Creating Commands Service now works similar:

    CommandsService commands = new CommandsServiceBuilder()
        .WithLogging(CreateLoggerFactory())
        .WithWolfClient(_client)
        .WithPrefix("!")
        .Build();
    await commands.StartAsync();
    

    Now you can also add commands directly to WolfClientBuilder - this way, client and its logging will be automatically added, and StartAsync() called for you!

    _client = new WolfClientBuilder()
        .WithLogging(CreateLoggerFactory())
        .WithCommands(commands =>
        {
            commands.WithPrefix("!");
        })
        .Build();
    

    Additional services

    There are 2 ways of adding additional services for Dependency Injection purposes.

    • The most common one is using WithSingletonService (on CommandsServiceBuilder) or WithService (on WolfClientBuilder) methods that will register the service with the collection.
    • Alternatively, both CommandsServiceBuilder and WolfClientBuilder can optionally take IServiceCollection through their constructor.

    Commands Changes

    Building Help Command

    Help commands are a common need in bots, and Wolfringo now has features that make creating them much easier. See Help Command Guide to learn more.

    If you already have a custom help command, you can upgrade it easily, but don't worry - it's not required! Help Command feature is opt-in, and your existing help command will work just fine!

    Getting Raw Arguments Text

    Previously, to get raw text of command arguments, you could use 2 approaches, both of which had issues:

    • Get Message Text - required you to manually remove prefix and command name.
    • Use string[] as argument - included all parsed arguments, but they were missing grouping characters, such as parentheses.

    Now there's a better way. You can simply mark a string argument with [ArgumentsText] attribute. See Arguments in Wolfringo Commands for an example and more info.

    Recipient info in Error Messages

    [MissingError] attribute and [ConvertingError] attribute now support {{RecipientID}} and {{RecipientName}} placeholders - they'll be replaced with bot's ID/nickname for private messages and group's ID/name for group messages.

    Getting Command Options

    Previously getting command options for given command would require manually checking attributes and global options instance.

    Since Wolfringo 2.0, you can inject a new ICommandOptions interface to your command method. This options instance will contain the actual prefix etc values for given command.

    Skipping Commands

    Wolfringo Commands System no longer has a strict rule that one message received = only one command handler attempted. Command execution now can be skipped, making CommandsService attempt to try another command. This is opt-in, so unless you start using this feature, your commands will function just like they did before.

    To do so, either return Task<ICommandResult> or ICommandResult with status of Skip in your command, or tell the requirement attribute to skip on failure. See Skipping using Requirements and Skipping using return value for more information.

    Command Timeouts

    Commands execution now times out after 1 day by default. This is a huge timeout, and isn't infinite only to help prevent any memory leaks. You can however specify timeout for both Standard and Regex commands by using Timeout property.

    In order to use the timeout, inject @System.Threading.CancellationToken into your command method, and use it in async calls. Alternatively you can also call ThrowIfCancellationRequested method.

    [Command("timeout", Timeout = 1000)]
    public async Task CmdTimeoutAsync(CancellationToken cancellationToken)
    {
        // simulate long running task
        await Task.Delay(1500, cancellationToken);
    
        // check timeout
        cancellationToken.ThrowIfCancellationRequested();
    
        // oops! This will time out!
        Console.WriteLine("This will never be written to console, because long-running task takes longer than Timeout!");
    }
    

    Regex commands also support a separate timeout value which is then provided to Regex Engine. This exists to prevent user attacks exploiting complex regexes in your commands. Default value is 1000ms which should be generous enough for most regexes, but if you wish to change it, you can use RegexTimeout property.

    Note

    Note that values of both Timeout and RegexTimeout properties are specified in milliseconds. So for 1 second timeout, set the value to 1000.

    Command Requirement changes

    If you created custom command requirements, you'll need to change the return type of CheckAsync method from Task<bool> to Task<ICommandResult>.

    ICommandResult changes

    If you used ICommandResult for any purpose in your bot, there are a few changes that you should be aware of:

    • IsSuccess is now obsolete and will be removed in later Wolfringo version.
    • Status property has been added instead.
    • Exception property has been removed. Wolfringo Commands System will simply throw exceptions now.
    • To support above changes, previous constructors of built-in result implementations have been replaced with new ones.
    • Built-in result implementations have been changed from struct to class.

    Achievement changes

    Group Achievements

    Group achievements are now supported. Yay!

    Sender now has a GetGroupAchievementsAsync method for it. UserAchievementListResponse has also been replaced with EntityAchievementListResponse.

    Nullable received times

    WOLF server now can report achievement with null receive date. For this reason GetUserAchievementsAsync return type has changed slightly, and you'll need to update your variable types.

    // old way:
    IReadOnlyDictionary<WolfAchievement, DateTime> achievements = await _client.GetUserAchievementsAsync(2644384, WolfLanguage.English);
    // new way:
    IReadOnlyDictionary<WolfAchievement, DateTime?> achievements = await _client.GetUserAchievementsAsync(2644384, WolfLanguage.English);
    

    Caching Configuration

    Caching and WolfClient have been separated in Wolfringo 2.0. This means that you can implement your own cache and add it using Dependency Injection.

    If you didn't disable caching, you'll notice no change at all.
    However, if you were disabling cache or its parts, you'll need to make a few adjustments.

    • Without Wolfringo.Hosting (Normal Bot)
    • With Wolfringo.Hosting (.NET Generic Host/ASP.NET Core)

    Properties for enabling and disabling caching have been removed from WolfClient. Instead, you can configure caching using WolfClientBuilder:

    _client = new WolfClientBuilder()
        .WithDefaultCaching(new WolfCacheOptions()
        {
            // set to false to disable
            options.UsersCachingEnabled = true;
            options.GroupsCachingEnabled = true;
            options.CharmsCachingEnabled = true;
            options.AchievementsCachingEnabled = true;
        })
        .Build();
    

    WolfCacheOptions is present in TehGM.Wolfringo.Caching namespace.

    Properties for enabling and disabling caching have been removed from HostedWolfClientOptions and moved to a new @TehGM.Wolfringo.Utilities.WolfCacheOptions class.

    If you used providers configuration (like from appsettings.json file), you need to configure the new options type.

    services.Configure<HostedWolfClientOptions>(context.Configuration.GetSection("WolfClient"));
    services.Configure<WolfCacheOptions>(context.Configuration.GetSection("WolfClient"));
    

    Alternatively, you can use a new hosted client builder method ConfigureCaching:

    services.AddWolfClient()
        // ... other configuration ...
        .ConfigureCaching(options =>
        {
            // set to false to disable
            options.UsersCachingEnabled = true;
            options.GroupsCachingEnabled = true;
            options.CharmsCachingEnabled = true;
            options.AchievementsCachingEnabled = true;
        });
    

    WolfClient defaults

    DefaultServerURL, BetaServerURL and DefaultDevice constants have been moved from WolfClient to WolfClientOptions.

    Ignoring Own Messages

    WolfClient will still ignore its own messages by default, but if you used to disable this feature, you'll find that IgnoreOwnChatMessages property is now read-only. To change it, you need to use WolfClientOptions class.

    _client = new WolfClientBuilder()
        .ConfigureOptions(options =>
        {
            // set to false to disable
            options.IgnoreOwnChatMessages = true;
        })
        .Build();
    

    Removed ServiceProvider classes

    SimpleServiceProvider and CombinedServiceProvider classes were used internally to help with fallback when library user didn't provide some required services. This is now handled by builders which use framework-provided @Microsoft.Extensions.DependencyInjection.IServiceCollection and @System.IServiceProvider, so both SimpleServiceProvider and CombinedServiceProvider were removed.

    If you used these classes, you'll need to remove references to them, and replace either with framework-provided solutions, or create your own implementations.

    Other changes

    There also has been a large number of smaller changes that shouldn't affect most people unless they're Customizing Wolfringo. Please refer to changelog and pull request on GitHub for more details.