- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我开始使用 chatjs.net 实现一个网络聊天系统.但我想知道 friend 列表应该绑定(bind)聊天列表。我指的是与 ROOM_ID_STUB 的房间聊天记录了用户名。但在我的情况下, friend 列表将显示在线和离线用户,不像所有示例 chatjs.net 只会是单人间。
任何人都可以建议我绑定(bind)我的 friend 列表的正确方法,并且每个登录的用户都会有一个聊天室,他们一起共享房间聊天列表?
public class ChatHub : Hub, IChatHub
{
/// <summary>
/// This STUB. In a normal situation, there would be multiple rooms and the user room would have to be
/// determined by the user profile
/// </summary>
public const string ROOM_ID_STUB = "chatjs-room";
/// <summary>
/// Current connections
/// 1 room has many users that have many connections (2 open browsers from the same user represents 2 connections)
/// </summary>
private static readonly Dictionary<string, Dictionary<int, List<string>>> connections = new Dictionary<string, Dictionary<int, List<string>>>();
/// <summary>
/// This is STUB. This will SIMULATE a database of chat messages
/// </summary>
private static readonly List<DbChatMessageStub> dbChatMessagesStub = new List<DbChatMessageStub>();
/// <summary>
/// This method is STUB. This will SIMULATE a database of users
/// </summary>
private static readonly List<DbUserStub> dbUsersStub = new List<DbUserStub>();
/// <summary>
/// This method is STUB. In a normal situation, the user info would come from the database so this method wouldn't be necessary.
/// It's only necessary because this class is simulating the database
/// </summary>
/// <param name="newUser"></param>
public static void RegisterNewUser(DbUserStub newUser)
{
if (newUser == null) throw new ArgumentNullException("newUser");
dbUsersStub.Add(newUser);
}
/// <summary>
/// This method is STUB. Returns if a user is registered in the FAKE DB.
/// Normally this wouldn't be necessary.
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public static bool IsUserRegisteredInDbUsersStub(DbUserStub user)
{
return dbUsersStub.Any(u => u.Id == user.Id);
}
/// <summary>
/// Tries to find a user with the provided e-mail
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
public static DbUserStub FindUserByEmail(string email)
{
if (email == null) return null;
return dbUsersStub.FirstOrDefault(u => u.Email == email);
}
/// <summary>
/// If the specified user is connected, return information about the user
/// </summary>
public ChatUser GetUserInfo(int userId)
{
var user = dbUsersStub.FirstOrDefault(u => u.Id == userId);
return user == null ? null : GetChatUserFromDbUserId(userId);
}
private ChatUser GetChatUserFromDbUserId(int dbUserId)
{
var myRoomId = this.GetMyRoomId();
// this is STUB. Normally you would go to the database get the real user
var dbUser = dbUsersStub.First(u => u.Id == dbUserId);
ChatUser.StatusType userStatus;
lock (connections)
{
userStatus = connections.ContainsKey(myRoomId)
? (connections[myRoomId].ContainsKey(dbUser.Id)
? ChatUser.StatusType.Online
: ChatUser.StatusType.Offline)
: ChatUser.StatusType.Offline;
}
return new ChatUser()
{
Id = dbUser.Id,
Name = dbUser.FullName,
Status = userStatus,
ProfilePictureUrl = GravatarHelper.GetGravatarUrl(GravatarHelper.GetGravatarHash(dbUser.Email), GravatarHelper.Size.s32)
};
}
private ChatMessage GetChatMessage(DbChatMessageStub chatMessage, string clientGuid)
{
return new ChatMessage()
{
Message = chatMessage.Message,
UserFrom = this.GetChatUserFromDbUserId(chatMessage.UserFromId),
UserTo = this.GetChatUserFromDbUserId(chatMessage.UserToId),
ClientGuid = clientGuid
};
}
/// <summary>
/// Returns my user id
/// </summary>
/// <returns></returns>
private int GetMyUserId()
{
// This would normally be done like this:
//var userPrincipal = this.Context.User as AuthenticatedPrincipal;
//if (userPrincipal == null)
// throw new NotAuthorizedException();
//var userData = userPrincipal.Profile;
//return userData.Id;
// But for this example, it will get my user from the cookie
return ChatCookieHelperStub.GetDbUserFromCookie(this.Context.Request).Id;
}
private string GetMyRoomId()
{
// This would normally be done like this:
//var userPrincipal = this.Context.User as AuthenticatedPrincipal;
//if (userPrincipal == null)
// throw new NotAuthorizedException();
//var userData = userPrincipal.Profile;
//return userData.MyTenancyIdentifier;
// But for this example, it will always return "chatjs-room", because we have only one room.
return ROOM_ID_STUB;
}
/// <summary>
/// Broadcasts to all users in the same room the new users list
/// </summary>
private void BroadcastUsersList()
{
var myRoomId = this.GetMyRoomId();
var connectionIds = new List<string>();
lock (connections)
{
if (connections.ContainsKey(myRoomId))
connectionIds = connections[myRoomId].Keys.SelectMany(userId => connections[myRoomId][userId]).ToList();
}
// gets the current room user's list
// this is STUB. You would normally go to the database to get the real room users
var dbRoomUsers = dbUsersStub.Where(u => u.TenancyId == myRoomId).OrderBy(u => u.FullName).ToList();
var usersList = dbRoomUsers.Select(u => this.GetChatUserFromDbUserId(u.Id)).ToList();
foreach (var connectionId in connectionIds)
this.Clients.Client(connectionId).usersListChanged(usersList);
}
private DbChatMessageStub PersistMessage(int otherUserId, string message)
{
var myUserId = this.GetMyUserId();
// this is STUB. Normally you would go to the real database to get the my user and the other user
var myUser = dbUsersStub.FirstOrDefault(u => u.Id == myUserId);
var otherUser = dbUsersStub.FirstOrDefault(u => u.Id == otherUserId);
if (myUser == null || otherUser == null)
return null;
var dbChatMessage = new DbChatMessageStub()
{
Date = DateTime.UtcNow,
Message = message,
UserFromId = myUserId,
UserToId = otherUserId,
TenancyId = myUser.TenancyId
};
// this is STUB. Normally you would add the dbMessage to the real database
dbChatMessagesStub.Add(dbChatMessage);
// normally you would save the database changes
//this.db.SaveChanges();
return dbChatMessage;
}
/// <summary>
/// Returns the message history
/// </summary>
public List<ChatMessage> GetMessageHistory(int otherUserId)
{
var myUserId = this.GetMyUserId();
// this is STUB. Normally you would go to the real database to get the messages
var dbMessages = dbChatMessagesStub
.Where(
m =>
(m.UserToId == myUserId && m.UserFromId == otherUserId) ||
(m.UserToId == otherUserId && m.UserFromId == myUserId))
.OrderByDescending(m => m.Date).Take(30).ToList();
dbMessages.Reverse();
return dbMessages.Select(m => this.GetChatMessage(m, null)).ToList();
}
/// <summary>
/// Sends a message to a particular user
/// </summary>
public void SendMessage(int otherUserId, string message, string clientGuid)
{
var myUserId = this.GetMyUserId();
var myRoomId = this.GetMyRoomId();
var dbChatMessage = PersistMessage(otherUserId, message);
var connectionIds = new List<string>();
lock (connections)
{
if (connections[myRoomId].ContainsKey(otherUserId))
connectionIds.AddRange(connections[myRoomId][otherUserId]);
if (connections[myRoomId].ContainsKey(myUserId))
connectionIds.AddRange(connections[myRoomId][myUserId]);
}
foreach (var connectionId in connectionIds)
this.Clients.Client(connectionId).sendMessage(this.GetChatMessage(dbChatMessage, clientGuid));
}
/// <summary>
/// Sends a typing signal to a particular user
/// </summary>
public void SendTypingSignal(int otherUserId)
{
var myUserId = this.GetMyUserId();
var myRoomId = this.GetMyRoomId();
var connectionIds = new List<string>();
lock (connections)
{
if (connections[myRoomId].ContainsKey(otherUserId))
connectionIds.AddRange(connections[myRoomId][otherUserId]);
}
foreach (var connectionId in connectionIds)
this.Clients.Client(connectionId).sendTypingSignal(this.GetUserInfo(myUserId));
}
public override Task OnConnected()
{
var myRoomId = this.GetMyRoomId();
var myUserId = this.GetMyUserId();
lock (connections)
{
if (!connections.ContainsKey(myRoomId))
connections[myRoomId] = new Dictionary<int, List<string>>();
if (!connections[myRoomId].ContainsKey(myUserId))
connections[myRoomId][myUserId] = new List<string>();
connections[myRoomId][myUserId].Add(this.Context.ConnectionId);
}
this.BroadcastUsersList();
return base.OnConnected();
}
public override Task OnDisconnected()
{
var myRoomId = this.GetMyRoomId();
var myUserId = this.GetMyUserId();
lock (connections)
{
if (connections.ContainsKey(myRoomId))
if (connections[myRoomId].ContainsKey(myUserId))
if (connections[myRoomId][myUserId].Contains(this.Context.ConnectionId))
{
connections[myRoomId][myUserId].Remove(this.Context.ConnectionId);
if (!connections[myRoomId][myUserId].Any())
{
connections[myRoomId].Remove(myUserId);
Task.Factory.StartNew(() =>
{
// this will run in separate thread.
// If the user is away for more than 10 seconds it will be removed from
// the room.
// In a normal situation this wouldn't be done because normally the users in a
// chat room are fixed, like when you have 1 chat room for each tenancy
Thread.Sleep(10000);
if (!connections[myRoomId].ContainsKey(myUserId))
{
var myDbUser = dbUsersStub.FirstOrDefault(u => u.Id == myUserId);
if (myDbUser != null)
{
dbUsersStub.Remove(myDbUser);
this.BroadcastUsersList();
}
}
});
}
}
}
return base.OnDisconnected();
}
}
最佳答案
private void BroadcastUsersList()
{
var myRoomId = this.GetMyRoomId();
var connectionIds = new List<string>();
lock (connections)
{
if (connections.ContainsKey(myRoomId))
connectionIds = connections[myRoomId].Keys.SelectMany(userId => connections[myRoomId][userId]).ToList();
}
List<UserSite> dbRoomUsers = new List<UserSite>();
int myId = GetMyUserId();
List<Int>listFriendId = getListUserIdFriendOfUser(myId);
listFriendId.Add(myId);
foreach (var item in dbUsersStub)
{
if (listFriendId.Contains(item.Id))
dbRoomUsers.Add(item);
}
var usersList = dbRoomUsers.Select(u => this.GetChatUserFromDbUserId(u.Id)).ToList();
foreach (var connectionId in connectionIds)
this.Clients.Client(connectionId).usersListChanged(usersList);
}
关于asp.net-mvc - 使用 chatjs.net SignalR MVC 聊天的好友列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18151902/
如标题所示,ans_list是一个答案列表,ans_index是一个数字(答案在词汇表中的索引,但与atm无关) 这里生成的 tree.anslist 是什么? (例如,仅针对第一个),忽略迭代。 f
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我目前将用户的输入存储在逗号分隔的列表中,如下所示: Userid | Options 1 | 1,2,5 用户在一个数组形式中勾选一组选项,然后用逗号连接起来 1,2,5 然后 MySQ
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将具有一个元素的东西拿走。 这与 How do I “flatte
我想知道如何完全展平列表和包含它们的东西。除其他外,我想出了一个解决方案,它可以将具有多个元素的东西滑倒并将它们放回原处,或者在滑倒后将带有一个元素的东西拿走。 这与 How do I “flatte
这个问题已经有答案了: Convert nested list to 2d array (3 个回答) 已关闭 7 年前。 java中有没有快捷方式可以转换 List> 到 String[][] ?
我在排序时遇到问题 List> 。我创建了一个自定义比较器,在其中编写了对数据进行排序的代码。 public class CustomComparator implements Comparator
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Java Generics: Cannot cast List to List? 我只是想知道为什么下面的java代
试图想出一个 LINQy 方法来做到这一点,但我什么也没想到。 我有一个对象列表<>,其中包含一个属性,该属性是逗号分隔的字母代码列表: lst[0].codes = "AA,BB,DD" lst[1
假设我有这些任务: points = [] point = (1, 2) 我怎么会这样做: points += point 它工作得很好,并且给了我点 = [1, 2]。但是,如果我这样做: poin
如何在 scala 中将 List[Task[List[Header]]] 类型转换为 Task[List[Header]]。 我有一个方法返回 Task[List[Header]] 并多次调用 do
如何在 Java 中查找二维列表的元素? 我有一个参数为 List> 的函数我想知道如何找到这个列表的行和列。 最佳答案 如果你喜欢 List> obj 然后你就可以像这样访问 obj.get(cur
分配 List到 List工作正常。 分配 List>到 List>不编译。 代码 public class Main { public static void main(String[] a
我正在用 Java 编写一个方法,该方法必须接收并迭代 Serializable 的 List。 有什么区别: public void myMethod(List list) { } 和 public
我看到很多人想用 mvvm 更新网格/列表/树的一部分,但他们不想刷新整个列表。 对于所有遇到此问题的人,我做了以下示例。 希望这对你有用。 最佳答案 这是一个简单的例子。整个代码中最重要的是: Bi
我正在为现有的 C++ 库编写包装器,该库使用列表,其中 T 是自定义结构。我被建议使用 vector 而不是列表,但我试图避免修改库。 为了更好地理解这个场景,我做了一个简单的应用程序,使用一个列表
List list List list 这两种声明有什么区别吗? 谢谢, 最佳答案 是的。 List可以包含所有派生自 Base 的不同事物的混合物. List包含同质项(从某种意义上说,它们必须全部
有人可以尽可能详细地解释以下类型之间的区别吗? List List List 让我更具体一点。我什么时候想使用 // 1 public void CanYouGiveMeAnAnswer(List l
我有一个元组列表,每个元组都是一对列表。所以我的数据看起来像: mylist = [(['foo', 'bar'], ['bar', 'bar']),(['bar', 'bar'],['bar', '
也许是一个时髦的标题,但我遇到了以下问题: 给定一个类型为 (a * b) list 的列表,我想创建一个类型为 (a * b list) list 的新列表。一个例子: 给定列表 let testL
我是一名优秀的程序员,十分优秀!