0%

關於寫個聊天室這件事 (二)訊息紀錄

聊天室要讓所有使用者收到彼此傳的訊息,可能要在DB開個資料表進行訊息紀錄,然後前端再透過Api查詢出來顯示在聊天室中,為了避免DB大量Query導致效能問題,或許還必須加入Cache機制才行。

流程修改

DB紀錄訊息、Cache優化存取速度;原本我是這麼想的,但仔細思考後決定捨棄DB,因為那些存在於DB的訊息我不會再拿來利用,可以說是一點保存的必要都沒有,於是就決定把訊息短暫的紀錄在Cache就好。
但總會發生例外,萬一有天我必須要將對話紀錄查詢出來時該怎麼辦呢?這時突然就想起了Slack,雖然免費的也有限制,卻也不失為一個優秀的中短期訊息保存方案。

建立訊息類別

必要的屬性有唯一識別碼、訊息內容、建立者、建立時間,寫成類別後如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ChatsResponseModel
{
public string Id { get; set; }
public string Message { get; set; }
public string User { get; set; }
public string Create { get; set; }
public bool Sce { get; set; }

public ChatsResponseModel()
{
Sce = false;
}
}

Cache

因為Cache現在還承包了原本DB該做的事情,所以相關的邏輯也必須先撰寫好才行。

讀寫Cache

為了後續方便使用以及統一存取的處理方式,先把Read、Write的方法寫好,並暫訂訊息的保存時間為一天。

1
2
3
4
5
public TEntity CacheRead<TEntity>(string cacheKey) where TEntity : class
{
var cacheEntity = HttpRuntime.Cache.Get(cacheKey) as TEntity;
return cacheEntity;
}
1
2
3
4
5
6
7
8
9
10
11
public void CacheWrite<TEntity>(string cacheKey, TEntity cacheEntity) where TEntity : class
{
HttpRuntime.Cache.Add(
cacheKey,
cacheEntity,
null,
DateTime.Now.AddDays(1),
Cache.NoSlidingExpiration,
CacheItemPriority.High,
null);
}

讀寫Cache中的訊息

結合剛剛提到的訊息類別,就可以簡單的使用Cache做訊息的讀寫了。

1
2
3
4
public List<ChatsResponseModel> Read() {
var chats = CacheRead<List<ChatsResponseModel>>(this.CacheKey) ?? new List<ChatsResponseModel>();
return chats;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public ChatsResponseModel Write(MessageRequestModel model, string userId, bool sce = false) {
var chats = this.Read() ?? new List<ChatsResponseModel>();
var newChat = new ChatsResponseModel()
{
Id = Guid.NewGuid().ToString(),
Message = model.Message,
User = ApplicationDbContext.Users.FirstOrDefault(s => s.Id == userId).UserName,
Create = DateTime.Now.ToString("H:mm:ss"),
Sce = sce
};
chats.Add(newChat);
CacheWrite(this.CacheKey, chats);
return newChat;
}

Api讀取訊息

訊息讀寫既然已經處理完畢,那Api也能取得目前已有的訊息紀錄了,以下為Api的回傳結果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[  
{
"Id":"262436f5-d9ac-4192-a4f1-5021b383b926",
"Message":"Hello world",
"User":"test@gmail.com",
"Create":"9:40:13",
"Sce":false
},
{
"Id":"de5d1bbb-903c-4bbf-ac7d-a2582d4a8f82",
"Message":"測試",
"User":"test@gmail.com",
"Create":"9:40:22",
"Sce":false
}
]

Slack

推薦看Slack Api,除了整體風格我很喜歡外,寫得也很清楚、測試也很好用,看完後直接使用Web Api,在聊天室接收到訊息時順便轉傳Slack作儲存之用。

實作Post Message方法

撰寫一個方法,收聊天室之訊息與使用者名稱,並填入至Slack Api所需要的參數中。

1
2
3
4
5
6
7
8
9
10
11
public void SlackPostMessage(string message, string name)
{
var pureMsg = SanitizeHtml(message);
if (!string.IsNullOrEmpty(pureMsg))
{
var url = $"https://slack.com/api/chat.postMessage?token={this.token}&channel={this.channel}&text={pureMsg}&username={name}";
var client = new RestClient(url);
var request = new RestRequest(Method.GET);
client.ExecuteTaskAsync(request);
}
}

Demo

下圖為同時開啟聊天室與Slack,已經可以看到Slack會幫聊天室備份訊息紀錄了。

結語

聊天室已經完成存取訊息(Cache)和查詢紀錄(Slack)的功能了,少了DB設計起來就是快,雖然存在著一些致命的硬傷,但我不說😈;如果大家有更好的處理方式的話,不妨分享給我吧!