-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create / edit message plus subscription
- Loading branch information
Showing
5 changed files
with
183 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,107 @@ | ||
import { Realtime } from 'ably/promises'; | ||
import { Types } from 'ably/promises'; | ||
import { ChatApi } from './ChatApi.js'; | ||
import { Message } from './entities.js'; | ||
import RealtimeChannelPromise = Types.RealtimeChannelPromise; | ||
import { MessageEvents } from './events.js'; | ||
|
||
const enum Direction { | ||
ascending = 'ascending', | ||
descending = 'descending', | ||
export const enum Direction { | ||
forwards = 'forwards', | ||
backwards = 'backwards', | ||
} | ||
|
||
interface QueryOptions { | ||
from: string; | ||
to: string; | ||
limit: string; | ||
direction: Direction; | ||
startId?: string; | ||
endId?: string; | ||
limit: number; | ||
direction?: keyof typeof Direction; | ||
} | ||
|
||
interface MessageListenerArgs { | ||
type: MessageEvents; | ||
message: Message; | ||
} | ||
|
||
type MessageListener = (args: MessageListenerArgs) => void; | ||
type ChannelListener = Types.messageCallback<Types.Message>; | ||
|
||
export class Messages { | ||
private readonly conversationId: string; | ||
private readonly realtime: Realtime; | ||
private readonly channel: RealtimeChannelPromise; | ||
private readonly chatApi: ChatApi; | ||
private messageToChannelListener = new WeakMap<MessageListener, ChannelListener>(); | ||
|
||
constructor(conversationId: string, realtime: Realtime, chatApi: ChatApi) { | ||
constructor(conversationId: string, channel: RealtimeChannelPromise, chatApi: ChatApi) { | ||
this.conversationId = conversationId; | ||
this.realtime = realtime; | ||
this.channel = channel; | ||
this.chatApi = chatApi; | ||
} | ||
|
||
// eslint-disable-next-line | ||
async query(options: QueryOptions) { | ||
return []; | ||
async query(options: QueryOptions): Promise<Message[]> { | ||
return this.chatApi.getMessages(this.conversationId, options); | ||
} | ||
|
||
async send(text: string): Promise<Message> { | ||
const createdMessages: Record<string, Message> = {}; | ||
|
||
let waitingMessageId: string | null = null; | ||
let resolver: ((message: Message) => void) | null = null; | ||
|
||
const waiter = ({ data }: Types.Message) => { | ||
const message: Message = data; | ||
if (waitingMessageId == null) createdMessages[message.id] = message; | ||
if (waitingMessageId == message.id) resolver?.(message); | ||
}; | ||
|
||
await this.channel.subscribe(MessageEvents.created, waiter); | ||
const { id } = await this.chatApi.sendMessage(this.conversationId, text); | ||
|
||
if (createdMessages[id]) return createdMessages[id]; | ||
|
||
waitingMessageId = id; | ||
|
||
return new Promise((resolve) => { | ||
resolver = (message) => { | ||
this.channel.unsubscribe(MessageEvents.created, waiter); | ||
resolve(message); | ||
}; | ||
}); | ||
} | ||
|
||
async edit(messageId: string, text: string): Promise<Message> { | ||
let resolver: ((message: Message) => void) | null = null; | ||
const waiter = ({ data }: Types.Message) => { | ||
const message: Message = data; | ||
if (messageId == message.id) resolver?.(message); | ||
}; | ||
|
||
const promise: Promise<Message> = new Promise((resolve) => { | ||
resolver = (message) => { | ||
this.channel.unsubscribe(MessageEvents.updated, waiter); | ||
resolve(message); | ||
}; | ||
}); | ||
|
||
await this.channel.subscribe(MessageEvents.updated, waiter); | ||
await this.chatApi.editMessage(this.conversationId, messageId, text); | ||
|
||
return promise; | ||
} | ||
|
||
async subscribe(event: MessageEvents, listener: MessageListener) { | ||
const channelListener = ({ name, data }: Types.Message) => { | ||
listener({ | ||
type: name as MessageEvents, | ||
message: data, | ||
}); | ||
}; | ||
this.messageToChannelListener.set(listener, channelListener); | ||
return this.channel.subscribe(event, channelListener); | ||
} | ||
|
||
unsubscribe(event: MessageEvents, listener: MessageListener) { | ||
const channelListener = this.messageToChannelListener.get(listener); | ||
if (!channelListener) return; | ||
this.channel.unsubscribe(event, channelListener); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
export interface Conversation { | ||
id: string; | ||
application_id: string; | ||
ttl: number | null; | ||
created_at: number; | ||
} | ||
|
||
export interface Message { | ||
id: string; | ||
client_id: string; | ||
conversation_id: string; | ||
content: string; | ||
reactions: { | ||
counts: Record<string, number>; | ||
latest: Reaction[]; | ||
mine: Reaction[]; | ||
}; | ||
created_at: number; | ||
updated_at: number | null; | ||
deleted_at: number | null; | ||
} | ||
|
||
export interface Reaction { | ||
id: string; | ||
message_id: string; | ||
type: string; | ||
client_id: string; | ||
updated_at: number | null; | ||
deleted_at: number | null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const enum MessageEvents { | ||
created = 'message.created', | ||
updated = 'message.updated', | ||
deleted = 'message.deleted', | ||
} |