/// <summary> /// Create a Twitch chatbot. /// </summary> public ChatController(AuthInfo info) { var _state = _stateMachine = new StateMachine <State, Trigger>(State.SignedOff); _state.OnTransitioned((transition => { _log.DebugFormat("{0} => {1}", transition.Source.ToString("G"), transition.Destination.ToString("G")); })); _state.Configure(State.Conceived) .Permit(Trigger.DisconnectRequested, State.SignedOff); _state.Configure(State.SignedOff) .SubstateOf(State.Conceived) .OnEntry(() => Task.Run(() => Whisperer.Stop())) .OnEntry(() => Task.Run(() => Talker.Stop())) .Ignore(Trigger.ChatbotsUnready) .Permit(Trigger.ConnectRequested, State.Connecting); _state.Configure(State.Connecting) .SubstateOf(State.Conceived) .OnEntry(() => Task.Run(() => Whisperer.Start())) .OnEntry(() => Task.Run(() => Talker.Start())) .Ignore(Trigger.ConnectRequested) .Ignore(Trigger.ChatbotsUnready) .Permit(Trigger.ChatbotsReady, State.Ready); _state.Configure(State.Ready) .SubstateOf(State.Conceived) .Ignore(Trigger.ChatbotsReady) .OnEntry(() => Ready?.Invoke(this, EventArgs.Empty)) .OnExit(() => Unready?.Invoke(this, EventArgs.Empty)); Whisperer = new ChatBot(info, true); Whisperer.Ready += CheckBotStates; Whisperer.Unready += CheckBotStates; Talker = new ChatBot(info, false); Talker.Ready += CheckBotStates; Talker.Unready += CheckBotStates; }
/// <summary> /// Create a Twitch chatbot. /// </summary> public ChatBot(AuthInfo info, bool whisper, int reconnectTime = 3000) { WhisperClient = whisper; _joinedChannels = new HashSet <string>(); _authInfo = info; _shouldReconnect = reconnectTime > 0; if (_shouldReconnect) { _reconnectTimer = new Timer(reconnectTime); _reconnectTimer.Elapsed += (sender, args) => { _reconnectTimer.Stop(); _stateMachine.Fire(Trigger.ConnectRequested); }; } var _state = _stateMachine = new StateMachine <State, Trigger>(State.SignedOff); _state.OnTransitioned((transition => { _log.DebugFormat("{0} => {1}", transition.Source.ToString("G"), transition.Destination.ToString("G")); })); _state.Configure(State.Conceived) .Permit(Trigger.DisconnectRequested, State.SignedOff); _state.Configure(State.SignedOff) .SubstateOf(State.Conceived) .Ignore(Trigger.Disconnected) .OnEntryFrom(Trigger.AuthInvalid, () => InvalidCreds?.Invoke(this, EventArgs.Empty)) .PermitIf(Trigger.ConnectRequested, whisper ? State.TwitchGroupApi : State.Authenticating, () => _running); _state.Configure(State.RetryConnection) .SubstateOf(State.SignedOff) .OnExit(() => _reconnectTimer.Stop()) .OnEntry(() => _reconnectTimer.Start()) .PermitDynamic(Trigger.ConnectRequested, () => whisper ? State.TwitchGroupApi : State.Twitch); _state.Configure(State.TwitchGroupApi) .SubstateOf(State.Conceived) .OnEntry(CheckGroupApi) .Permit(Trigger.ApiCheckFailed, State.RetryConnection) .Permit(Trigger.GroupInfoReceived, State.Authenticating); _state.Configure(State.Twitch) .SubstateOf(State.Conceived) .Permit(Trigger.Connected, State.Authenticating) .PermitDynamic(Trigger.Disconnected, () => _shouldReconnect ? State.RetryConnection : State.SignedOff) .Permit(Trigger.AuthInvalid, State.SignedOff) .OnEntry(InitializeTwitchConnection) .OnExit(ReleaseTwitchConnection); _state.Configure(State.Authenticating) .SubstateOf(State.Twitch) .Permit(Trigger.SignedIn, State.Ready) .PermitReentry(Trigger.AuthRetry) .Permit(Trigger.AuthInvalid, State.SignedOff); _state.Configure(State.Ready) .SubstateOf(State.Twitch) .OnEntry(() => Ready?.Invoke(this, EventArgs.Empty)) .OnExit(() => Unready?.Invoke(this, EventArgs.Empty)); }