對於FastHttpApi來說搭建一個基於Websocket的頁面聊天室是一個非常簡單的事件;畢竟基於FastHttpApi編寫的接口默認就提供了WebSocket支持,因此在做基於Websocket通訊應用的時候和傳統ajax數據交互應用沒有多大的差別;以下講解如何實現一個聊天室和管理功能。
功能描述
- 用戶功能,主要功能:登陸,創建房間,進行房間,發言和查詢房間用戶信息
- 管理功能,主要功能:查看所有用戶的發言進出房間情況,刪除房間,踢用戶下線
功能原型圖
用戶功能實現
用戶功能不多,登陸、創建房間、進入房間、發言和查詢房間用戶功能。在傳統的網絡服務中編寫起來可能有點因難,但在組件的支持下和傳統web api沒有兩樣。可能有人員會有點疑惑,畢竟web服務的api是無法向其他用戶主動發信息,但在FastHttpApi則是可以的。接下來我們看一下這幾個功能的API代碼。
用戶登陸
public bool Login(string userName, IHttpContext context)
{
context.Session.Name = userName;
if (context.Session.Name == "admin")
lock (mAdminList)
mAdminList.Add(context.Session);
return true;
}
登陸功能很簡單提交暱稱即可;由於是示例這裏就不作太多安全性的處理,當用戶名是admin就直接加入到管理員列表中了(在管理員列表的用戶是可以接收其他用戶的發言信息)。`
創建房間
public object CreateRoom(string roomName, IHttpContext context)
{
roomName = roomName.ToLower();
if (mRooms.Count > 200)
return new ActionResult(503, "房間已經滿,不能再創建");
if (mRooms.ContainsKey(roomName))
return new ActionResult(504, "房間已經存在");
Room room = new Room();
room.Name = roomName;
room.Controller = this;
mRooms[room.Name] = room;
context.SendToWebSocket(new ActionResult(new Command { Type = "CreateRoom", Name = roomName }));
return true;
}
在這裏對創建房間的數量進行了一個限制,創建成功後需要向所有用戶廣播一個創建房間信息。對於組件來說可以通過IHttpContext向當前服務中所有websocket連接發送數據;最後它還是要響應回當前請求的用戶便建房間成功(代碼中涉及的狀態都是隨意定義,和具體的HTTP狀態並沒有直接關係)。
進入和退出房間
public object CheckInRoom(string roomName, IHttpContext context)
{
Room room;
if (mRooms.TryGetValue(roomName, out room))
room.CheckIn(context);
else
return new ActionResult(404, "房間不存在");
return true;
}
public object CheckOutRoom(string roomName, IHttpContext context)
{
Room room;
if (mRooms.TryGetValue(roomName, out room))
room.CheckOut(context);
else
return new ActionResult(404, "房間不存在");
return true;
}
以上是進入和退出房間的代碼,這個代碼只是告訴當前用戶進入房間的情況;我們還需要告訴當前房間的其他用戶和管理員誰進或退出房間
public void CheckIn(IHttpContext context)
{
if (!Sessions.Contains(context.Request))
{
Command cmd = new Command();
cmd.Type = "CheckIn";
cmd.Room = Name;
cmd.Name = context.Session.Name;
context.Session["room"] = this.Name;
lock (this.Sessions)
Sessions.Add(context.Request);
SendMessage(cmd, context.Server);
Controller.SendToAdmin(cmd);
}
}
public void CheckOut(IHttpContext context)
{
Command cmd = new Command();
cmd.Type = "CheckOut";
cmd.Room = Name;
cmd.Name = context.Session.Name;
lock (this.Sessions)
Sessions.Remove(context.Request);
SendMessage(cmd, context.Server);
Controller.SendToAdmin(cmd);
}
通過以上代碼,用戶在進入或退出房間時都會把消息發給當前房間的所有用戶和管理員。
用戶發言
public void SendMessage(string message, IHttpContext context)
{
string name;
if (context.WebSocket)
{
name = context.Session.Name;
Room room = GetRoom(context.Session);
if (room != null)
Command cmd = room.Talk(name, message, context);
}
}
public Command Talk(string username, string message, IHttpContext context)
{
Command cmd = new Command();
cmd.Type = "Talk";
cmd.Message = message;
cmd.Room = Name;
cmd.Name = username;
SendMessage(cmd, context.Server);
Controller.SendToAdmin(cmd);
return cmd;
}
首先需要判斷一下當的上下文是不是WebSocket,如果是就允許繼續操作,從前用戶Session獲取房間信息,如果房間信息存在就把消息推送給房間的其他用戶和管理員。這樣用戶的基礎的服務功能已經完成。
管理端代碼
管理端主要是監控和管理,所以功能相對並不多,主要就是刪除房間和踢除在線用戶。
public void CloseSession([BodyParameter]List<int> sessions, IHttpContext context)
{
foreach (int i in sessions)
{
ISession session = context.Server.BaseServer.GetSession(i);
if (session != null)
session.Dispose();
}
}
public void CloseRoom(string roomName, IHttpContext context)
{
Room room;
if (mRooms.Remove(roomName, out room))
{
room.Sessions.Clear();
Command cmd = new Command();
cmd.Type = "Delete";
cmd.Room = roomName;
context.SendToWebSocket(new ActionResult(cmd));
}
}
組件可以根據會話ID,獲取會話對象後直接釋放。對於關閉房間,在清除房間後廣播一條刪除房間消息給所有用戶即可。
頁面整合
當編寫完成方法後,VS插件會自動生成對應的調用腳本,頁面只需經引用腳即可調用.在頁面處理上給合Vuejs還是可以很方便地把功能整合到一起的。
用戶登陸方法
async function login() {
if (!$('#userName').val() || $('#userName').val().toLowerCase() == 'admin') {
alert('登陸名稱無效!');
return;
}
var result = await $samples$chat$Login($('#userName').val());
if (result.Code != 200) {
alert(result.Error);
}
else {
alert("登陸成功");
lstTalkControl.Data = [];
$('#loginBar').hide();
$('#lstbody').empty();
loginStatus = true;
activeRoom = null;
listRoom();
}
}
用戶發送消息
async function sendMessage() {
if (!$('#talkMsg').val()) {
alert('請輸入發言的內容!');
return;
}
var result = await $samples$chat$SendMessage($('#talkMsg').val());
if (result.Code == 200) {
$('#talkMsg').val('');
}
else {
alert(result.Error);
}
}
定義接收廣播消息
api_receive(function (result) {
switch (result.Data.Type) {
case "Talk":
lstTalkControl.Data.push({ Type: 'Talk', Time: GetTime(), Name: result.Data.Name, Message: ' 說:' + result.Data.Message });
break;
case "CheckIn":
lstTalkControl.Data.push({ Type: 'CheckIn', Time: GetTime(), Name: result.Data.Name, Message: ' 進入房間' });
listRoomUsers();
break;
case "CheckOut":
lstTalkControl.Data.push({ Type: 'CheckOut', Time: GetTime(), Name: result.Data.Name, Message: ' 退出房間' });
listRoomUsers();
break;
}
});
踢除用戶
async function closeSession() {
var items = getSelectItems();
if (items.length > 0) {
if (confirm('是否要清除告訴的連接?')) {
var result = await $samples$chat$CloseSession(items);
}
}
}
這樣聊天室用戶和管理功能就集成完成,對於其他一些功能如用戶連接斷開廣播消息,Uvejs數據綁定這些功能就不細說了可以通過sample代碼來細看。