/// <summary>
        ///     Gets the preferred node using the <see cref="LoadBalancingStrategy"/> specified in
        ///     the options.
        /// </summary>
        /// <param name="type">the type of the purpose for the node</param>
        /// <returns>the next preferred node</returns>
        /// <exception cref="InvalidOperationException">
        ///     thrown if the cluster has not been initialized.
        /// </exception>
        /// <exception cref="InvalidOperationException">thrown if no nodes is available</exception>
        /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
        public LavalinkNode GetPreferredNode(NodeRequestType type = NodeRequestType.Unspecified)
        {
            EnsureNotDisposed();

            if (!_initialized)
            {
                throw new InvalidOperationException("The cluster has not been initialized.");
            }

            lock (_nodesLock)
            {
                return(GetPreferredNodeInternal(type));
            }
        }
        /// <summary>
        ///     Gets the node that serves the guild specified by <paramref name="guildId"/> (if no
        ///     node serves the guild, <see cref="PreferredNode"/> is used).
        /// </summary>
        /// <param name="guildId">the guild snowflake identifier</param>
        /// <param name="type">the type of the purpose for the node</param>
        /// <returns>the serving node for the specified <paramref name="guildId"/></returns>
        /// <exception cref="InvalidOperationException">
        ///     thrown if the cluster has not been initialized.
        /// </exception>
        /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
        public LavalinkNode GetServingNode(ulong guildId, NodeRequestType type = NodeRequestType.Unspecified)
        {
            EnsureNotDisposed();

            lock (_nodesLock)
            {
                var node = _nodes.FirstOrDefault(s => s.HasPlayer(guildId));

                if (node != null)
                {
                    return(node);
                }

                return(GetPreferredNodeInternal(type));
            }
        }
        public GetObjectsInfoNodeRequest(IEnumerable <long> objectsId, long?requestorUserId, NodeRequestType nodeRequestType)
        {
            ObjectsId       = objectsId.ToList();
            RequestorUserId = requestorUserId;
            switch (nodeRequestType)
            {
            case NodeRequestType.GetChats:
            case NodeRequestType.GetUsers:
            case NodeRequestType.GetChannels:
                RequestType = nodeRequestType;
                break;

            default:
                throw new ArgumentException($"NodeRequestType can only {NodeRequestType.GetUsers.ToString()} or {NodeRequestType.GetChats.ToString()}");
            }
        }
        private LavalinkNode GetPreferredNodeInternal(NodeRequestType type = NodeRequestType.Unspecified)
        {
            // find a connected node
            var nodes = _nodes.Where(s => s.IsConnected).ToArray();

            // no nodes available
            if (nodes.Length == 0)
            {
                throw new InvalidOperationException("No node available.");
            }

            // get the preferred node by the load balancing strategy
            var node = _loadBalacingStrategy(this, nodes, type);

            // update last usage
            node.LastUsage = DateTimeOffset.UtcNow;

            return(node);
        }