- Implement unread state sync for SSE
This commit is contained in:
@@ -251,6 +251,7 @@ internal class Tab
|
|||||||
public bool HideWhenInactive;
|
public bool HideWhenInactive;
|
||||||
|
|
||||||
[NonSerialized] public uint Unread;
|
[NonSerialized] public uint Unread;
|
||||||
|
[NonSerialized] public uint LastSendUnread;
|
||||||
[NonSerialized] public long LastActivity;
|
[NonSerialized] public long LastActivity;
|
||||||
[NonSerialized] public MessageList Messages = new();
|
[NonSerialized] public MessageList Messages = new();
|
||||||
|
|
||||||
@@ -265,8 +266,8 @@ internal class Tab
|
|||||||
Messages.AddPrune(message, MessageManager.MessageDisplayLimit);
|
Messages.AddPrune(message, MessageManager.MessageDisplayLimit);
|
||||||
if (!unread)
|
if (!unread)
|
||||||
return;
|
return;
|
||||||
Unread += 1;
|
|
||||||
|
|
||||||
|
Unread += 1;
|
||||||
if (message.Matches(Plugin.Config.InactivityHideChannels!, Plugin.Config.InactivityHideExtraChatAll, Plugin.Config.InactivityHideExtraChatChannels))
|
if (message.Matches(Plugin.Config.InactivityHideChannels!, Plugin.Config.InactivityHideExtraChatAll, Plugin.Config.InactivityHideExtraChatChannels))
|
||||||
LastActivity = Environment.TickCount64;
|
LastActivity = Environment.TickCount64;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ interface ChannelList {
|
|||||||
export interface ChatTab {
|
export interface ChatTab {
|
||||||
name: string;
|
name: string;
|
||||||
index: number;
|
index: number;
|
||||||
|
unreadCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ref `DataStructure.ChatTabList`
|
// ref `DataStructure.ChatTabList`
|
||||||
@@ -52,6 +53,12 @@ interface ChatTabList {
|
|||||||
tabs: ChatTab[];
|
tabs: ChatTab[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ref `DataStructure.ChatTabUnreadState`
|
||||||
|
interface ChatTabUnreadState {
|
||||||
|
index: number;
|
||||||
|
unreadCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class ChatTwoWeb {
|
export class ChatTwoWeb {
|
||||||
elements!: ChatElements;
|
elements!: ChatElements;
|
||||||
maxTimestampWidth: number = 0;
|
maxTimestampWidth: number = 0;
|
||||||
@@ -297,7 +304,7 @@ export class ChatTwoWeb {
|
|||||||
this.connection = source('/sse')
|
this.connection = source('/sse')
|
||||||
|
|
||||||
this.connection.select('close').subscribe((data: string) => {
|
this.connection.select('close').subscribe((data: string) => {
|
||||||
console.log(`Data received: ${data}`)
|
console.log(`close: ${data}`)
|
||||||
if (data) {
|
if (data) {
|
||||||
console.log('Closing SSE connection.');
|
console.log('Closing SSE connection.');
|
||||||
this.connection.close();
|
this.connection.close();
|
||||||
@@ -306,7 +313,7 @@ export class ChatTwoWeb {
|
|||||||
|
|
||||||
// new messages to be appended to the message list
|
// new messages to be appended to the message list
|
||||||
this.connection.select('new-message').subscribe((data: string) => {
|
this.connection.select('new-message').subscribe((data: string) => {
|
||||||
console.log(`Data received: ${data}`)
|
console.log(`new-message: ${data}`)
|
||||||
if (data) {
|
if (data) {
|
||||||
try {
|
try {
|
||||||
let message: MessageResponse = JSON.parse(data);
|
let message: MessageResponse = JSON.parse(data);
|
||||||
@@ -319,7 +326,7 @@ export class ChatTwoWeb {
|
|||||||
|
|
||||||
// a bulk of new messages, with a clear of the message list beforehand
|
// a bulk of new messages, with a clear of the message list beforehand
|
||||||
this.connection.select('bulk-messages').subscribe((data: string) => {
|
this.connection.select('bulk-messages').subscribe((data: string) => {
|
||||||
console.log(`Data received: ${data}`)
|
console.log(`bulk-messages: ${data}`)
|
||||||
if (data) {
|
if (data) {
|
||||||
this.clearAllMessages();
|
this.clearAllMessages();
|
||||||
try {
|
try {
|
||||||
@@ -334,7 +341,7 @@ export class ChatTwoWeb {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.connection.select('channel-switched').subscribe((data: string) => {
|
this.connection.select('channel-switched').subscribe((data: string) => {
|
||||||
console.log(`Data received: ${data}`)
|
console.log(`channel-switched: ${data}`)
|
||||||
if (data) {
|
if (data) {
|
||||||
try {
|
try {
|
||||||
let channel: SwitchChannel = JSON.parse(data);
|
let channel: SwitchChannel = JSON.parse(data);
|
||||||
@@ -347,7 +354,7 @@ export class ChatTwoWeb {
|
|||||||
|
|
||||||
// list of all channels
|
// list of all channels
|
||||||
this.connection.select('channel-list').subscribe((data: string) => {
|
this.connection.select('channel-list').subscribe((data: string) => {
|
||||||
console.log(`Data received: ${data}`)
|
console.log(`channel-list: ${data}`)
|
||||||
if (data) {
|
if (data) {
|
||||||
try {
|
try {
|
||||||
let channelList: ChannelList = JSON.parse(data);
|
let channelList: ChannelList = JSON.parse(data);
|
||||||
@@ -386,5 +393,17 @@ export class ChatTwoWeb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// the unread state of a specific tab has changed
|
||||||
|
this.connection.select('tab-unread-state').subscribe((data: string) => {
|
||||||
|
console.log(`tab-unread-state: ${data}`)
|
||||||
|
if (data) {
|
||||||
|
try {
|
||||||
|
const chatTabUnreadState: ChatTabUnreadState = JSON.parse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ namespace ChatTwo.Http.MessageProtocol;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains a valid tab with its assigned index
|
/// Contains a valid tab with its assigned index
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct ChatTab(string name, int index)
|
public struct ChatTab(string name, int index, uint unreadCount)
|
||||||
{
|
{
|
||||||
[JsonProperty("name")] public string Name = name;
|
[JsonProperty("name")] public string Name = name;
|
||||||
[JsonProperty("index")] public int Index = index;
|
[JsonProperty("index")] public int Index = index;
|
||||||
|
[JsonProperty("unreadCount")] public uint UnreadCount = unreadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -21,6 +22,15 @@ public struct ChatTabList(ChatTab[] tabs)
|
|||||||
[JsonProperty("tabs")] public ChatTab[] Tabs = tabs;
|
[JsonProperty("tabs")] public ChatTab[] Tabs = tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains a valid tab index and the current unread state as a number unread of messages
|
||||||
|
/// </summary>
|
||||||
|
public struct ChatTabUnreadState(int index, uint unreadCount)
|
||||||
|
{
|
||||||
|
[JsonProperty("index")] public int Index = index;
|
||||||
|
[JsonProperty("unreadCount")] public uint UnreadCount = unreadCount;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains the current channel name
|
/// Contains the current channel name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public class CloseEvent() : BaseEvent("close");
|
|||||||
// Tab related
|
// Tab related
|
||||||
public class ChatTabListEvent(ChatTabList list) : BaseEvent("tab-list", JsonConvert.SerializeObject(list));
|
public class ChatTabListEvent(ChatTabList list) : BaseEvent("tab-list", JsonConvert.SerializeObject(list));
|
||||||
public class ChatTabSwitchedEvent(ChatTab chatTab) : BaseEvent("tab-switched", JsonConvert.SerializeObject(chatTab));
|
public class ChatTabSwitchedEvent(ChatTab chatTab) : BaseEvent("tab-switched", JsonConvert.SerializeObject(chatTab));
|
||||||
|
public class ChatTabUnreadStateEvent(ChatTabUnreadState unreadState) : BaseEvent("tab-unread-state", JsonConvert.SerializeObject(unreadState));
|
||||||
|
|
||||||
// Input channel related
|
// Input channel related
|
||||||
public class ChannelListEvent(ChannelList channelList) : BaseEvent("channel-list", JsonConvert.SerializeObject(channelList));
|
public class ChannelListEvent(ChannelList channelList) : BaseEvent("channel-list", JsonConvert.SerializeObject(channelList));
|
||||||
|
|||||||
@@ -104,12 +104,13 @@ public class Processing
|
|||||||
|
|
||||||
public ChatTab GetCurrentTab()
|
public ChatTab GetCurrentTab()
|
||||||
{
|
{
|
||||||
return new ChatTab(HostContext.Core.Plugin.CurrentTab.Name, HostContext.Core.Plugin.LastTab);
|
var currentTab = HostContext.Core.Plugin.CurrentTab;
|
||||||
|
return new ChatTab(currentTab.Name, HostContext.Core.Plugin.LastTab, currentTab.Unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatTabList GetAllTabs()
|
public ChatTabList GetAllTabs()
|
||||||
{
|
{
|
||||||
var tabs = Plugin.Config.Tabs.Select((tab, idx) => new ChatTab(tab.Name, idx)).ToArray();
|
var tabs = Plugin.Config.Tabs.Select((tab, idx) => new ChatTab(tab.Name, idx, tab.Unread)).ToArray();
|
||||||
return new ChatTabList(tabs);
|
return new ChatTabList(tabs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using ChatTwo.Http.MessageProtocol;
|
using ChatTwo.Http.MessageProtocol;
|
||||||
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
namespace ChatTwo.Http;
|
namespace ChatTwo.Http;
|
||||||
|
|
||||||
@@ -11,6 +13,27 @@ public class ServerCore : IAsyncDisposable
|
|||||||
{
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
HostContext = new HostContext(this);
|
HostContext = new HostContext(this);
|
||||||
|
|
||||||
|
Plugin.Framework.Update += FrameworkUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
Plugin.Framework.Update -= FrameworkUpdate;
|
||||||
|
await HostContext.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FrameworkUpdate(IFramework _)
|
||||||
|
{
|
||||||
|
foreach (var (tab, idx) in Plugin.Config.Tabs.WithIndex())
|
||||||
|
{
|
||||||
|
if (tab.Unread == tab.LastSendUnread)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tab.LastSendUnread = tab.Unread;
|
||||||
|
foreach (var eventServer in HostContext.EventConnections)
|
||||||
|
eventServer.OutboundQueue.Enqueue(new ChatTabUnreadStateEvent(new ChatTabUnreadState(idx, tab.Unread)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region SSE Helper
|
#region SSE Helper
|
||||||
@@ -165,9 +188,4 @@ public class ServerCore : IAsyncDisposable
|
|||||||
{
|
{
|
||||||
return await HostContext.Stop();
|
return await HostContext.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
await HostContext.DisposeAsync();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user