/// <summary> /// Asynchronously obtains a grant of <paramref name="requestedBytes"/> for the requesting <paramref name="username"/>. /// </summary> /// <remarks> /// This operation completes when any number of bytes can be granted. The amount returned may be smaller than the /// requested amount. /// </remarks> /// <param name="username">The username of the requesting user.</param> /// <param name="requestedBytes">The number of requested bytes.</param> /// <param name="cancellationToken">The token to monitor for cancellation.</param> /// <returns>The operation context, including the number of bytes granted.</returns> public Task <int> GetBytesAsync(string username, int requestedBytes, CancellationToken cancellationToken) { var group = Users.GetGroup(username); var bucket = TokenBuckets.GetValueOrDefault(group ?? string.Empty, TokenBuckets[Application.DefaultGroup]); return(bucket.GetAsync(requestedBytes, cancellationToken)); }
/// <summary> /// Returns wasted bytes for redistribution. /// </summary> /// <param name="username">The username of the user that generated the waste.</param> /// <param name="attemptedBytes">The number of bytes that were attempted to be transferred.</param> /// <param name="grantedBytes">The number of bytes granted by all governors in the system.</param> /// <param name="actualBytes">The actual number of bytes transferred.</param> public void ReturnBytes(string username, int attemptedBytes, int grantedBytes, int actualBytes) { var waste = Math.Max(0, grantedBytes - actualBytes); if (waste == 0) { return; } var group = Users.GetGroup(username); var bucket = TokenBuckets.GetValueOrDefault(group ?? string.Empty, TokenBuckets[Application.DefaultGroup]); // we don't have enough information to tell whether grantedBytes was reduced by the global limiter within // Soulseek.NET, so we just return the bytes that we know for sure that were wasted, which is grantedBytes - actualBytes. // example: we grant 1000 bytes. Soulseek.NET grants only 500. 250 bytes are written. ideally we would return 750 // bytes, but instead we return 250. this discrepancy doesn't really matter because Soulseek.NET is the constraint in // this scenario and the additional tokens we would return would never be used. bucket.Return(waste); }