TMI Cluster for Twitch Chatbots

Overview

TMI Cluster for Twitch Chatbots

Total Downloads Latest Stable Version License Discord

Introduction

TMI Cluster is a Laravel package that smoothly enables a highly scalable IRC client cluster for Twitch. TMI Cluster consists of multiple supervisors that can be deployed on multiple hosts. The core is inspired by Horizon, which handles the complex IRC process management.

The cluster stores its data in the database and has a Redis Command Queue to send IRC commands and receive messages.

Features

  • Supervisor can be deployed on multiple servers
  • Up-to-date Twitch IRC Client written in PHP 7.4
  • Scalable message input/output queue
  • Advanced cluster status dashboard
  • Channel management and invite screen

PHP Twitch Messaging Interface

The TMI Cluster is powered by the PHP Twitch Messaging Interface client to communicate with Twitch. It's a full featured, high performance Twitch IRC client written in PHP 7.4.

Official Documentation

You can view our official documentation here.

Comments
  • PHP 8.1 - Implement __serialize() and __unserialize()

    PHP 8.1 - Implement __serialize() and __unserialize()

    TMI Cluster: 3.0.8 PHP: 8.1

    --

    LOGS

    [2022-11-18 00:07:41] [51273e78] PHP Deprecated: GhostZero\Tmi\Events\Twitch\NoticeEvent implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /home/forge/example.com/vendor/ghostzero/tmi/src/Events/Twitch/NoticeEvent.php on line 8 PHP Deprecated: GhostZero\Tmi\Events\Twitch\ModsEvent implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /home/forge/example.com/vendor/ghostzero/tmi/src/Events/Twitch/ModsEvent.php on line 8

    [2022-11-18 00:11:22] [51273e78] PHP Deprecated: GhostZero\Tmi\Events\Irc\PingEvent implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /home/forge/example.com/vendor/ghostzero/tmi/src/Events/Irc/PingEvent.php on line 14

    [2022-11-18 00:16:13] [51273e78] PHP Deprecated: GhostZero\Tmi\Events\Irc\PartEvent implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in /home/forge/example.com/vendor/ghostzero/tmi/src/Events/Irc/PartEvent.php on line 12

    opened by pcboii 1
  • Allowed memory size of 134217728 bytes exhausted (tried to allocate 8388616 bytes)

    Allowed memory size of 134217728 bytes exhausted (tried to allocate 8388616 bytes)

    [2022-10-18 19:39:38] [94ca50d9] Register cleanup loop for every 530 sec.
    [2022-10-18 19:39:40] [94ca50d9] TMI Cluster Client getting evacuated with status code 5...
    Channel Distributor: 0 locked channels got unlocked for re-join.
    TMI Cluster Client evacuated! Migrated: 0
    Got exit signal with code 5
    [2022-10-18 19:39:46] Unable to acquire flush stale lock...
    [2022-10-18 19:39:50] Reconnecting 93212 disconnected channels...
    [2022-10-18 19:40:22] #0 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(719): Illuminate\Database\Connection->runQueryCallback('update `tmi_clu...', Array, Object(Closure))
    #1 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(576): Illuminate\Database\Connection->run('update `tmi_clu...', Array, Object(Closure))
    #2 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Connection.php(509): Illuminate\Database\Connection->affectingStatement('update `tmi_clu...', Array)
    #3 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php(3281): Illuminate\Database\Connection->update('update `tmi_clu...', Array)
    #4 /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php(999): Illuminate\Database\Query\Builder->update(Array)
    #5 /var/www/html/vendor/ghostzero/tmi-cluster/src/Repositories/DatabaseChannelManager.php(61): Illuminate\Database\Eloquent\Builder->update(Array)
    #6 /var/www/html/vendor/ghostzero/tmi-cluster/src/Repositories/RedisChannelDistributor.php(56): GhostZero\TmiCluster\Repositories\DatabaseChannelManager->acknowledged(Array)
    #7 /var/www/html/vendor/ghostzero/tmi-cluster/src/Repositories/RedisChannelDistributor.php(70): GhostZero\TmiCluster\Repositories\RedisChannelDistributor->joinNow(Array, Array, false)
    #8 /var/www/html/vendor/ghostzero/tmi-cluster/src/Repositories/SupervisorRepository.php(61): GhostZero\TmiCluster\Repositories\RedisChannelDistributor->flushStale(Array, Array)
    #9 /var/www/html/vendor/ghostzero/tmi-cluster/src/AutoScale.php(78): GhostZero\TmiCluster\Repositories\SupervisorRepository->flushStale()
    #10 /var/www/html/vendor/ghostzero/tmi-cluster/src/AutoScale.php(64): GhostZero\TmiCluster\AutoScale->releaseStaleSupervisors(Object(GhostZero\TmiCluster\Supervisor))
    #11 /var/www/html/vendor/ghostzero/tmi-cluster/src/Supervisor.php(107): GhostZero\TmiCluster\AutoScale->scale(Object(GhostZero\TmiCluster\Supervisor))
    #12 /var/www/html/vendor/ghostzero/tmi-cluster/src/Supervisor.php(78): GhostZero\TmiCluster\Supervisor->autoScale()
    #13 /var/www/html/vendor/ghostzero/tmi-cluster/src/Supervisor.php(53): GhostZero\TmiCluster\Supervisor->loop()
    #14 /var/www/html/vendor/ghostzero/tmi-cluster/src/Commands/TmiClusterCommand.php(90): GhostZero\TmiCluster\Supervisor->monitor()
    #15 /var/www/html/vendor/ghostzero/tmi-cluster/src/Commands/TmiClusterCommand.php(57): GhostZero\TmiCluster\Commands\TmiClusterCommand->start(Object(GhostZero\TmiCluster\Supervisor))
    #16 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): GhostZero\TmiCluster\Commands\TmiClusterCommand->handle()
    #17 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
    #18 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
    #19 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
    #20 /var/www/html/vendor/laravel/framework/src/Illuminate/Container/Container.php(651): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
    #21 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(136): Illuminate\Container\Container->call(Array)
    #22 /var/www/html/vendor/symfony/console/Command/Command.php(308): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
    #23 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Command.php(121): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
    #24 /var/www/html/vendor/symfony/console/Application.php(998): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #25 /var/www/html/vendor/symfony/console/Application.php(299): Symfony\Component\Console\Application->doRunCommand(Object(GhostZero\TmiCluster\Commands\TmiClusterCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #26 /var/www/html/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #27 /var/www/html/vendor/laravel/framework/src/Illuminate/Console/Application.php(102): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #28 /var/www/html/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(129): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #29 /var/www/html/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
    #30 {main}
    
    In Arr.php line 565:
                                                                                   
      Allowed memory size of 134217728 bytes exhausted (tried to allocate 8388616 bytes)                                                                      
                    
    
    opened by ghostzero 1
  • Add license scan report and status

    Add license scan report and status

    Your FOSSA integration was successful! Attached in this PR is a badge and license report to track scan status in your README.

    Below are docs for integrating FOSSA license checks into your CI:

    opened by fossabot 1
  • Install documentation

    Install documentation

    Currently, there is no documentation how to install and us the TMI cluster. This can be resolved with an getting started within the readme or wiki.

    • Explain how to install
    • Explain how to use supervisors (start, stop, supervisor evacuation)
    • Explain how to use the TMI Event's
    documentation help wanted good first issue 
    opened by ghostzero 1
  • Graceful shutdown

    Graceful shutdown

    Currently the irc processes do not gracefully shutdown. This means, that all current connected channels will not be migrated to other instances within a low time-frame. This means, all channels will be only collected if our purge system is collecting stale processes and supervisors. But this will take ~30 seconds.

    enhancement 
    opened by ghostzero 1
  • Add channel manager & invite screen

    Add channel manager & invite screen

    image

    This PR will do some fancy improvements. I added the following changes:

    • [x] Prefix all tables with tmi_cluster_ eg. tmi_cluster_channels.
    • [x] Add channel manager to authorize or revokeAuthorization a channel to join the cluster.
    • [x] Add invite screen to faster kick-off new chatbots.
    • [x] Change route registration. So we're now more flexible.
    • [x] Rewrite the auto-part mechanism.
    • [x] Add command to terminate a given supervisor.
    • [x] Add command flag to authorize channel on join.
    • [x] Add command to de-/authorize channels.
    • [x] Only send messages to authorized channels.
    • [x] Update and publish the new documentation.
    • [x] Update phpunit tests.

    The new documentation is available at: https://tmiphp.com/docs/tmi-cluster.html

    opened by ghostzero 0
  • Bump elliptic from 6.5.3 to 6.5.4

    Bump elliptic from 6.5.3 to 6.5.4

    Bumps elliptic from 6.5.3 to 6.5.4.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Load balance channels per supervisor

    Load balance channels per supervisor

    Currently there is no load balancing at supervisor level. However, this would prevent too many channels on one process.

    The join process also enters some channels twice. This must be prevented Then you can also switch off the auto-cleanup (which ensures that 24/7 channels are sometimes removed).

    bug enhancement 
    opened by ghostzero 0
  • Start supervisor with average supervisor scale

    Start supervisor with average supervisor scale

    It would be helpful if when starting a supervisor the current scale size of the cluster is directly taken into account. For example, if the initial scale is 5, or 15, but currently 10 is needed on average.

    This would scale new supervisors directly in the correct size.

    enhancement 
    opened by ghostzero 0
  • array_merge(): Argument #2 must be of type array, stdClass given

    array_merge(): Argument #2 must be of type array, stdClass given

    2-12-20 14:36:09] [d7eded7e] TMI Cluster Client getting evacuated with statu                                                                                                                    s code 5...
    Channel Distributor: 0 locked channels got unlocked for re-join.
    TMI Cluster Client evacuated! Migrated: 0
    Got exit signal with code 5
    [2022-12-20 14:36:09] [a300d9ec] Register cleanup loop for every 403 sec.
    [2022-12-20 14:36:10] [d7eded7e] Register cleanup loop for every 646 sec.
    [2022-12-20 14:36:14] array_merge(): Argument #2 must be of type array, stdClass                                                                                                                     given
    [2022-12-20 14:36:14] #0 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Support                                                                                                                    /Arr.php(31): array_merge()
    #1 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Repositories/RedisChannelDist                                                                                                                    ributor.php(54): GhostZero\TmiCluster\Support\Arr::unique()
    #2 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Repositories/RedisChannelDist                                                                                                                    ributor.php(70): GhostZero\TmiCluster\Repositories\RedisChannelDistributor->join                                                                                                                    Now()
    #3 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Repositories/SupervisorReposi                                                                                                                    tory.php(61): GhostZero\TmiCluster\Repositories\RedisChannelDistributor->flushSt                                                                                                                    ale()
    #4 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/AutoScale.php(79): GhostZero\                                                                                                                    TmiCluster\Repositories\SupervisorRepository->flushStale()
    #5 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/AutoScale.php(64): GhostZero\                                                                                                                    TmiCluster\AutoScale->releaseStaleSupervisors()
    #6 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Supervisor.php(107): GhostZer                                                                                                                    o\TmiCluster\AutoScale->scale()
    #7 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Supervisor.php(78): GhostZero                                                                                                                    \TmiCluster\Supervisor->autoScale()
    #8 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Supervisor.php(53): GhostZero                                                                                                                    \TmiCluster\Supervisor->loop()
    #9 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Commands/TmiClusterCommand.ph                                                                                                                    p(90): GhostZero\TmiCluster\Supervisor->monitor()
    #10 /var/www/waifu/vendor/ghostzero/tmi-cluster/src/Commands/TmiClusterCommand.p                                                                                                                    hp(57): GhostZero\TmiCluster\Commands\TmiClusterCommand->start()
    #11 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Container/BoundMethod                                                                                                                    .php(36): GhostZero\TmiCluster\Commands\TmiClusterCommand->handle()
    #12 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Container/Util.php(40                                                                                                                    ): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
    #13 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Container/BoundMethod                                                                                                                    .php(93): Illuminate\Container\Util::unwrapIfClosure()
    #14 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Container/BoundMethod                                                                                                                    .php(37): Illuminate\Container\BoundMethod::callBoundMethod()
    #15 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Container/Container.p                                                                                                                    hp(653): Illuminate\Container\BoundMethod::call()
    #16 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Console/Command.php(1                                                                                                                    36): Illuminate\Container\Container->call()
    #17 /var/www/waifu/vendor/symfony/console/Command/Command.php(298): Illuminate\C                                                                                                                    onsole\Command->execute()
    #18 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Console/Command.php(1                                                                                                                    21): Symfony\Component\Console\Command\Command->run()
    #19 /var/www/waifu/vendor/symfony/console/Application.php(1015): Illuminate\Cons                                                                                                                    ole\Command->run()
    #20 /var/www/waifu/vendor/symfony/console/Application.php(299): Symfony\Componen                                                                                                                    t\Console\Application->doRunCommand()
    #21 /var/www/waifu/vendor/symfony/console/Application.php(171): Symfony\Componen                                                                                                                    t\Console\Application->doRun()
    #22 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Console/Application.p                                                                                                                    hp(94): Symfony\Component\Console\Application->run()
    #23 /var/www/waifu/vendor/laravel/framework/src/Illuminate/Foundation/Console/Ke                                                                                                                    rnel.php(129): Illuminate\Console\Application->run()
    #24 /var/www/waifu/artisan(37): Illuminate\Foundation\Console\Kernel->handle()
    #25 {main}
    [2022-12-20 14:36:29] Reconnecting 654 disconnected channels...
    [2022-12-20 14:36:36] Scale out: 10
    [2022-12-20 14:36:37] Scale out: 11
    [2022-12-20 14:36:37] [edf2b530] Register cleanup loop for
    
    opened by ghostzero 0
  • Proof of Concept - Multi-Tenancy

    Proof of Concept - Multi-Tenancy

    Motivation

    I have now received feedback from several people that users should be able to change the bot username.

    ETA: The plan is to start this proof of concept in Q2/Q3 2022.

    Task

    In the first prove of concept I would suggest to implement it like this:

    • The chabot will still enter the chat as a default bot account (eg. bot_username).
    • Messages will be sent with the specified bot account (eg. streamer_username).
    • By default the TMI-Cluster will still continue to use the default bot account.
    • It is only possible to define one bot account per channel.

    Background of POC

    Adding another bot account as a listener of chat messages puts a considerable load on the TMI cluster in terms of resources. Therefore, I suggest that the chatbot continues to join the channels with the current default bot account so that this problem is migrated.

    In other words: Users only recognize that, for example, bot_username is in the chat, but will reply with streamer_username.

    Updated Documentation

    Sending Messages via TMI-Cluster

    You can send a message within the laravel ecosystem at any time, you don't even need to have the TMI cluster connected in the target chat. The messages are processed async via the TMI cluster queue. You can define the bot_id attribute within the ChannelManager to override the message sender.

    use GhostZero\TmiCluster\Facades\TmiCluster;
    
    TmiCluster::sendMessage('ghostzero', 'Hello World!');
    

    Current Documentation: https://tmiphp.com/docs/tmi-cluster.html#sending-messages-via-tmi-cluster

    enhancement help wanted 
    opened by ghostzero 0
Releases(3.0.8)
Owner
René Preuß
Twitch B2B Developer
René Preuß
Magento2 + Varnish + PHP7 + Redis + SSL (cluster ready)

Docker Magento2: Varnish + PHP7 + Redis + SSL cluster ready docker-compose infrastructure Infrastructure overview Container 1: MariaDB Container 2: Re

Fabrizio Balliano 332 Dec 30, 2022
Proxy based Redis cluster solution supporting pipeline and scaling dynamically

Codis is a proxy based high performance Redis cluster solution written in Go. It is production-ready and widely used at wandoujia.com and many compani

null 12.7k Jan 2, 2023
A pocketmine-mp server that we develop live on Twitch every Saturday from 8pm to 10pm (FR)

Server A pocketmine-mp server that we develop live on Twitch every Saturday from 8pm to 10pm (FR) Contributing Pull requests are welcome. For major ch

Gaëtan H 11 Oct 9, 2022
Laravel Thermite is an extended PostgreSQL Laravel database driver to connect to a CockroachDB cluster.

Laravel Thermite Laravel Thermite is an extended PostgreSQL Laravel database driver to connect to a CockroachDB cluster. ?? Supporting If you are usin

Renoki Co. 9 Nov 15, 2022
Twitch Helix API PHP Wrapper for Laravel

Laravel Twitch PHP Twitch Helix API Wrapper for Laravel 5+ ⚠️ Changes on May 01, 2020 Since May 01, 2020, Twitch requires all requests to contain a va

Roman Zipp 87 Dec 7, 2022
Twitch IRC Bots in PHP \o/

laravel-twitch-irc Twitch IRC Bot for laravel applications. This ships with the ability to create custom commands for your bot, with aliases, cooldown

Sam Parton 4 Nov 7, 2022
Magento2 + Varnish + PHP7 + Redis + SSL (cluster ready)

Docker Magento2: Varnish + PHP7 + Redis + SSL cluster ready docker-compose infrastructure Infrastructure overview Container 1: MariaDB Container 2: Re

Fabrizio Balliano 332 Dec 30, 2022
Proxy based Redis cluster solution supporting pipeline and scaling dynamically

Codis is a proxy based high performance Redis cluster solution written in Go. It is production-ready and widely used at wandoujia.com and many compani

null 12.7k Jan 2, 2023