using System; using System.Collections.Generic; using System.Linq; using System.Numerics; namespace axXez.TS3.Protocol { /// Parsed TeamSpeak text-protocol message — includes the command name and all key-value entries. public class TsMessage { /// The command or notification name (e.g. "clientlist", "notifyclientmoved"). public string Name { get; set; } /// All parsed key-value entry sets. Multiple entries are separated by | in the raw data. public List Entries { get; set; } /// The raw message string, before parsing. public string RawData { get; private set; } /// Whether the message contains at least one data entry. public bool HasData => Entries?.Count > 0; /// Number of entries in the message. public int Count => Entries?.Count ?? 0; /// Shorthand for the first entry. null if is false. public TsDataEntry Params => HasData ? Entries[0] : null; /// Returns the entry at the given index. public TsDataEntry this[int index] => Entries[index]; /// Returns the value of the given key from the first entry, or null if there is no data. public string this[string key] => HasData ? Entries[0][key] : null; internal TsMessage() { } internal TsMessage(string name, string data) { Name = name; RawData = data; ParseEntries(data); } /// Parses a raw TeamSpeak text-protocol string into a . public static TsMessage Parse(string raw) { var parts = raw.Split('|'); var first = parts[0].Trim(); int nameEnd = first.IndexOf(' '); var name = nameEnd >= 0 ? first[..nameEnd] : first; var entries = new List(); foreach (var part in parts) entries.Add(TsDataEntry.Parse(part)); return new TsMessage { Name = name, RawData = raw, Entries = entries }; } private void ParseEntries(string data) { if (string.IsNullOrWhiteSpace(data)) { Entries = null; return; } Entries = new(); foreach (var part in data.Split('|')) Entries.Add(TsDataEntry.Parse(part)); } /// Returns the value of the first matching key from the first entry, or an empty string if not found. public string Get(params string[] keys) => HasData ? Entries[0].GetValue(keys) : ""; /// Returns the numeric value of the first matching key from the first entry, or the type's default if not found. public T Get(params string[] keys) where T : INumber => HasData ? Entries[0].GetValue(keys) : default; /// Deserializes the first entry into a of type . public T Get() where T : TsEntity => HasData ? Entries[0].GetEntity() : default; /// Returns the Unix-timestamp field from the first entry as a . public DateTime GetDateTime(params string[] keys) => HasData ? Entries[0].GetDateTime(keys) : default; /// Returns the value of the first matching key from every entry. public List GetAll(params string[] keys) => HasData ? Entries.Select(x => x.GetValue(keys)).ToList() : []; /// Returns the numeric value of the first matching key from every entry. public List GetAll(params string[] keys) where T : INumber => HasData ? Entries.Select(x => x.GetValue(keys)).ToList() : []; /// Deserializes every entry into a of type . public List GetAll() where T : TsEntity => HasData ? Entries.Select(x => x.GetEntity()).ToList() : []; internal Dictionary ToDictionary() => HasData ? Entries[0].ToDictionary() : new(); internal List> ToDictionaryList() => HasData ? Entries.Select(e => e.ToDictionary()).ToList() : new(); } }