frankvHoof93 / TikTokLiveSharp

Port of TikTok live library for C#
https://vanhoof.dev
Other
139 stars 27 forks source link

Dotnet add RunAsync method #75

Closed MaxRodin closed 2 months ago

MaxRodin commented 2 months ago

This adds a RunAsync method, which is an asynchronous overload of TikTokBaseClient.Run. It also adds an --async flag to the test application for testing.

Many method calls within Run were already asynchronous, so the new method just awaits them instead calling Task.Run.

This allows a parent application more control over the threads of the TikTokLiveClient. For example, you can now pause threads while the client waits for the OnConnected event to fire, instead of relying solely on the events themselves.

frankvHoof93 commented 2 months ago

Not really sure why you'd want to pause the Run-Task anyways?

A better way to add more control over the threads would probably be to make the polling- & running-tasks protected (so users can make a subclass of TTLBase/TTLLiveClient if they want direct access to them.

Could you elaborate more on the purpose? What do you mean by 'pausing threads while the client waits for the OnConnected-event to fire'? Since the thread itself is what will be firing the OnConnected-event..

MaxRodin commented 2 months ago

Hi, thanks for the response.

That was a poor explanation on my part, so I apologize. I couldn't recreate whatever issue I thought I was having, so I must have confused something along the way. Please forget the part about "pausing while waiting for OnConnected to fire" lol

I do think it's a worthwhile implementation though. Personally, executing Run as an asynchronous method made it easier for me to follow certain coding patterns (like using an intermediary event channel) and abstract things out. Here's my specific use case:

static async Task Main(string[] args)
    {
        // Build map of gift names to key codes
        var giftKeyMap = new Dictionary<string, VirtualKeyCode>
        {
            {"Rose", VirtualKeyCode.VK_1},
            {"Heart Me", VirtualKeyCode.VK_2},
            {"Team Bracelet", VirtualKeyCode.VK_3},
            {"Star", VirtualKeyCode.VK_4},
        };

        // Get hostname.
        string hostName = args[0];

        // Set target process.
        var targetProcessName = "notepad.exe";

        // Create client object and connect.
        var client = new TikTokLiveClient(hostName, 5f);
        var runTask = client.RunAsync(new CancellationToken());

        // Create keyboard.
        var inputSim = new InputSimulator();

        // Create input channel
        var inputChannel = new MyInputChannel(); // Provides a new set of events

        // Subscribe input controller and tiktoklive client to InputChannel.
        var inputController = new InputController(inputSim, giftKeyMap, inputChannel, targetProcessName); // Listens to the input channel for input.
        var tikTokLiveInputManager = new TikTokLiveInputManager(client, inputChannel); // Sends to signals input channel.

        await runTask;
    }

In the above example, I'm mapping a gift to a key on the keyboard. The code above essentially wraps the TikTokLiveClient events so they (and potentially other streaming APIs) interface with my app more easily.

I could write a method that does a simple dictionary lookup on giftKeyMap and presses the associated key - and then subscribe that method directly to TiKTokLiveClient.OnGift. But after a certain point I was struggling to keep code clean. Between decoupling and fleshing things out, I found myself wanting control of the main thread. Adding the RunAsync method was the cleanest solution I could come up with for personal use, so I thought I'd share

frankvHoof93 commented 2 months ago

merged into dev. Will go out with next release.