Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Event on connection lost #45

Open
dedmen opened this issue Jan 29, 2020 · 5 comments
Open

Feature: Event on connection lost #45

dedmen opened this issue Jan 29, 2020 · 5 comments

Comments

@dedmen
Copy link

dedmen commented Jan 29, 2020

I have the issue that my service monitoring my TS server is apparently loosing Query connection after hours/days.

Would be good to have a event to notify me of that, such that I can trigger a reconnect.

I think firing a event from here would work?:
https://github.com/nikeee/TeamSpeak3QueryAPI/blob/master/src/TeamSpeak3QueryApi/QueryClient.cs#L394

@realbadidas
Copy link

why not make a loop that checks if the bool function IsConnected() of TeamSpeakClient.Client is false?

@dedmen
Copy link
Author

dedmen commented Mar 19, 2020

why not make a loop that checks if the bool function IsConnected() of TeamSpeakClient.Client is false?

I tried that at first, didn't work.
Right now my workaround is to simply send "version" command on a 4 minute timer, to make sure it doesn't idle kick me.
That has ran flawlessly for weeks now.

@lgund
Copy link

lgund commented Jul 2, 2020

Hey @dedmen ,

there is a much smarter solution by just added the event. You just need to add your QueryClient.cs like this.

Adding the Eventhandler

    public class QueryClient : IDisposable
    {
        public EventHandler OnConnectionLost;

        /// <summary>Gets the remote host of the Query API client.</summary>
        /// <returns>The remote host of the Query API client.</returns>
        public string Host { get; }

Adding the firing method

After that you need to create the virtual method the fire the event. I´ve added this code before the constructors but it doesen´t matter where you add it.

        #region Events
        public virtual void EventConnectionLost(EventArgs e)
        {
            OnConnectionLost?.Invoke(this, e);
        }
        #endregion

Firing the method if the connection is lost

Now you just need to fire the method if the client lost the connection. That on line 407. There you just type EventConnectionLost(EventArgs.Empty);. But to be sure here is the whole class of ResponseProcessingLoop

        private CancellationTokenSource ResponseProcessingLoop()
        {
            var cts = _cts = new CancellationTokenSource();
            Task.Run(async () =>
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    string line = null;
                    try
                    {
                        line = await _reader.ReadLineAsync().WithCancellation(cts.Token).ConfigureAwait(false);
                    }
                    catch (OperationCanceledException)
                    {
                        break;
                    }

                    Debug.WriteLine(line);

                    if (line == null)
                    {
                        cts.Cancel();
                        continue;
                    }

                    if (string.IsNullOrWhiteSpace(line))
                        continue;

                    var s = line.Trim();

                    if (s.StartsWith("error", StringComparison.OrdinalIgnoreCase))
                    {
                        Debug.Assert(_currentCommand != null);

                        var error = ParseError(s);
                        _currentCommand.Error = error;
                        InvokeResponse(_currentCommand);
                    }
                    else if (s.StartsWith("notify", StringComparison.OrdinalIgnoreCase))
                    {
                        s = s.Remove(0, "notify".Length);
                        var not = ParseNotification(s);
                        InvokeNotification(not);
                    }
                    else
                    {
                        Debug.Assert(_currentCommand != null);
                        _currentCommand.RawResponse = s;
                        _currentCommand.ResponseDictionary = ParseResponse(s);
                    }
                }

                IsConnected = false;
                EventConnectionLost(EventArgs.Empty);

            });
            return cts;
        }

That´s it. Now you can easy check for a lost connection without traffic waste 👍 . Now to be fair here is my example how I check the connection.

Example

_client.Client.OnConnectionLost += async (sender, e) =>
{
    Log.Error($"Instance {Instance.Alias}: Verbindung zum Server verloren...");
    Log.Error($"Instance {Instance.Alias}: Verbindungsversuch wird in {TIME_TO_RETRY} erneut versucht...");
    await Task.Delay(TIME_TO_RETRY);
    _ = Connect();
};

I hope you can work with this :)

@dedmen
Copy link
Author

dedmen commented Jul 6, 2020

I hope you can work with this

Yeah thats exactly what I was requesting. Why not make a pull request and get it added to the library?

@lgund
Copy link

lgund commented Jul 6, 2020

I will make a pull request if I am finished with fixing all problems. There are also a problem if the user is banned. There will be no QueryExecaption casted. Currently in my project I added the whole source and not the package to develop live with the source. I just read this issue and create you fast fix 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants