/// <summary> /// 撤销一个订阅者已有的订阅(如果没有订阅,不会进行任何操作) /// </summary> /// <param name="subscriberId">订阅者 ID</param> /// <param name="targetId">目标 ID</param> /// <param name="targetType">目标类型</param> /// <exception cref="ArgumentNullException">有参数为 null</exception> public async Task RemoveAsync([NotNull] string subscriberId, [NotNull] string targetId, SubscriptionTargetType targetType) { if (subscriberId == null) { throw new ArgumentNullException(nameof(subscriberId)); } if (targetId == null) { throw new ArgumentNullException(nameof(targetId)); } if (subscriberId == targetId || !await IsSubscribedAsync(subscriberId, targetId, targetType)) { return; } var subscriptions = await _dbContext.Subscriptions.Where(s => s.SubscriberId == subscriberId && s.TargetId == targetId && s.TargetType == targetType) .ToListAsync(); _dbContext.Subscriptions.RemoveRange(subscriptions); await _dbContext.SaveChangesAsync(); var redisDb = _redis.GetDatabase(); var cacheKey = UserSubscribedTargetsCacheKey(subscriberId); foreach (var subscription in subscriptions) { await redisDb.SetRemoveAsync(cacheKey, UserSubscribedTargetCacheValue(subscription.TargetId, subscription.TargetType)); } await IncreaseSubscriberCountAsync(targetId, targetType, -subscriptions.Count); }
public async Task <IHttpActionResult> DeleteOne(string targetId, SubscriptionTargetType targetType) { var subscriberId = User.Identity.GetUserId(); await _cachedData.Subscriptions.RemoveAsync(subscriberId, targetId, targetType); return(Ok()); }
/// <summary> /// 添加一个新订阅(如果已经订阅,不会进行任何操作) /// </summary> /// <param name="subscriberId">订阅者 ID</param> /// <param name="targetId">目标 ID</param> /// <param name="targetType">目标类型</param> /// <returns>订阅成功返回 <c>true</c></returns> /// <exception cref="ArgumentNullException">有参数为 null</exception> public async Task <bool> AddAsync([NotNull] string subscriberId, [NotNull] string targetId, SubscriptionTargetType targetType) { if (subscriberId == null) { throw new ArgumentNullException(nameof(subscriberId)); } if (targetId == null) { throw new ArgumentNullException(nameof(targetId)); } if (subscriberId == targetId || await IsSubscribedAsync(subscriberId, targetId, targetType)) { return(false); } _dbContext.Subscriptions.Add(new Subscription { SubscriberId = subscriberId, TargetId = targetId, TargetType = targetType }); await _dbContext.SaveChangesAsync(); var redisDb = _redis.GetDatabase(); await redisDb.SetAddAsync(UserSubscribedTargetsCacheKey(subscriberId), UserSubscribedTargetCacheValue(targetId, targetType)); await IncreaseSubscriberCountAsync(targetId, targetType, 1); return(true); }
/// <summary> /// 判断指定用户是否订阅过指定目标 /// </summary> /// <param name="userId">用户 ID</param> /// <param name="targetId">目标 ID</param> /// <param name="targetType">目标类型</param> /// <returns>如果用户订阅过,返回 <c>true</c></returns> public async Task <bool> IsSubscribedAsync(string userId, string targetId, SubscriptionTargetType targetType) { if (userId == null || targetId == null) { return(false); } var cacheKey = await InitUserSubscribedTargetsAsync(userId); return(await _redis.GetDatabase() .SetContainsAsync(cacheKey, UserSubscribedTargetCacheValue(targetId, targetType))); }
private async Task IncreaseSubscriberCountAsync([NotNull] string targetId, SubscriptionTargetType targetType, long value) { var cacheKey = TargetSubscriberCountCacheKey(targetId, targetType); var redisDb = _redis.GetDatabase(); if (await redisDb.KeyExistsAsync(cacheKey)) { if (value >= 0) { await redisDb.StringIncrementAsync(cacheKey, value); } else { await redisDb.StringDecrementAsync(cacheKey, -value); } } }
/// <summary> /// 获取指定目标的订阅者数量 /// </summary> /// <param name="targetId">目标 ID</param> /// <param name="targetType">目标类型</param> /// <exception cref="ArgumentNullException"><paramref name="targetId"/> 为 null</exception> /// <returns>目标的订阅者数量</returns> public async Task <long> GetSubscriberCountAsync([NotNull] string targetId, SubscriptionTargetType targetType) { if (targetId == null) { throw new ArgumentNullException(nameof(targetId)); } var cacheKey = TargetSubscriberCountCacheKey(targetId, targetType); var redisDb = _redis.GetDatabase(); var cacheResult = await redisDb.StringGetAsync(cacheKey); if (cacheResult.HasValue) { await redisDb.KeyExpireAsync(cacheKey, CachedDataProvider.DefaultTtl); return((long)cacheResult); } var subscriberCount = await _dbContext.Subscriptions .LongCountAsync(s => s.TargetId == targetId && s.TargetType == targetType); await redisDb.StringSetAsync(cacheKey, subscriberCount, CachedDataProvider.DefaultTtl); return(subscriberCount); }
public async Task <IHttpActionResult> CreateOne(string targetId, SubscriptionTargetType targetType) { var subscriberId = User.Identity.GetUserId(); bool existed; KeylolUser targetUser = null; switch (targetType) { case SubscriptionTargetType.Point: existed = await _dbContext.Points.AnyAsync(p => p.Id == targetId); break; case SubscriptionTargetType.User: if (subscriberId.Equals(targetId, StringComparison.OrdinalIgnoreCase)) { return(this.BadRequest(nameof(targetId), Errors.Invalid)); } targetUser = await _userManager.FindByIdAsync(targetId); existed = targetUser != null; break; case SubscriptionTargetType.Conference: existed = await _dbContext.Conferences.AnyAsync(c => c.Id == targetId); break; default: throw new ArgumentOutOfRangeException(nameof(targetType), targetType, null); } if (!existed) { return(this.BadRequest(nameof(targetId), Errors.NonExistent)); } var succeed = await _cachedData.Subscriptions.AddAsync(subscriberId, targetId, targetType); if (targetType == SubscriptionTargetType.User && succeed) { Debug.Assert(targetUser != null, "targetUser != null"); var subscriberCount = (int)await _cachedData.Subscriptions.GetSubscriberCountAsync(targetId, targetType); if (targetUser.NotifyOnSubscribed) { await _cachedData.Messages.AddAsync(new Message { Type = MessageType.NewSubscriber, OperatorId = subscriberId, ReceiverId = targetId, Count = subscriberCount }); } if (targetUser.SteamNotifyOnSubscribed) { var subscriber = await _userManager.FindByIdAsync(subscriberId); await _userManager.SendSteamChatMessageAsync(targetUser, await _cachedData.Users.IsFriendAsync(subscriberId, targetId) ?$"用户 {subscriber.UserName} 成为了你的第 {subscriberCount} 位听众,并开始与你互相关注。换句话说,你们已经成为好友啦!" : $"用户 {subscriber.UserName} 关注了你并成为你的第 {subscriberCount} 位听众,你们之间互相关注后会成为好友。"); } } return(Ok()); }
private static string TargetSubscriberCountCacheKey(string targetId, SubscriptionTargetType targetType) => $"subscriber-count:{targetType.ToString().ToCase(NameConventionCase.PascalCase, NameConventionCase.DashedCase)}:{targetId}";
private static string UserSubscribedTargetCacheValue(string targetId, SubscriptionTargetType targetType) => $"{targetType.ToString().ToCase(NameConventionCase.PascalCase, NameConventionCase.DashedCase)}:{targetId}";