/// <summary>Creates a new client. A client can manage one connection to a server.</summary> /// <param name="dispatcherType">The message processing method for incomming notifications. /// See <see cref="EventDispatchType"/> for further information about each type.</param> public Ts3FullClient() { status = Ts3ClientStatus.Disconnected; msgProc = new AsyncMessageProcessor(MessageHelper.GetToClientNotificationType); context = new ConnectionContext { WasExit = true }; }
private void ProcessInitServer(InitServer initServer) { packetHandler.ClientId = initServer.ClientId; lock (statusLock) status = Ts3ClientStatus.Connected; OnConnected?.Invoke(this, EventArgs.Empty); }
private void ProcessInitServer(InitServer initServer) { packetHandler.ClientId = initServer.ClientId; packetHandler.ReceiveInitAck(); lock (statusLock) status = Ts3ClientStatus.Connected; OnConnected?.Invoke(this, new EventArgs()); }
/// <summary>Creates a new client. A client can manage one connection to a server.</summary> /// <param name="dispatcherType">The message processing method for incomming notifications. /// See <see cref="EventDispatchType"/> for further information about each type.</param> public Ts3FullClient(EventDispatchType dispatcherType) { status = Ts3ClientStatus.Disconnected; ts3Crypt = new Ts3Crypt(); packetHandler = new PacketHandler(ts3Crypt); msgProc = new MessageProcessor(false); dispatcher = EventDispatcherHelper.Create(dispatcherType); wasExit = true; }
private void NetworkLoop() { while (true) { lock (statusLock) { if (wasExit) { break; } } if (wasExit) { break; } IncomingPacket packet = packetHandler.FetchPacket(); if (packet == null) { break; } switch (packet.PacketType) { case PacketType.Command: case PacketType.CommandLow: string message = Util.Encoder.GetString(packet.Data, 0, packet.Data.Length); var result = msgProc.PushMessage(message); if (result.HasValue) { dispatcher.Invoke(result.Value); } break; case PacketType.Voice: case PacketType.VoiceWhisper: // VOICE break; case PacketType.Init1: var forwardData = ts3Crypt.ProcessInit1(packet.Data); if (forwardData == null) { break; } packetHandler.AddOutgoingPacket(forwardData, PacketType.Init1); break; } } lock (statusLock) { status = Ts3ClientStatus.Disconnected; DisconnectInternal(); } }
/// <summary>Creates a new client. A client can manage one connection to a server.</summary> /// <param name="dispatcherType">The message processing method for incomming notifications. /// See <see cref="EventDispatchType"/> for further information about each type.</param> public Ts3FullClient(EventDispatchType dispatcherType) { status = Ts3ClientStatus.Disconnected; ts3Crypt = new Ts3Crypt(); packetHandler = new PacketHandler(ts3Crypt); msgProc = new AsyncMessageProcessor(); dispatcher = EventDispatcherHelper.Create(dispatcherType); context = new ConnectionContext { WasExit = true }; }
private void DisconnectInternal(bool manualLock = false, bool triggerEvent = true) { if (wasExit) { return; } if (!manualLock) { Monitor.Enter(StatusLock); } try { switch (Status) { case Ts3ClientStatus.Disconnected: if (!wasExit) { wasExit = true; packetHandler.Stop(); msgProc.DropQueue(); dispatcher.Dispose(); if (triggerEvent) { OnDisconnected?.Invoke(this, new DisconnectEventArgs(packetHandler.ExitReason ?? MoveReason.LeftServer)); } } break; case Ts3ClientStatus.Disconnecting: break; case Ts3ClientStatus.Connected: ClientDisconnect(MoveReason.LeftServer, QuitMessage); Status = Ts3ClientStatus.Disconnecting; break; case Ts3ClientStatus.Connecting: break; default: break; } } finally { if (!manualLock) { Monitor.Exit(StatusLock); } } }
private void DisconnectInternal(ConnectionContext ctx, CommandError error = null, Ts3ClientStatus?setStatus = null) { bool triggerEventSafe = false; lock (statusLock) { Log.Debug("DisconnectInternal wasExit:{0} error:{1} oldStatus:{2} newStatus:{3}", ctx.WasExit, error?.ErrorFormat(), status, setStatus); if (setStatus.HasValue) { status = setStatus.Value; } if (ctx.WasExit) { return; } switch (status) { case Ts3ClientStatus.Connecting: case Ts3ClientStatus.Disconnected: ctx.WasExit = true; packetHandler.Stop(); msgProc.DropQueue(); dispatcher.Dispose(); dispatcher = null; triggerEventSafe = true; break; case Ts3ClientStatus.Disconnecting: break; case Ts3ClientStatus.Connected: ClientDisconnect(Reason.LeftServer, QuitMessage); status = Ts3ClientStatus.Disconnecting; break; default: throw Util.UnhandledDefault(status); } } if (triggerEventSafe) { OnDisconnected?.Invoke(this, new DisconnectEventArgs(ctx.ExitReason ?? Reason.LeftServer, error)); } }
/// <summary>Tries to connect to a server.</summary> /// <param name="conData">Set the connection information properties as needed. /// For further details about each setting see the respective property documentation in <see cref="ConnectionData"/></param> /// <exception cref="ArgumentException">When some required values are not set or invalid.</exception> /// <exception cref="Ts3Exception">When the connection could not be established.</exception> public override void Connect(ConnectionData conData) { if (!(conData is ConnectionDataFull conDataFull)) { throw new ArgumentException($"Use the {nameof(ConnectionDataFull)} derivative to connect with the full client.", nameof(conData)); } if (conDataFull.Identity is null) { throw new ArgumentNullException(nameof(conDataFull.Identity)); } if (conDataFull.VersionSign is null) { throw new ArgumentNullException(nameof(conDataFull.VersionSign)); } connectionDataFull = conDataFull; ConnectionData = conData; Disconnect(); if (!TsDnsResolver.TryResolve(conData.Address, out remoteAddress)) { throw new Ts3Exception("Could not read or resolve address."); } lock (statusLock) { returnCode = 0; status = Ts3ClientStatus.Connecting; VersionSign = conDataFull.VersionSign; ts3Crypt = new Ts3Crypt(); ts3Crypt.Identity = conDataFull.Identity; var ctx = new ConnectionContext { WasExit = false }; context = ctx; packetHandler = new PacketHandler <S2C, C2S>(ts3Crypt, conData.LogId); packetHandler.PacketEvent = (ref Packet <S2C> packet) => { PacketEvent(ctx, ref packet); }; packetHandler.StopEvent = (closeReason) => { ctx.ExitReason = closeReason; DisconnectInternal(ctx, setStatus: Ts3ClientStatus.Disconnected); }; packetHandler.Connect(remoteAddress); dispatcher = new ExtraThreadEventDispatcher(); dispatcher.Init(InvokeEvent, conData.LogId); } }
/// <summary>Tries to connect to a server.</summary> /// <param name="conData">Set the connection information properties as needed. /// For further details about each setting see the respective property documentation in <see cref="ConnectionData"/></param> /// <exception cref="ArgumentException">When not some required values are not set or invalid.</exception> /// <exception cref="Ts3Exception">When the connection could not be established.</exception> public override void Connect(ConnectionData conData) { if (!(conData is ConnectionDataFull conDataFull)) { throw new ArgumentException($"Use the {nameof(ConnectionDataFull)} deriverate to connect with the full client.", nameof(conData)); } try { HidePing = File.Exists("noping"); } catch (Exception) { } Console.WriteLine("Hidden Ping: {0}", HidePing); if (conDataFull.Identity == null) { throw new ArgumentNullException(nameof(conDataFull.Identity)); } if (conDataFull.VersionSign == null) { throw new ArgumentNullException(nameof(conDataFull.VersionSign)); } connectionDataFull = conDataFull; ConnectionData = conData; Disconnect(); if (!TsDnsResolver.TryResolve(conData.Address, out remoteAddress)) { throw new Ts3Exception("Could not read or resolve address."); } lock (statusLock) { returnCode = 0; status = Ts3ClientStatus.Connecting; context = new ConnectionContext { WasExit = false }; VersionSign = conDataFull.VersionSign; ts3Crypt.Reset(); ts3Crypt.Identity = conDataFull.Identity; packetHandler.Connect(remoteAddress); dispatcher.Init(NetworkLoop, InvokeEvent, context); } dispatcher.EnterEventLoop(); }
private void DisconnectInternal(ConnectionContext ctx, bool triggerEvent = true) { bool triggerEventSafe = false; lock (statusLock) { if (ctx.WasExit) { return; } switch (status) { case Ts3ClientStatus.Disconnected: ctx.WasExit = true; packetHandler.Stop(); msgProc.DropQueue(); dispatcher.Dispose(); triggerEventSafe = triggerEvent; break; case Ts3ClientStatus.Disconnecting: break; case Ts3ClientStatus.Connected: ClientDisconnect(MoveReason.LeftServer, QuitMessage); status = Ts3ClientStatus.Disconnecting; break; case Ts3ClientStatus.Connecting: break; default: throw Util.UnhandledDefault(status); } } if (triggerEventSafe) { OnDisconnected?.Invoke(this, new DisconnectEventArgs(packetHandler.ExitReason ?? MoveReason.LeftServer)); } }
private void InvokeEvent(LazyNotification lazyNotification) { var notification = lazyNotification.Notifications; switch (lazyNotification.NotifyType) { case NotificationType.ChannelCreated: break; case NotificationType.ChannelDeleted: break; case NotificationType.ChannelChanged: break; case NotificationType.ChannelEdited: break; case NotificationType.ChannelMoved: break; case NotificationType.ChannelPasswordChanged: break; case NotificationType.ClientEnterView: OnClientEnterView?.Invoke(this, notification.Cast <ClientEnterView>()); break; case NotificationType.ClientLeftView: var clientLeftArr = notification.Cast <ClientLeftView>().ToArray(); var leftViewEvent = clientLeftArr.FirstOrDefault(clv => clv.ClientId == packetHandler.ClientId); if (leftViewEvent != null) { packetHandler.ExitReason = leftViewEvent.Reason; lock (statusLock) { status = Ts3ClientStatus.Disconnected; DisconnectInternal(context); } break; } OnClientLeftView?.Invoke(this, clientLeftArr); break; case NotificationType.ClientMoved: OnClientMoved?.Invoke(this, notification.Cast <ClientMoved>()); break; case NotificationType.ServerEdited: break; case NotificationType.TextMessage: OnTextMessageReceived?.Invoke(this, notification.Cast <TextMessage>()); break; case NotificationType.TokenUsed: break; // full client events case NotificationType.InitIvExpand: ProcessInitIvExpand((InitIvExpand)notification.FirstOrDefault()); break; case NotificationType.InitServer: ProcessInitServer((InitServer)notification.FirstOrDefault()); break; case NotificationType.ChannelList: break; case NotificationType.ChannelListFinished: try { ChannelSubscribeAll(); } catch (Ts3CommandException) { } break; case NotificationType.ClientNeededPermissions: break; case NotificationType.ClientChannelGroupChanged: break; case NotificationType.ClientServerGroupAdded: break; case NotificationType.ConnectionInfo: break; case NotificationType.ConnectionInfoRequest: ProcessConnectionInfoRequest(); break; case NotificationType.ChannelSubscribed: break; case NotificationType.ChannelUnsubscribed: break; case NotificationType.ClientChatComposing: break; case NotificationType.ServerGroupList: break; case NotificationType.ServerGroupsByClientId: break; case NotificationType.StartUpload: break; case NotificationType.StartDownload: break; case NotificationType.FileTransfer: break; case NotificationType.FileTransferStatus: break; case NotificationType.FileList: break; case NotificationType.FileListFinished: break; case NotificationType.FileInfo: break; // special case NotificationType.Error: lock (statusLock) { if (status == Ts3ClientStatus.Connecting) { status = Ts3ClientStatus.Disconnected; DisconnectInternal(context, false); } } OnErrorEvent?.Invoke(this, (CommandError)notification.First()); break; case NotificationType.Unknown: default: throw Util.UnhandledDefault(lazyNotification.NotifyType); } }