From b9a55eca9d8b14d8707b182cb56e2380b94b877f Mon Sep 17 00:00:00 2001 From: Gagan Suie Date: Wed, 11 Jan 2023 02:26:42 -0600 Subject: [PATCH 1/4] Feat: added chatStore and placeholder socketStore --- src/lib/stores/chatStore.ts | 399 +++++++++++++++++++++++++++++++++- src/lib/stores/followStore.ts | 18 ++ src/lib/stores/socketStore.ts | 389 +++++++++++++++++++++++++++++++++ 3 files changed, 805 insertions(+), 1 deletion(-) diff --git a/src/lib/stores/chatStore.ts b/src/lib/stores/chatStore.ts index 88d19406..10390ab6 100644 --- a/src/lib/stores/chatStore.ts +++ b/src/lib/stores/chatStore.ts @@ -1 +1,398 @@ -import { writable } from 'svelte/store' \ No newline at end of file +import { writable, type Writable } from 'svelte/store' +import { socketStore } from './socketStore' +import { PUBLIC_API_URL } from '$env/static/public' +import { userStore } from './userStore' +import { authStore } from './authStore' +import { channelStore } from './channelStore' + +class ChatStore { + public lastMessageSendDate: Date = new Date() + private skip = 0 + private limit = 100 + + constructor( + public searchQuery: Writable = writable(''), + public chats: Writable<[]> = writable([]), + public messages: Writable<[]> = writable([]), + public activeTabs: Writable<[]> = writable([]), + public isShowingSearchResults: Writable = writable(false), + ) {} + + resetSkipLimit() { + this.skip = 0 + this.limit = 100 + } + + deleteMessage({ message, channelId }: { message: any, channelId: string }) { + socketStore.emitDeleteMessageToChannel(channelId, JSON.stringify(message)) + } + + deleteAllMessages({ channelId }: { channelId: string }) { + socketStore.emitDeleteAllMessagesToChannel(channelId) + } + + public async postFile({ channelId, fileToUpload }: { channelId: string, fileToUpload: File }) { + const formData: FormData = new FormData() + formData.append('file', fileToUpload, fileToUpload.name) + formData.append('channelId', channelId) + formData.append('name', fileToUpload.name) + formData.append('type', fileToUpload.type) + return await fetch(`${PUBLIC_API_URL}/attachments/file`, { method: 'POST', body: JSON.stringify(formData) }) + } + + public async deleteFile({ key }: { key: string }) { + return await fetch(`${PUBLIC_API_URL}/attachments/file?key=${key}`, { + method: 'DELETE' + }) + } + + public async getTrendingGifs() { + return await fetch(`${PUBLIC_API_URL}/giphy/trending`, { + method: 'GET' + }).then(response => response.json()) + } + + public async searchGifs({ query }: { query: string }) { + return await fetch(`${PUBLIC_API_URL}/giphy/search?${query}`, { + method: 'GET' + }).then(response => response.json()) + } + + public async getMessages({ chat, chatType }: { chat: any, chatType: string }) { + const data = { limit: this.limit, skip: 0 } + if (chatType == 'channelChat') { + this.skip = this.skip + this.limit + data.skip = this.skip + socketStore.emitHistoryToChannel(chat.channel, data.skip) + } else if (chatType == 'oneToOneChat') { + data.skip = chat.skip + } + } + + public async sendChannelMessage({ channel, attributes }: { channel: any, attributes: any }) { + const dateNow = new Date() + const diff = Math.round( + Math.abs((dateNow.getTime() - this.lastMessageSendDate.getTime()) / 1000) + ) + if (diff <= 0.7) { + //TODO: show alert + // this.snackBar.open('Please be courteous to other users', null, { + // duration: 1000 + // }) + } else { + //TODO: get currentUser + const user: any = null + attributes.userId = user._id + attributes.avatar = user.avatar + const completeMessage = { + attributes: attributes, + body: attributes.text, + state: { timestamp: new Date().toISOString() }, + user: user, + author: user.displayName + } + socketStore.emitMessageToChannel(channel._id, completeMessage) + this.lastMessageSendDate = new Date() + // this.sendEmailAndWebNotifications({ channel: channel._id, user, attributes }) + } + } + + public async sendChatMessage({ chat, attributes }: { chat: any, attributes: any }) { + //TODO: get currentUser + const user: any = null + attributes.userId = user._id + attributes.avatar = user.avatar + const completeMessage = { + attributes: attributes, + body: attributes.text, + state: { timestamp: new Date().toISOString() }, + user: user, + author: user.displayName + } + socketStore.emitChatMessage({ source1: chat.source1, source2: chat.source2, message: completeMessage }) + this.lastMessageSendDate = new Date() + // this.sendEmailAndWebNotifications({ channel: chat._id, user, attributes }) + } + + // public async sendEmailAndWebNotifications({ channel, user, attributes }: { channel: any, user: any, attributes: any }) { + // let notificationSubscribers = [] + // notificationSubscribers = channel?.notificationSubscribers?.filter((id: any) => + // id == user._id ? false : true + // ) + // if (notificationSubscribers?.length) { + // const sendNotificationsTo: any[] = [] + // // const sendEmailsTo = [] + // notificationSubscribers = await userStore.getUsersByIds(notificationSubscribers) + // notificationSubscribers.forEach((user: any) => { + // if (user.isWebNotificationsEnabled) sendNotificationsTo.push(user._id) + // // if (user.isEmailNotificationsEnabled) sendEmailsTo.push(user._id) + // }) + // const body = `${user.customUsername}: ${attributes.text}` + // const title = `New message at ${channel.title}` + // const sendToList = [] + // // if (sendNotificationsTo.length) { + // // sendToList.push( + // // this.notificationService.sendWebNotifications({ + // // body, + // // title, + // // userIds: sendNotificationsTo + // // }) + // // ) + // // } + // // if (sendEmailsTo.length) { + // // sendToList.push(this.notificationService.sendEmails({ + // // subject: `Chat notification from codecrow.io`, message: body, name: channel.title, userIds: sendEmailsTo, url: `${environment.hostUrl}/channel/${channel._id}` + // // })) + // // } + // return Promise.all(sendToList) + // } else { + // return Promise.resolve() + // } + // } + + emitChannelChatTypingByUser({ typingUser, channelId = '' }: { typingUser: any, channelId: string }) { + if (!channelId) { + socketStore.emitChatTypingByUser(typingUser) + } else { + socketStore.emitChannelChatTypingByUser(channelId, typingUser) + } + } + + public async createChat({ source1, source2 }: { source1: string, source2: string }) { + return await fetch(`${PUBLIC_API_URL}/chats`, { + method: 'PUT', + body: JSON.stringify({ source1, source2 }), + }).then(async response => { + const res = await response.json() + //TODO: fix array push to writable + // this.chats.subscribe((value: any) => { + // const doesChatExist = value.some((cht: any) => res._id === cht._id) + // if (!doesChatExist) value.push(res) + // return res + // }) + }) + } + + public async getChat({ source1, source2 }: { source1: string, source2: string }) { + return await fetch(`${PUBLIC_API_URL}/chats/me?source1=${source1}&source2=${source2}`, { + method: 'GET' + }).then(response => response.json()) + } + + public async getChats(isRefresh = false) { + if (isRefresh) { + this.chats.set([]) + this.resetSkipLimit() + } + return await fetch(`${PUBLIC_API_URL}/chats?searchQuery=${this.searchQuery}&skip=${this.skip}&limit=${this.limit}`, { + method: 'GET' + }).then(async response => { + const res = await response.json() + //TODO: fix array push to writable + // if (chats.length) { + // this.skip += this.limit + // this.chats.push(...chats) + // } else { + //TODO: show alert + // if (this.searchQuery && !this.skip) + // this.snackBar.open('No results with the search criteria', null, { + // duration: 2000 + // }) + // } + // return this.chats + }) + } + + public async deleteChat({ chat }: { chat: any }) { + // const dialogData: DialogData = { + // title: 'Delete Chat', + // message: 'Are you sure you want to delete this chat?', + // okText: 'Yes', + // cancelText: 'Cancel' + // } + + // const dialogRef = this.dialogService.openDialog(dialogData, { + // disableClose: true + // }) + + // dialogRef.afterClosed().subscribe(async (result: any) => { + // if (result) { + await fetch(`${PUBLIC_API_URL}/chats?chatId=${chat._id}`, { + method: 'DELETE' + }).then(async response => { + await response.json() + //TODO: fix array filter to writable + // this.chats.set(this.chats.filter((cht) => cht.chat._id !== chat._id)) + }) + // } + // }) + } + + public async updateChatProperties({ chatId, updatedProperties }: { chatId: string, updatedProperties: any }) { + return await fetch(`${PUBLIC_API_URL}/chats?chatId=${chatId}`, { + method: 'PATCH', body: JSON.stringify(updatedProperties) + }).then(response => response.json()) + } + + public async incrementUnreadMessageCount({ chatId }: { chatId: string }) { + return await fetch(`${PUBLIC_API_URL}/chats?unread/chatId=${chatId}`, { + method: 'PATCH' + }) + } + + public async clearUnreadMessageCount({ chatId }: { chatId: string }) { + return await fetch(`${PUBLIC_API_URL}/chats?unread/chatId=${chatId}`, { + method: 'DELETE' + }) + } + + public async searchChats() { + this.chats.set([]) + return this.getChats(true) + } + + public async openChat({ chat, friendGroup = null }: { chat: any, friendGroup: any }) { + if (friendGroup) { + return this.activateGroupTab(friendGroup) + } + //TODO: get writable channel id + // if (!chat.chat) { + // const existingChat = await this.getChat({ + // source1: authStore.currentUser._id, + // source2: chat._id + // }) + // if (!existingChat) { + // chat = await this.createChat({ + // source1: authStore.currentUser._id, + // source2: chat._id + // }) + // } else { + // chat = existingChat + // } + // } + // this.activateChatTab(chat) + // socketStore.emitChatMessage({ + // source1: authStore.currentUser._id, + // source2: chat._id, + // message: "incoming message" + // }) + + } + + public async activateChatTab({ chat }: { chat: any }) { + const user = authStore.currentUser + if (this.checkAlreadyExist(chat)) return + //TODO: get writable activeTabs + // this.activeTabs.push(chat) + await this.clearUnreadMessageCount({ chatId: chat.chat._id }) + chat.chat.unreadMessageCount = 0 + } + + public async activateGroupTab({ group }: { group: any }) { + const user = authStore.currentUser + if (this.checkAlreadyExist(group)) return + //TODO: get writable activeTabs + // socketStore.emitChannelSubscribeByUser(group.channelId, user._id) + // this.activeTabs.push(group) + } + + checkAlreadyExist({ item }: { item: any }) { + //TODO: get writable currentUser + // const chat = this.activeTabs.find((chat) => { + // if (chat._id === item._id || ((chat.source1 === item.source1 && chat.source2 === item.source2) || + // (chat.source2 === item.source1 && chat.source1 === item.source2))) { + // return true + // } + // }) + // return (this.activeTabs.indexOf(item) !== -1) || (chat !== undefined) + return null + } + + public async incomingMessageActivateChatTab(data: any) { + const user = authStore.currentUser + const otherUser = userStore.getUserById(data.source1) + const chat = null + //TODO: get writable currentUser + // const existingChat = await this.getChat({ + // source1: authStore.currentUser._id, + // source2: data.source1 + // }) + // if (!existingChat) { + // chat = await this.createChat({ + // source1: authStore.currentUser._id, + // source2: data.source1, + // user: otherUser + // }) + // } else { + // chat = existingChat + // } + // if (!user.isDoNotDisturbEnabled) { + // chat.isUserRequestingToOpenChat = true + // this.initIncomingMessage = data + // this.activateChatTab(chat) + // } + } + + public async blockUser({ senderId, isBlocked }: { senderId: string, isBlocked: boolean }) { + //TODO: get writable channel id + // await channelStore.blockUserFromChannel({ + // channelId: channelStore.currentChannel._id, + // userId: senderId + // }) + // await channelStore.removeChannelNotificationSubscriber({ + // channelId: channelStore.currentChannel._id, + // userId: senderId + // }) + // socketStore.emitRemovedUser(channelStore.currentChannel._id, senderId) + // channelStore.currentChannel.blockedUsers?.push(senderId) + // isBlocked = channelStore.isUserBlockedFromChannel(senderId) + } + + public async unblockUser({ senderId, isBlocked }: { senderId: string, isBlocked: boolean }) { + //TODO: get writable channel id + // await channelStore.unblockUserFromChannel({ + // channelId: channelStore.currentChannel._id, + // userId: senderId + // }) + // channelStore.currentChannel.blockedUsers = + // channelStore.currentChannel.blockedUsers?.filter( + // (user) => !!(user != senderId) + // ) + // isBlocked = channelStore.isUserBlockedFromChannel(senderId) + } + + public async showDeleteMessageDialog({ oneVone, message }: { oneVone: boolean, message: any }) { + // const dialogData: DialogData = { + // title: 'Delete Message', + // message: 'Are you sure you want to delete this message?', + // okText: 'Yes', + // cancelText: 'Cancel' + // } + + // const dialogRef = this.dialogService.openDialog(dialogData, { + // disableClose: true + // }) + + // dialogRef.afterClosed().subscribe((result) => { + // if (result) { + //TODO: show alert + this.commitDeleteMessage({ oneVone, message }) + // } + // }) + } + + public async commitDeleteMessage({ oneVone, message }: { oneVone: boolean, message: any }) { + let chan = null + if (oneVone || !channelStore.currentChannel) { + chan = { _id: message.channelId } // if friend chat + } else { + chan = channelStore.currentChannel // if channel chat + } + if (chan) { + //TODO: get writable channel id + // this.deleteMessage({ message, channelId: chan._id }) + } + } +} + +export const chatStore = new ChatStore() \ No newline at end of file diff --git a/src/lib/stores/followStore.ts b/src/lib/stores/followStore.ts index 30f9403f..6185ffe5 100644 --- a/src/lib/stores/followStore.ts +++ b/src/lib/stores/followStore.ts @@ -31,6 +31,24 @@ class FollowStore { method: 'GET' }).then(response => response.json()) } + + public async toggleFollow({ follow, senderId, userId }: { follow: any, senderId: string, userId: string }) { + if (follow) { + if (!follow.isFollowing) { + await this.createFollow({ + source1: senderId, + source2: userId + }) + follow.isFollowing = true + } else { + await this.deleteFollow({ + source1: senderId, + source2: userId + }) + follow.isFollowing = false + } + } + } } export const followStore = new FollowStore() \ No newline at end of file diff --git a/src/lib/stores/socketStore.ts b/src/lib/stores/socketStore.ts index efa5f2f4..19d85730 100644 --- a/src/lib/stores/socketStore.ts +++ b/src/lib/stores/socketStore.ts @@ -3,6 +3,395 @@ import { writable } from "svelte/store" class SocketStore { + // constructor() { + // } + + // async setupWebsocketConnection(websocketId, isChannelConnection) { + // if (!isChannelConnection) { + // return new Promise((resolve) => { + // this.apiSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/wsid/${websocketId}/connect`) + + // this.apiSocket.addEventListener('open', (data) => { + // console.log("socket connection open") + // console.log(data) + // resolve(true) + // }) + // this.apiSocket.addEventListener('message', (data) => { + // console.log("listening to messages") + // console.log(data) + // }) + // this.apiSocket.addEventListener('error', (data) => { + // console.log("socket connection error") + // console.log(data) + // }) + // this.apiSocket.addEventListener('close', (data) => { + // console.log("socket connection close") + // console.log(data) + // }) + // }) + // } + // if (isChannelConnection) { + + // return new Promise((resolve) => { + // this.channelSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/channelid/${websocketId}/connect`) + + // this.channelSocket.addEventListener('open', (data) => { + // console.log("channel socket connection open") + // console.log(data) + // resolve(true) + // }) + // this.channelSocket.addEventListener('message', (data) => { + // console.log("listening to messages") + // console.log(data) + // }) + // this.channelSocket.addEventListener('error', (data) => { + // console.log("socket connection error") + // console.log(data) + // }) + // this.channelSocket.addEventListener('close', (data) => { + // console.log("socket connection close") + // console.log(data) + // }) + // }) + + // } + // } + + // setupChannelSocketConnection(channelId) { + // return this.http.get(`${environment.apiUrl}/wsinit/channelid?channelId=${channelId}`, { responseType: 'text' }).toPromise() + // } + + // async emitUserConnection(userId: string, isOnline: boolean) { + // if (!this.isBrowser) return + // return new Promise((resolve) => { + // this.apiSocket.send( + // JSON.stringify({ + // eventName: isOnline ? 'user-connect' : 'user-disconnect', + // userId: userId + // }) + // ) + // resolve(isOnline) + // }) + // } + + // listenToUserConnection(userId: string): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `user-connection-${userId}`) { + // this.sessionName = JSON.parse(data.data).user.userId + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // listenToRemovedUser(channelId): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `user-removed-${channelId}`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitRemovedUser(channelId, userId) { + // this.channelSocket.send(JSON.stringify({ eventName: `user-removed`, channelId, userId })) + // } + + // listenToChannelUpdate(channelId): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `channel-update-${channelId}`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitChannelUpdate(channelId) { + // this.channelSocket.send(JSON.stringify({ eventName: `channel-update`, channelId })) + // } + + // listenToChannelAccessRequest({ channelId }): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `channel-access-request` && JSON.parse(data.data).channelId === channelId) { + // observer.next(data) + // } + // }) + // }) + // } + + // emitChannelAccessRequest({ channelId, userId }) { + // this.apiSocket.send( + // JSON.stringify({ + // eventName: `channel-access-request`, + // channel: channelId, + // user: userId + // }) + // ) + // } + + // listenToChannelAccessResponse({ channelId }): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `channel-access-response` && JSON.parse(data.data).channelId === channelId) { + // observer.next(data) + // } + // }) + // }) + // } + + // emitChannelAccessResponse({ channelId, userId, isGrantedAccess }) { + // this.apiSocket.send( + // JSON.stringify({ + // eventName: `channel-access-response`, + // channel: channelId, + // user: userId, + // isGrantedAccess + // }) + // ) + // } + + + // /************ Recording ****************/ + + // emitVideoRecordingStarted({ channelId }) { + // this.apiSocket.send(JSON.stringify({ eventName: `video-recording-started`, channelId })) + // } + + // listenToVideoRecordingStarted({ channelId }): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `video-recording-started` && JSON.parse(data.data).channelId === channelId) { + // observer.next(JSON.parse(data.data)) + // return data + // } + // }) + // }) + // } + + // emitVideoRecordingEnded({ channelId, sessionCounter }) { + // this.apiSocket.send( + // JSON.stringify({ eventName: 'video-recording-ended', channelId, sessionCounter }) + // ) + // } + + // listenToCompositionStatusUpdate({ channelId }): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if ( + // JSON.parse(data.data).eventName === `composition-status-update` && + // JSON.parse(data.data).channelId === channelId + // ) { + // observer.next(JSON.parse(data.data)) + // return data + // } + // }) + // }) + // } + + // emitCompositionDeleted({ channelId, compositionSid }) { + // this.apiSocket.send( + // JSON.stringify({ eventName: 'composition-deleted', channelId, compositionSid }) + // ) + // } + + // listenToCompositionDeleted({ channelId }): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `composition-deleted` && JSON.parse(data.data).channelId === channelId) { + // observer.next(JSON.parse(data.data)) + // return data + // } + // }) + // }) + // } + + // /************ Chat ****************/ + + // listenToChatMessages(): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `message-received`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitChatMessage({ source1, source2, message }) { + // this.apiSocket.send(JSON.stringify({ eventName: `message-sent`, source1, source2, message })) + // } + + // listenToChatTyping(): Observable { + // return new Observable((observer) => { + // this.apiSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `chat-typing`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitChatTypingByUser(userId) { + // this.apiSocket.send( + // JSON.stringify({ + // eventName: `chat-typing`, + // user: userId, + // isTyping: true + // }) + // ) + // } + + // /************ Channel chat ****************/ + + // // listenToChannel(channelId): Observable { + // // return new Observable((observer) => { + // // this.channelSocket.addEventListener(`message`, (data) => { + // // const parsedData = JSON.parse(data.data) + // // switch (parsedData.eventName) { + // // case `channel-message-${channelId}`: + // // observer.next(JSON.parse(parsedData)) + // // break + // // } + // // }) + // // }) + // // } + + // listenToChannelMessage(channelId): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `channel-message-${channelId}`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitChannelSubscribeByUser(channelId, userId) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `channel-subscribe`, + // channel: channelId, + // userId: userId + // }) + // ) + // debugger + // } + + // emitMessageToChannel(channelId, message) { + // this.channelSocket.send( + // JSON.stringify({ eventName: `channel-message`, channel: channelId, message }) + // ) + // } + + // emitDeleteMessageToChannel(channelId, message) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `delete-channel-message`, + // channel: channelId, + // message + // }) + // ) + // } + + // emitDeleteAllMessagesToChannel(channelId) { + // this.channelSocket.send( + // JSON.stringify({ eventName: `delete-all-channel-messages`, channel: channelId }) + // ) + // } + + // emitHistoryToChannel(channelId, skip) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `channel-message-history`, + // channel: channelId, + // skip + // }) + // ) + // } + + // listenToChannelTyping(): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // if (JSON.parse(data.data).eventName === `typing`) { + // observer.next(JSON.parse(data.data)) + // } + // }) + // }) + // } + + // emitChannelChatTypingByUser(channelId, typingUser) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `channel-chat-typing`, + // channel: channelId, + // typingUser + // }) + // ) + // } + + // /************ Channel streaming ****************/ + + // listenToRoomMemberUpdate({ channelId }): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // const parsedData = JSON.parse(data.data) + // if (parsedData.eventName === `channel-streaming-room-member-update-${channelId}`) { + // console.log("parsedData", parsedData) + // observer.next(parsedData) + // } + // }) + // }) + // } + + // emitRoomMemberUpdate({ channelId, userData, isNewUser }) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: 'channel-streaming-room-member-update', + // channel: channelId, + // userData, + // isNewUser + // }) + // ) + // } + + // listenToUserActions({ channelId }): Observable { + // return new Observable((observer) => { + // this.channelSocket.addEventListener(`message`, (data) => { + // const parsedData = JSON.parse(data.data) + // if (parsedData.eventName === `channel-streaming-user-actions-${channelId}`) { + // console.log("parsedData", parsedData) + // observer.next(parsedData) + // } + // }) + // }) + // } + + // emitUserActions({ channelId, userData, message }) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `channel-streaming-user-actions`, + // channel: channelId, + // userData, + // message + // }) + // ) + // } + + // emitReactToMessage(channelId: string, message: Object, user: Object, reaction: string) { + // this.channelSocket.send( + // JSON.stringify({ + // eventName: `react-to-message`, + // channel: channelId, + // message, + // user, + // reaction + // }) + // ) + // } } export const socketStore = new SocketStore() \ No newline at end of file From a0f67e7140faa7ad4b4bf7fcf9cf4d312e6008f1 Mon Sep 17 00:00:00 2001 From: Gagan Suie Date: Wed, 11 Jan 2023 18:33:34 -0600 Subject: [PATCH 2/4] Feat: added streamStore --- src/lib/assets/styles/tailwind-output.css | 320 ++++----- src/lib/stores/channelStore.ts | 1 + src/lib/stores/chatStore.ts | 8 +- src/lib/stores/socketStore.ts | 762 +++++++++++----------- src/lib/stores/streamStore.ts | 717 +++++++++++++++++++- 5 files changed, 1214 insertions(+), 594 deletions(-) diff --git a/src/lib/assets/styles/tailwind-output.css b/src/lib/assets/styles/tailwind-output.css index 17af7f8d..734f7bcd 100644 --- a/src/lib/assets/styles/tailwind-output.css +++ b/src/lib/assets/styles/tailwind-output.css @@ -674,6 +674,40 @@ html { max-width: 1536px; } } +.alert { + display: flex; + width: 100%; + flex-direction: column; + align-items: center; + justify-content: space-between; + gap: 1rem; + --tw-bg-opacity: 1; + background-color: hsl(var(--b2, var(--b1)) / var(--tw-bg-opacity)); + padding: 1rem; + border-radius: var(--rounded-box, 1rem); +} +.alert > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0.5rem * var(--tw-space-y-reverse)); +} +@media (min-width: 768px) { + + .alert { + flex-direction: row; + } + + .alert > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0px * var(--tw-space-y-reverse)); + } +} +.alert > :where(*) { + display: flex; + align-items: center; + gap: 0.5rem; +} .avatar { position: relative; display: inline-flex; @@ -841,6 +875,14 @@ html { padding-top: 0.25rem; padding-bottom: 0.25rem; } +.\!chat { + display: grid !important; + grid-template-columns: repeat(2, minmax(0, 1fr)) !important; + -moz-column-gap: 0.75rem !important; + column-gap: 0.75rem !important; + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} .checkbox { flex-shrink: 0; --chkbg: var(--bc); @@ -2891,10 +2933,6 @@ html { .relative { position: relative; } -.inset-y-0 { - top: 0px; - bottom: 0px; -} .top-0 { top: 0px; } @@ -2979,6 +3017,9 @@ html { .mr-auto { margin-right: auto; } +.ml-0 { + margin-left: 0px; +} .-mt-64 { margin-top: -16rem; } @@ -3024,12 +3065,6 @@ html { .mt-2 { margin-top: 0.5rem; } -.mt-1 { - margin-top: 0.25rem; -} -.ml-0 { - margin-left: 0px; -} .block { display: block; } @@ -3069,6 +3104,9 @@ html { .h-10 { height: 2.5rem; } +.h-5 { + height: 1.25rem; +} .h-\[31rem\] { height: 31rem; } @@ -3090,12 +3128,6 @@ html { .h-\[375px\] { height: 375px; } -.h-5 { - height: 1.25rem; -} -.h-4 { - height: 1rem; -} .min-h-screen { min-height: 100vh; } @@ -3139,6 +3171,9 @@ html { .w-\[194px\] { width: 194px; } +.w-5 { + width: 1.25rem; +} .w-8 { width: 2rem; } @@ -3160,15 +3195,6 @@ html { .w-48 { width: 12rem; } -.w-5 { - width: 1.25rem; -} -.w-4 { - width: 1rem; -} -.w-28 { - width: 7rem; -} .min-w-0 { min-width: 0px; } @@ -3314,6 +3340,11 @@ html { margin-right: calc(2rem * var(--tw-space-x-reverse)); margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse))); } +.-space-x-px > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(-1px * var(--tw-space-x-reverse)); + margin-left: calc(-1px * calc(1 - var(--tw-space-x-reverse))); +} .space-x-6 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1.5rem * var(--tw-space-x-reverse)); @@ -3324,11 +3355,6 @@ html { margin-right: calc(0.375rem * var(--tw-space-x-reverse)); margin-left: calc(0.375rem * calc(1 - var(--tw-space-x-reverse))); } -.-space-x-px > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(-1px * var(--tw-space-x-reverse)); - margin-left: calc(-1px * calc(1 - var(--tw-space-x-reverse))); -} .divide-x > :not([hidden]) ~ :not([hidden]) { --tw-divide-x-reverse: 0; border-right-width: calc(1px * var(--tw-divide-x-reverse)); @@ -3371,10 +3397,6 @@ html { .rounded-3xl { border-radius: 1.5rem; } -.rounded-b { - border-bottom-right-radius: 0.25rem; - border-bottom-left-radius: 0.25rem; -} .rounded-l-lg { border-top-left-radius: 0.5rem; border-bottom-left-radius: 0.5rem; @@ -3383,6 +3405,10 @@ html { border-top-right-radius: 0.5rem; border-bottom-right-radius: 0.5rem; } +.rounded-b { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} .rounded-tl { border-top-left-radius: 0.25rem; } @@ -3398,9 +3424,6 @@ html { .border-t { border-top-width: 1px; } -.border-b { - border-bottom-width: 1px; -} .border-gray-300 { --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity)); @@ -3413,6 +3436,10 @@ html { --tw-border-opacity: 1; border-color: rgb(255 255 255 / var(--tw-border-opacity)); } +.border-blue-300 { + --tw-border-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-border-opacity)); +} .border-\[\#40B58A\] { --tw-border-opacity: 1; border-color: rgb(64 181 138 / var(--tw-border-opacity)); @@ -3421,10 +3448,6 @@ html { --tw-border-opacity: 1; border-color: rgb(200 25 139 / var(--tw-border-opacity)); } -.border-blue-300 { - --tw-border-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-border-opacity)); -} .border-opacity-50 { --tw-border-opacity: 0.5; } @@ -3456,6 +3479,18 @@ html { --tw-bg-opacity: 1; background-color: rgb(87 101 241 / var(--tw-bg-opacity)); } +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} +.bg-blue-50 { + --tw-bg-opacity: 1; + background-color: rgb(239 246 255 / var(--tw-bg-opacity)); +} .bg-transparent { background-color: transparent; } @@ -3494,22 +3529,6 @@ html { .bg-\[\#00000040\] { background-color: #00000040; } -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} -.bg-gray-50 { - --tw-bg-opacity: 1; - background-color: rgb(249 250 251 / var(--tw-bg-opacity)); -} -.bg-gray-100 { - --tw-bg-opacity: 1; - background-color: rgb(243 244 246 / var(--tw-bg-opacity)); -} -.bg-blue-50 { - --tw-bg-opacity: 1; - background-color: rgb(239 246 255 / var(--tw-bg-opacity)); -} .bg-hero { background-image: url('src/lib/assets/images/network-bg.png'); } @@ -3556,15 +3575,15 @@ html { .p-2 { padding: 0.5rem; } +.p-10 { + padding: 2.5rem; +} .p-2\.5 { padding: 0.625rem; } .p-3 { padding: 0.75rem; } -.p-10 { - padding: 2.5rem; -} .py-6 { padding-top: 1.5rem; padding-bottom: 1.5rem; @@ -3601,6 +3620,14 @@ html { padding-left: 2.5rem; padding-right: 2.5rem; } +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} .py-8 { padding-top: 2rem; padding-bottom: 2rem; @@ -3609,10 +3636,6 @@ html { padding-left: 1rem; padding-right: 1rem; } -.px-6 { - padding-left: 1.5rem; - padding-right: 1.5rem; -} .px-5 { padding-left: 1.25rem; padding-right: 1.25rem; @@ -3621,10 +3644,6 @@ html { padding-left: 1.75rem; padding-right: 1.75rem; } -.py-3 { - padding-top: 0.75rem; - padding-bottom: 0.75rem; -} .px-12 { padding-left: 3rem; padding-right: 3rem; @@ -3679,12 +3698,12 @@ html { .pt-24 { padding-top: 6rem; } -.pt-8 { - padding-top: 2rem; -} .pt-4 { padding-top: 1rem; } +.pt-8 { + padding-top: 2rem; +} .pt-6 { padding-top: 1.5rem; } @@ -3694,9 +3713,6 @@ html { .pt-1 { padding-top: 0.25rem; } -.pl-10 { - padding-left: 2.5rem; -} .text-left { text-align: left; } @@ -3737,13 +3753,13 @@ html { font-size: 3rem; line-height: 1; } -.text-\[13px\] { - font-size: 13px; -} .text-xs { font-size: 0.75rem; line-height: 1rem; } +.text-\[13px\] { + font-size: 13px; +} .font-bold { font-weight: 700; } @@ -3820,6 +3836,18 @@ html { --tw-text-opacity: 1; color: rgb(236 0 140 / var(--tw-text-opacity)); } +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} +.text-blue-600 { + --tw-text-opacity: 1; + color: rgb(37 99 235 / var(--tw-text-opacity)); +} .text-base-200 { --tw-text-opacity: 1; color: hsl(var(--b2, var(--b1)) / var(--tw-text-opacity)); @@ -3840,18 +3868,6 @@ html { --tw-text-opacity: 1; color: rgb(68 79 88 / var(--tw-text-opacity)); } -.text-gray-900 { - --tw-text-opacity: 1; - color: rgb(17 24 39 / var(--tw-text-opacity)); -} -.text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} -.text-blue-600 { - --tw-text-opacity: 1; - color: rgb(37 99 235 / var(--tw-text-opacity)); -} .underline { text-decoration-line: underline; } @@ -3868,11 +3884,6 @@ html { --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-md { - --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} .outline-none { outline: 2px solid transparent; outline-offset: 2px; @@ -3977,286 +3988,216 @@ html { -webkit-clip-path: polygon(100% 50%,0 0,0% 100%,100% 50%); clip-path: polygon(100% 50%,0 0,0% 100%,100% 50%); } - .before\:absolute::before { content: var(--tw-content); position: absolute; } - .before\:left-\[-18\%\]::before { content: var(--tw-content); left: -18%; } - .before\:left-\[100\%\]::before { content: var(--tw-content); left: 100%; } - .before\:left-\[50\%\]::before { content: var(--tw-content); left: 50%; } - .before\:top-\[710px\]::before { content: var(--tw-content); top: 710px; } - .before\:mt-\[11\.2px\]::before { content: var(--tw-content); margin-top: 11.2px; } - .before\:h-0::before { content: var(--tw-content); height: 0px; } - .before\:h-\[1600px\]::before { content: var(--tw-content); height: 1600px; } - .before\:w-24::before { content: var(--tw-content); width: 6rem; } - .before\:w-1::before { content: var(--tw-content); width: 0.25rem; } - .before\:translate-x-\[-50\%\]::before { content: var(--tw-content); --tw-translate-x: -50%; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } - .before\:translate-y-\[-50\%\]::before { content: var(--tw-content); --tw-translate-y: -50%; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } - .before\:rounded-\[20px\]::before { content: var(--tw-content); border-radius: 20px; } - .before\:border-t-2::before { content: var(--tw-content); border-top-width: 2px; } - .before\:border-dashed::before { content: var(--tw-content); border-style: dashed; } - .before\:border-\[\#F8F8F8\]::before { content: var(--tw-content); --tw-border-opacity: 1; border-color: rgb(248 248 248 / var(--tw-border-opacity)); } - .before\:bg-\[\#DADADA\]::before { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(218 218 218 / var(--tw-bg-opacity)); } - .before\:content-\[\'\'\]::before { --tw-content: ''; content: var(--tw-content); } - .after\:absolute::after { content: var(--tw-content); position: absolute; } - .after\:left-\[-22\.5\%\]::after { content: var(--tw-content); left: -22.5%; } - .after\:left-\[116\.8\%\]::after { content: var(--tw-content); left: 116.8%; } - .after\:mt-\[-2px\]::after { content: var(--tw-content); margin-top: -2px; } - .after\:h-7::after { content: var(--tw-content); height: 1.75rem; } - .after\:w-7::after { content: var(--tw-content); width: 1.75rem; } - .after\:rounded-full::after { content: var(--tw-content); border-radius: 9999px; } - .after\:bg-\[\#EC008C\]::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(236 0 140 / var(--tw-bg-opacity)); } - .after\:bg-\[\#C8198B\]::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(200 25 139 / var(--tw-bg-opacity)); } - .after\:bg-\[\#8A388A\]::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(138 56 138 / var(--tw-bg-opacity)); } - .after\:bg-\[\#4E3388\]::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(78 51 136 / var(--tw-bg-opacity)); } - .after\:bg-\[\#2B328C\]::after { content: var(--tw-content); --tw-bg-opacity: 1; background-color: rgb(43 50 140 / var(--tw-bg-opacity)); } - .after\:content-\[\'\'\]::after { --tw-content: ''; content: var(--tw-content); } - .focus\:border:focus { border-width: 1px; } - .focus\:border-indigo-700:focus { --tw-border-opacity: 1; border-color: rgb(67 56 202 / var(--tw-border-opacity)); } - -.focus\:border-blue-500:focus { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); -} - .focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; } - .focus\:ring-2:focus { --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); } - .focus\:ring-white:focus { --tw-ring-opacity: 1; --tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity)); } - -.focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); -} - .hover\:border-\[\#5765f1\]:hover { --tw-border-opacity: 1; border-color: rgb(87 101 241 / var(--tw-border-opacity)); } - .hover\:border-white:hover { --tw-border-opacity: 1; border-color: rgb(255 255 255 / var(--tw-border-opacity)); } - .hover\:border-\[\#40B58A\]:hover { --tw-border-opacity: 1; border-color: rgb(64 181 138 / var(--tw-border-opacity)); } - .hover\:border-\[\#C8198B\]:hover { --tw-border-opacity: 1; border-color: rgb(200 25 139 / var(--tw-border-opacity)); } - .hover\:bg-\[\#5765f1\]:hover { --tw-bg-opacity: 1; background-color: rgb(87 101 241 / var(--tw-bg-opacity)); } - -.hover\:bg-transparent:hover { - background-color: transparent; -} - -.hover\:bg-\[\#C8198B\]:hover { - --tw-bg-opacity: 1; - background-color: rgb(200 25 139 / var(--tw-bg-opacity)); -} - .hover\:bg-gray-50:hover { --tw-bg-opacity: 1; background-color: rgb(249 250 251 / var(--tw-bg-opacity)); } - .hover\:bg-gray-100:hover { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } - .hover\:bg-blue-100:hover { --tw-bg-opacity: 1; background-color: rgb(219 234 254 / var(--tw-bg-opacity)); } - +.hover\:bg-transparent:hover { + background-color: transparent; +} +.hover\:bg-\[\#C8198B\]:hover { + --tw-bg-opacity: 1; + background-color: rgb(200 25 139 / var(--tw-bg-opacity)); +} .hover\:text-gray-700:hover { --tw-text-opacity: 1; color: rgb(55 65 81 / var(--tw-text-opacity)); } - .hover\:text-blue-700:hover { --tw-text-opacity: 1; color: rgb(29 78 216 / var(--tw-text-opacity)); } - .hover\:underline:hover { text-decoration-line: underline; } - @media (prefers-color-scheme: dark) { - .dark\:border-gray-600 { - --tw-border-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-border-opacity)); - } - .dark\:border-gray-700 { --tw-border-opacity: 1; border-color: rgb(55 65 81 / var(--tw-border-opacity)); } - .dark\:bg-gray-900 { - --tw-bg-opacity: 1; - background-color: rgb(17 24 39 / var(--tw-bg-opacity)); - } - .dark\:bg-gray-700 { --tw-bg-opacity: 1; background-color: rgb(55 65 81 / var(--tw-bg-opacity)); @@ -4282,35 +4223,6 @@ html { color: rgb(59 130 246 / var(--tw-text-opacity)); } - .dark\:placeholder-gray-400::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); - } - - .dark\:placeholder-gray-400::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(156 163 175 / var(--tw-placeholder-opacity)); - } - - .dark\:ring-offset-gray-800 { - --tw-ring-offset-color: #1f2937; - } - - .dark\:focus\:border-blue-500:focus { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); - } - - .dark\:focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); - } - - .dark\:focus\:ring-blue-600:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(37 99 235 / var(--tw-ring-opacity)); - } - .dark\:hover\:bg-gray-600:hover { --tw-bg-opacity: 1; background-color: rgb(75 85 99 / var(--tw-bg-opacity)); @@ -4326,7 +4238,6 @@ html { color: rgb(255 255 255 / var(--tw-text-opacity)); } } - @media (min-width: 640px) { .sm\:col-span-2 { @@ -4373,12 +4284,7 @@ html { margin-top: calc(6rem * calc(1 - var(--tw-space-y-reverse))); margin-bottom: calc(6rem * var(--tw-space-y-reverse)); } - - .sm\:rounded-lg { - border-radius: 0.5rem; - } } - @media (min-width: 768px) { .md\:gap-4 { @@ -4389,7 +4295,6 @@ html { gap: 1.5rem; } } - @media (min-width: 1024px) { .lg\:order-2 { @@ -4534,7 +4439,6 @@ html { text-align: right; } } - @media (min-width: 1280px) { .xl\:mb-0 { diff --git a/src/lib/stores/channelStore.ts b/src/lib/stores/channelStore.ts index e4d1e01e..d56aeacf 100644 --- a/src/lib/stores/channelStore.ts +++ b/src/lib/stores/channelStore.ts @@ -211,6 +211,7 @@ class ChannelStore { } async leaveChannel({ userId, deleteOrLeaveOnExit = false }: { userId: string, deleteOrLeaveOnExit?: boolean }) { + //TODO: fix writeable subscribe this.currentChannel.subscribe(async value => { if (value) { if (value.user === userId) { diff --git a/src/lib/stores/chatStore.ts b/src/lib/stores/chatStore.ts index 10390ab6..a6cdffd1 100644 --- a/src/lib/stores/chatStore.ts +++ b/src/lib/stores/chatStore.ts @@ -1,9 +1,9 @@ import { writable, type Writable } from 'svelte/store' -import { socketStore } from './socketStore' +import { socketStore } from '$lib/stores/socketStore' import { PUBLIC_API_URL } from '$env/static/public' -import { userStore } from './userStore' -import { authStore } from './authStore' -import { channelStore } from './channelStore' +import { userStore } from '$lib/stores/userStore' +import { authStore } from '$lib/stores/authStore' +import { channelStore } from '$lib/stores/channelStore' class ChatStore { public lastMessageSendDate: Date = new Date() diff --git a/src/lib/stores/socketStore.ts b/src/lib/stores/socketStore.ts index 19d85730..d32accff 100644 --- a/src/lib/stores/socketStore.ts +++ b/src/lib/stores/socketStore.ts @@ -3,395 +3,395 @@ import { writable } from "svelte/store" class SocketStore { - // constructor() { - // } - - // async setupWebsocketConnection(websocketId, isChannelConnection) { - // if (!isChannelConnection) { - // return new Promise((resolve) => { - // this.apiSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/wsid/${websocketId}/connect`) - - // this.apiSocket.addEventListener('open', (data) => { - // console.log("socket connection open") - // console.log(data) - // resolve(true) - // }) - // this.apiSocket.addEventListener('message', (data) => { - // console.log("listening to messages") - // console.log(data) - // }) - // this.apiSocket.addEventListener('error', (data) => { - // console.log("socket connection error") - // console.log(data) - // }) - // this.apiSocket.addEventListener('close', (data) => { - // console.log("socket connection close") - // console.log(data) - // }) - // }) - // } - // if (isChannelConnection) { - - // return new Promise((resolve) => { - // this.channelSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/channelid/${websocketId}/connect`) - - // this.channelSocket.addEventListener('open', (data) => { - // console.log("channel socket connection open") - // console.log(data) - // resolve(true) - // }) - // this.channelSocket.addEventListener('message', (data) => { - // console.log("listening to messages") - // console.log(data) - // }) - // this.channelSocket.addEventListener('error', (data) => { - // console.log("socket connection error") - // console.log(data) - // }) - // this.channelSocket.addEventListener('close', (data) => { - // console.log("socket connection close") - // console.log(data) - // }) - // }) - - // } - // } - - // setupChannelSocketConnection(channelId) { - // return this.http.get(`${environment.apiUrl}/wsinit/channelid?channelId=${channelId}`, { responseType: 'text' }).toPromise() - // } - - // async emitUserConnection(userId: string, isOnline: boolean) { - // if (!this.isBrowser) return - // return new Promise((resolve) => { - // this.apiSocket.send( - // JSON.stringify({ - // eventName: isOnline ? 'user-connect' : 'user-disconnect', - // userId: userId - // }) - // ) - // resolve(isOnline) - // }) - // } - - // listenToUserConnection(userId: string): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `user-connection-${userId}`) { - // this.sessionName = JSON.parse(data.data).user.userId - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // listenToRemovedUser(channelId): Observable { - // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `user-removed-${channelId}`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitRemovedUser(channelId, userId) { - // this.channelSocket.send(JSON.stringify({ eventName: `user-removed`, channelId, userId })) - // } - - // listenToChannelUpdate(channelId): Observable { - // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `channel-update-${channelId}`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitChannelUpdate(channelId) { - // this.channelSocket.send(JSON.stringify({ eventName: `channel-update`, channelId })) - // } - - // listenToChannelAccessRequest({ channelId }): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `channel-access-request` && JSON.parse(data.data).channelId === channelId) { - // observer.next(data) - // } - // }) - // }) - // } - - // emitChannelAccessRequest({ channelId, userId }) { - // this.apiSocket.send( - // JSON.stringify({ - // eventName: `channel-access-request`, - // channel: channelId, - // user: userId - // }) - // ) - // } - - // listenToChannelAccessResponse({ channelId }): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `channel-access-response` && JSON.parse(data.data).channelId === channelId) { - // observer.next(data) - // } - // }) - // }) - // } - - // emitChannelAccessResponse({ channelId, userId, isGrantedAccess }) { - // this.apiSocket.send( - // JSON.stringify({ - // eventName: `channel-access-response`, - // channel: channelId, - // user: userId, - // isGrantedAccess - // }) - // ) - // } - - - // /************ Recording ****************/ - - // emitVideoRecordingStarted({ channelId }) { - // this.apiSocket.send(JSON.stringify({ eventName: `video-recording-started`, channelId })) - // } - - // listenToVideoRecordingStarted({ channelId }): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `video-recording-started` && JSON.parse(data.data).channelId === channelId) { - // observer.next(JSON.parse(data.data)) - // return data - // } - // }) - // }) - // } - - // emitVideoRecordingEnded({ channelId, sessionCounter }) { - // this.apiSocket.send( - // JSON.stringify({ eventName: 'video-recording-ended', channelId, sessionCounter }) - // ) - // } - - // listenToCompositionStatusUpdate({ channelId }): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if ( - // JSON.parse(data.data).eventName === `composition-status-update` && - // JSON.parse(data.data).channelId === channelId - // ) { - // observer.next(JSON.parse(data.data)) - // return data - // } - // }) - // }) - // } - - // emitCompositionDeleted({ channelId, compositionSid }) { - // this.apiSocket.send( - // JSON.stringify({ eventName: 'composition-deleted', channelId, compositionSid }) - // ) - // } - - // listenToCompositionDeleted({ channelId }): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `composition-deleted` && JSON.parse(data.data).channelId === channelId) { - // observer.next(JSON.parse(data.data)) - // return data - // } - // }) - // }) - // } - - // /************ Chat ****************/ - - // listenToChatMessages(): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `message-received`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitChatMessage({ source1, source2, message }) { - // this.apiSocket.send(JSON.stringify({ eventName: `message-sent`, source1, source2, message })) - // } - - // listenToChatTyping(): Observable { - // return new Observable((observer) => { - // this.apiSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `chat-typing`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitChatTypingByUser(userId) { - // this.apiSocket.send( - // JSON.stringify({ - // eventName: `chat-typing`, - // user: userId, - // isTyping: true - // }) - // ) - // } - - // /************ Channel chat ****************/ - - // // listenToChannel(channelId): Observable { - // // return new Observable((observer) => { - // // this.channelSocket.addEventListener(`message`, (data) => { - // // const parsedData = JSON.parse(data.data) - // // switch (parsedData.eventName) { - // // case `channel-message-${channelId}`: - // // observer.next(JSON.parse(parsedData)) - // // break - // // } - // // }) - // // }) - // // } - - // listenToChannelMessage(channelId): Observable { - // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `channel-message-${channelId}`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitChannelSubscribeByUser(channelId, userId) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `channel-subscribe`, - // channel: channelId, - // userId: userId - // }) - // ) - // debugger - // } - - // emitMessageToChannel(channelId, message) { - // this.channelSocket.send( - // JSON.stringify({ eventName: `channel-message`, channel: channelId, message }) - // ) - // } - - // emitDeleteMessageToChannel(channelId, message) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `delete-channel-message`, - // channel: channelId, - // message - // }) - // ) - // } - - // emitDeleteAllMessagesToChannel(channelId) { - // this.channelSocket.send( - // JSON.stringify({ eventName: `delete-all-channel-messages`, channel: channelId }) - // ) - // } - - // emitHistoryToChannel(channelId, skip) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `channel-message-history`, - // channel: channelId, - // skip - // }) - // ) - // } - - // listenToChannelTyping(): Observable { - // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { - // if (JSON.parse(data.data).eventName === `typing`) { - // observer.next(JSON.parse(data.data)) - // } - // }) - // }) - // } - - // emitChannelChatTypingByUser(channelId, typingUser) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `channel-chat-typing`, - // channel: channelId, - // typingUser - // }) - // ) - // } - - // /************ Channel streaming ****************/ - - // listenToRoomMemberUpdate({ channelId }): Observable { - // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { - // const parsedData = JSON.parse(data.data) - // if (parsedData.eventName === `channel-streaming-room-member-update-${channelId}`) { - // console.log("parsedData", parsedData) - // observer.next(parsedData) - // } - // }) - // }) - // } - - // emitRoomMemberUpdate({ channelId, userData, isNewUser }) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: 'channel-streaming-room-member-update', - // channel: channelId, - // userData, - // isNewUser - // }) - // ) - // } - - // listenToUserActions({ channelId }): Observable { + constructor() { + } + + async setupWebsocketConnection(websocketId, isChannelConnection) { + if (!isChannelConnection) { + return new Promise((resolve) => { + this.apiSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/wsid/${websocketId}/connect`) + + this.apiSocket.addEventListener('open', (data) => { + console.log("socket connection open") + console.log(data) + resolve(true) + }) + this.apiSocket.addEventListener('message', (data) => { + console.log("listening to messages") + console.log(data) + }) + this.apiSocket.addEventListener('error', (data) => { + console.log("socket connection error") + console.log(data) + }) + this.apiSocket.addEventListener('close', (data) => { + console.log("socket connection close") + console.log(data) + }) + }) + } + if (isChannelConnection) { + + return new Promise((resolve) => { + this.channelSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/channelid/${websocketId}/connect`) + + this.channelSocket.addEventListener('open', (data) => { + console.log("channel socket connection open") + console.log(data) + resolve(true) + }) + this.channelSocket.addEventListener('message', (data) => { + console.log("listening to messages") + console.log(data) + }) + this.channelSocket.addEventListener('error', (data) => { + console.log("socket connection error") + console.log(data) + }) + this.channelSocket.addEventListener('close', (data) => { + console.log("socket connection close") + console.log(data) + }) + }) + + } + } + + setupChannelSocketConnection(channelId) { + return this.http.get(`${environment.apiUrl}/wsinit/channelid?channelId=${channelId}`, { responseType: 'text' }).toPromise() + } + + async emitUserConnection(userId: string, isOnline: boolean) { + if (!this.isBrowser) return + return new Promise((resolve) => { + this.apiSocket.send( + JSON.stringify({ + eventName: isOnline ? 'user-connect' : 'user-disconnect', + userId: userId + }) + ) + resolve(isOnline) + }) + } + + listenToUserConnection(userId: string): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `user-connection-${userId}`) { + this.sessionName = JSON.parse(data.data).user.userId + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + listenToRemovedUser(channelId): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `user-removed-${channelId}`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitRemovedUser(channelId, userId) { + this.channelSocket.send(JSON.stringify({ eventName: `user-removed`, channelId, userId })) + } + + listenToChannelUpdate(channelId): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `channel-update-${channelId}`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitChannelUpdate(channelId) { + this.channelSocket.send(JSON.stringify({ eventName: `channel-update`, channelId })) + } + + listenToChannelAccessRequest({ channelId }): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `channel-access-request` && JSON.parse(data.data).channelId === channelId) { + observer.next(data) + } + }) + }) + } + + emitChannelAccessRequest({ channelId, userId }) { + this.apiSocket.send( + JSON.stringify({ + eventName: `channel-access-request`, + channel: channelId, + user: userId + }) + ) + } + + listenToChannelAccessResponse({ channelId }): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `channel-access-response` && JSON.parse(data.data).channelId === channelId) { + observer.next(data) + } + }) + }) + } + + emitChannelAccessResponse({ channelId, userId, isGrantedAccess }) { + this.apiSocket.send( + JSON.stringify({ + eventName: `channel-access-response`, + channel: channelId, + user: userId, + isGrantedAccess + }) + ) + } + + + /************ Recording ****************/ + + emitVideoRecordingStarted({ channelId }) { + this.apiSocket.send(JSON.stringify({ eventName: `video-recording-started`, channelId })) + } + + listenToVideoRecordingStarted({ channelId }): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `video-recording-started` && JSON.parse(data.data).channelId === channelId) { + observer.next(JSON.parse(data.data)) + return data + } + }) + }) + } + + emitVideoRecordingEnded({ channelId, sessionCounter }) { + this.apiSocket.send( + JSON.stringify({ eventName: 'video-recording-ended', channelId, sessionCounter }) + ) + } + + listenToCompositionStatusUpdate({ channelId }): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if ( + JSON.parse(data.data).eventName === `composition-status-update` && + JSON.parse(data.data).channelId === channelId + ) { + observer.next(JSON.parse(data.data)) + return data + } + }) + }) + } + + emitCompositionDeleted({ channelId, compositionSid }) { + this.apiSocket.send( + JSON.stringify({ eventName: 'composition-deleted', channelId, compositionSid }) + ) + } + + listenToCompositionDeleted({ channelId }): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `composition-deleted` && JSON.parse(data.data).channelId === channelId) { + observer.next(JSON.parse(data.data)) + return data + } + }) + }) + } + + /************ Chat ****************/ + + listenToChatMessages(): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `message-received`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitChatMessage({ source1, source2, message }) { + this.apiSocket.send(JSON.stringify({ eventName: `message-sent`, source1, source2, message })) + } + + listenToChatTyping(): Observable { + return new Observable((observer) => { + this.apiSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `chat-typing`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitChatTypingByUser(userId) { + this.apiSocket.send( + JSON.stringify({ + eventName: `chat-typing`, + user: userId, + isTyping: true + }) + ) + } + + /************ Channel chat ****************/ + + // listenToChannel(channelId): Observable { // return new Observable((observer) => { // this.channelSocket.addEventListener(`message`, (data) => { // const parsedData = JSON.parse(data.data) - // if (parsedData.eventName === `channel-streaming-user-actions-${channelId}`) { - // console.log("parsedData", parsedData) - // observer.next(parsedData) + // switch (parsedData.eventName) { + // case `channel-message-${channelId}`: + // observer.next(JSON.parse(parsedData)) + // break // } // }) // }) // } - // emitUserActions({ channelId, userData, message }) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `channel-streaming-user-actions`, - // channel: channelId, - // userData, - // message - // }) - // ) - // } - - // emitReactToMessage(channelId: string, message: Object, user: Object, reaction: string) { - // this.channelSocket.send( - // JSON.stringify({ - // eventName: `react-to-message`, - // channel: channelId, - // message, - // user, - // reaction - // }) - // ) - // } + listenToChannelMessage(channelId): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `channel-message-${channelId}`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitChannelSubscribeByUser(channelId, userId) { + this.channelSocket.send( + JSON.stringify({ + eventName: `channel-subscribe`, + channel: channelId, + userId: userId + }) + ) + debugger + } + + emitMessageToChannel(channelId, message) { + this.channelSocket.send( + JSON.stringify({ eventName: `channel-message`, channel: channelId, message }) + ) + } + + emitDeleteMessageToChannel(channelId, message) { + this.channelSocket.send( + JSON.stringify({ + eventName: `delete-channel-message`, + channel: channelId, + message + }) + ) + } + + emitDeleteAllMessagesToChannel(channelId) { + this.channelSocket.send( + JSON.stringify({ eventName: `delete-all-channel-messages`, channel: channelId }) + ) + } + + emitHistoryToChannel(channelId, skip) { + this.channelSocket.send( + JSON.stringify({ + eventName: `channel-message-history`, + channel: channelId, + skip + }) + ) + } + + listenToChannelTyping(): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + if (JSON.parse(data.data).eventName === `typing`) { + observer.next(JSON.parse(data.data)) + } + }) + }) + } + + emitChannelChatTypingByUser(channelId, typingUser) { + this.channelSocket.send( + JSON.stringify({ + eventName: `channel-chat-typing`, + channel: channelId, + typingUser + }) + ) + } + + /************ Channel streaming ****************/ + + listenToRoomMemberUpdate({ channelId }): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + const parsedData = JSON.parse(data.data) + if (parsedData.eventName === `channel-streaming-room-member-update-${channelId}`) { + console.log("parsedData", parsedData) + observer.next(parsedData) + } + }) + }) + } + + emitRoomMemberUpdate({ channelId, userData, isNewUser }) { + this.channelSocket.send( + JSON.stringify({ + eventName: 'channel-streaming-room-member-update', + channel: channelId, + userData, + isNewUser + }) + ) + } + + listenToUserActions({ channelId }): Observable { + return new Observable((observer) => { + this.channelSocket.addEventListener(`message`, (data) => { + const parsedData = JSON.parse(data.data) + if (parsedData.eventName === `channel-streaming-user-actions-${channelId}`) { + console.log("parsedData", parsedData) + observer.next(parsedData) + } + }) + }) + } + + emitUserActions({ channelId, userData, message }) { + this.channelSocket.send( + JSON.stringify({ + eventName: `channel-streaming-user-actions`, + channel: channelId, + userData, + message + }) + ) + } + + emitReactToMessage(channelId: string, message: Object, user: Object, reaction: string) { + this.channelSocket.send( + JSON.stringify({ + eventName: `react-to-message`, + channel: channelId, + message, + user, + reaction + }) + ) + } } export const socketStore = new SocketStore() \ No newline at end of file diff --git a/src/lib/stores/streamStore.ts b/src/lib/stores/streamStore.ts index 88d19406..ccfa6781 100644 --- a/src/lib/stores/streamStore.ts +++ b/src/lib/stores/streamStore.ts @@ -1 +1,716 @@ -import { writable } from 'svelte/store' \ No newline at end of file +import { writable, type Writable } from 'svelte/store' +import { PUBLIC_API_URL } from '$env/static/public' +import { channelStore } from '$lib/stores/channelStore' +import { socketStore } from '$lib/stores/socketStore' + +class StreamStore { + public videoStreamId = '' + public hasActiveTracks = false + + public userData: { + id: string + avatar: any + customUsername: any + displayName: string + userType: string + obsState: string + screenState: string + webcamState: string + audioState: string + isHandRaised: boolean + obsStream: any + screenStream: any + webcamStream: any + audioStream: any + } = { + id: '', + avatar: null, + customUsername: null, + displayName: '', + userType: 'listener', + obsState: 'restricted', + screenState: 'restricted', + webcamState: 'restricted', + audioState: 'restricted', + isHandRaised: false, + obsStream: null, + screenStream: null, + webcamStream: null, + audioStream: null + } + + public streamOptions: { + isRecording: boolean + isLiveStreaming: boolean + isEveryoneSilenced: boolean + duration: number + hasWaitedOneSecondObs: boolean + hasWaitedOneSecondScreen: boolean + hasWaitedOneSecondWebcam: boolean + hasWaitedOneSecondAudio: boolean + hasWaitedOneSecondRecord: boolean + hasWaitedOneSecondRaiseHand: boolean + hasWaitedOneSecondSilence: boolean + isTimedOut: boolean + isMaxLimitReached: boolean + } = { + isRecording: false, + isLiveStreaming: false, + isEveryoneSilenced: true, + duration: 0, + hasWaitedOneSecondObs: true, + hasWaitedOneSecondScreen: true, + hasWaitedOneSecondWebcam: true, + hasWaitedOneSecondAudio: true, + hasWaitedOneSecondRecord: true, + hasWaitedOneSecondRaiseHand: true, + hasWaitedOneSecondSilence: true, + isTimedOut: false, + isMaxLimitReached: false + } + + constructor( + public roomMembers: Writable<[]> = writable([]), + public channelMembersCount: Writable = writable(0), + ) {} + + async getMembers({ channelId, isParticipant, skip, limit }: { channelId: string, isParticipant: boolean, skip: number, limit: number }) { + return await fetch(`${PUBLIC_API_URL}/channel-members?channelId=${channelId}&isParticipant=${isParticipant}&skip=${skip}&limit=${limit}`, { + method: 'GET', + }).then(response => response.json()) + } + + async getChannelMembersCount({ channelId }: { channelId: string }) { + return await fetch(`${PUBLIC_API_URL}/channel-members/count?channelId=${channelId}`, { + method: 'GET' + }).then(response => response.json()) + } + + async initRoomMembers() { + //TODO: get currenChannel writeable + // this.roomMembers = await this.getMembers({ + // channelId: channelStore.currentChannel._id, + // isParticipant: true, + // skip: 0, + // limit: 10 + // }) + // this.channelMembersCount = await this.getChannelMembersCount({ + // channelId: channelStore.currentChannel._id + // }) + // Object.assign(this.userData, this.getMember(this.authService.currentUser)) + // const doesUserExist = this.roomMembers.some((member) => member.id == this.userData.id) + // if (channelStore.currentChannel.user === this.userData.id && !doesUserExist) { + // this.roomMembers.push(this.userData) + // } + // socketStore.emitRoomMemberUpdate({ + // channelId: channelStore.currentChannel._id, + // userData: this.userData, + // isNewUser: true + // }) + // this.listenToRoomMemberUpdate() + // this.listenToUserActions() + + // this.streamOptions.isEveryoneSilenced = + // channelStore.currentChannel.isEveryoneSilenced + // if (channelStore.currentChannel.user === this.authService.currentUser._id) { + // await this.createLiveStream( + // channelStore.currentChannel._id, + // `${channelStore.currentChannel.title}-${channelStore.currentChannel.user}` + // ) + // await channelStore.updateIsStreaming({ + // channelId: channelStore.currentChannel._id, + // isStreaming: true + // }) + // } + } + + listenToRoomMemberUpdate() { + //TODO: fix subscribing to writeables + // this.roomMembersSubscription = socketStore + // .listenToRoomMemberUpdate({ + // channelId: channelStore.currentChannel._id + // }) + // .subscribe(async (data) => { + // if (channelStore.currentChannel) { + // if (data.isNewUser) { + // const doesUserExist = this.roomMembers.some( + // (member) => member.id == data.userData.id + // ) + // if (!doesUserExist && data.userData.userType != 'listener') { + // this.roomMembers.push(data.userData) + // if (this.userData.id == data.userData.id) { + // this.userData = data.userData + // } + // } + // } else if (!data.isNewUser) { + // const index = this.roomMembers.findIndex( + // (item) => item.id == data.userData.id + // ) + // if (index > -1) this.roomMembers.splice(index, 1) + // if (this.userData.id == data.userData.id) { + // this.userData = data.userData + // } + // } + // if (data.userData.obsStream) this.attachTrack(data.userData.obsStream, data.userData.id, 'obs') + // if (data.userData.screenStream) this.attachTrack(data.userData.screenStream, data.userData.id, 'screen') + // if (data.userData.webcamStream) this.attachTrack(data.userData.webcamStream, data.userData.id, 'webcam') + // if (data.userData.audioStream) this.attachTrack(data.userData.audioStream, data.userData.id, 'audio') + // this.channelMembersCount = await this.getChannelMembersCount({ + // channelId: channelStore.currentChannel._id + // }) + // console.log("this.channelMembersCount", this.channelMembersCount) + // channelStore.currentChannel.memberCount = this.channelMembersCount + // } + // }) + } + + listenToUserActions() { + //TODO: fix subscribing to writeables + // this.userActionsSubscription = socketStore + // .listenToUserActions({ + // channelId: channelStore.currentChannel._id + // }) + // .subscribe(async (data) => { + // const messageData = JSON.parse(data.message) + // let member = this.roomMembers.find((member) => member.id == messageData.userId) + // if (!member) member = data.userData + // switch (messageData.type) { + // case 'toggleTrack': + // if (messageData.trackType === 'obs') { member.obsState === 'live' ? this.attachTrack(member.obsStream, data.userData.id, 'obs') : this.detachTrack(member.id, 'obs') } + // if (messageData.trackType === 'screen' && this.userData.id !== member.id) { + // member.screenState === 'live' ? this.attachTrack(member.screenStream, member.id, 'screen') : this.detachTrack(member.id, 'screen') + // } + // if (messageData.trackType === 'webcam' && this.userData.id !== member.id) { member.webcamState === 'live' ? this.attachTrack(member.webcamStream, member.id, 'webcam') : this.detachTrack(member.id, 'webcam') } + // if (messageData.trackType === 'audio' && this.userData.id !== member.id) { member.audioState === 'live' ? this.attachTrack(member.audioStream, member.id, 'audio') : this.detachTrack(member.id, 'audio') } + // break; + // case 'toggleRaiseHand': + // if (channelStore.currentChannel.user == this.userData.id && + // this.userData.id != messageData.userId && + // messageData.isHandRaised + // ) { + // const snackBarRef = this.snackBar.open( + // `${member.displayName} would like to participate`, + // 'Allow', + // { duration: 5000, verticalPosition: 'top' } + // ) + // snackBarRef.onAction().subscribe(() => { + // try { + // this.toggleUserType(member, true) + // } catch (err) { + // console.log(err) + // } + // }) + // // this.inAppSnackBarService.openSnackBar(`${member} would like to participate`, 'error', 3000, 'bottom', 'center') + // } + // break + // case 'toggleSilenceOnEveryone': + // this.streamOptions.isEveryoneSilenced = messageData.isEveryoneSilenced + // if (this.userData.id !== channelStore.currentChannel.user) { + // await this.stopObsStream() + // await this.stopScreenStream() + // await this.stopWebcamStream() + // await this.stopAudioStream() + // } + // break + // case 'toggleRestriction': + // switch (messageData.featureType) { + // case 'obs': + // if (member.id === messageData.userId) { + // member.obsState = messageData.featureState + // } + // if (this.userData.id === messageData.userId) { + // this.userData.obsState = messageData.featureState + // await this.stopObsStream(this.userData.obsState) + // } + // break + // case 'screen': + // if (member.id === messageData.userId) { + // member.screenState = messageData.featureState + // } + // if (this.userData.id === messageData.userId) { + // this.userData.screenState = messageData.featureState + // await this.stopScreenStream(this.userData.screenState) + // } + // break + // case 'webcam': + // if (member.id === messageData.userId) { + // member.webcamState = messageData.featureState + // } + // if (this.userData.id === messageData.userId) { + // this.userData.webcamState = messageData.featureState + // await this.stopWebcamStream(this.userData.webcamState) + // } + // break + // case 'audio': + // if (member.id === messageData.userId) { + // member.audioState = messageData.featureState + // } + // if (this.userData.id === messageData.userId) { + // this.userData.audioState = messageData.featureState + // await this.stopAudioStream(this.userData.audioState) + // } + // break + // } + // break + // } + // this.updateUserInRoom(member) + // }) + } + + disconnected() { + console.log('disconnected') + //TODO: determine if this is needed + // if (!this.sharedService.wasHomePressed) { + // window.location.href = '/' + // } + this.streamOptions = { + isRecording: false, + isLiveStreaming: false, + isEveryoneSilenced: false, + duration: 0, + hasWaitedOneSecondObs: true, + hasWaitedOneSecondScreen: true, + hasWaitedOneSecondWebcam: true, + hasWaitedOneSecondAudio: true, + hasWaitedOneSecondRecord: true, + hasWaitedOneSecondRaiseHand: true, + hasWaitedOneSecondSilence: true, + isTimedOut: false, + isMaxLimitReached: false + } + this.videoStreamId = '' + this.roomMembers.set([]) + this.hasActiveTracks = false + //TODO: determine if this is needed + // this.sharedService.wasHomePressed = false + + //TODO: fix sockets + // socketStore.emitRoomMemberUpdate({ + // channelId: channelStore.currentChannel._id, + // userData: this.userData, + // isNewUser: false + // }) + // if (this.authService.currentUser && channelStore.currentChannel.user == this.authService.currentUser._id) { + // this.updateLiveStream() + // channelStore.updateIsStreaming({ + // channelId: channelStore.currentChannel._id, + // isStreaming: false + // }) + // } + } + + getMember({ _id, avatar, customUsername, displayName, obsStream, screenStream, webcamStream, audioStream } + : { _id: string, avatar: string, customUsername: string, displayName: string, obsStream: string, screenStream: string, webcamStream: string, audioStream: string }) { + return { + id: _id, + avatar: avatar, + customUsername: customUsername, + displayName: displayName, + userType: '',//TODO: fix subscribing to writeables _id == channelStore.currentChannel.user ? 'host' : 'listener', + obsState: 'hibernate', + screenState: 'hibernate', + webcamState: 'hibernate', + audioState: 'hibernate', + isHandRaised: false, + obsStream, + screenStream, + webcamStream, + audioStream + } + } + + updateUserInRoom(userData: any) { + //TODO: fix subscribing to writeables + // const roomUser = this.roomMembers.find((member) => member.id == userData.id) + // if (roomUser) { + // Object.assign(roomUser, userData) + // } else { + // if (userData.userType != 'listener') this.roomMembers.push(userData) + // } + } + + async startObsStream() { + if (this.streamOptions.hasWaitedOneSecondObs) { + this.waitOneSecondObs() + const trackName = `obs-${this.userData.id}` + const liveInput = await this.getLiveInput({ meta: { name: trackName }, recording: { mode: "automatic" } }) + this.userData.obsStream = liveInput + this.userData.obsState = 'live' + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'obs' }) + this.streamOptions.isLiveStreaming = true + // this.sfxService.playAudio(SoundEffect.StartedSharingScreen) + this.waitOneSecondObs() + this.checkForActiveTracks() + //TODO: show alert + // this.dialogService.openDialog({ + // title: 'Streaming Information', + // message: `URL: + ${liveInput.webRTC.url}`, + // okText: 'OK' + // }, { + // disableClose: true + // }) + } + } + + async stopObsStream(state = 'hibernate') { + await this.deleteLiveInput({ inputId: this.userData.obsStream?.uid }) + this.streamOptions.isLiveStreaming = false + this.userData.obsStream = null + this.userData.obsState = state + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'obs' }) + this.detachTrack({ memberId: this.userData.id, trackType: 'obs' }) + this.checkForActiveTracks() + } + + async startScreenStream() { + if (this.streamOptions.hasWaitedOneSecondScreen) { + this.waitOneSecondScreen() + const trackName = `screen-${this.userData.id}` + const liveInput = await this.getLiveInput({ meta: { name: trackName }, recording: { mode: "automatic" } }) + this.userData.screenStream = liveInput + const videoElement = this.createVideoElement({ memberId: this.userData.id, trackType: 'screen' }) + //TODO: add WHIPClient + // const input = new WHIPClient(liveInput.webRTC.url, videoElement, 'screen') + this.userData.screenState = 'live' + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'screen' }) + // this.userData.screenStream.on('stopped', () => { + // this.stopScreenStream() + // }) + this.streamOptions.isLiveStreaming = true + // this.sfxService.playAudio(SoundEffect.StartedSharingScreen) + this.waitOneSecondScreen() + this.checkForActiveTracks() + } + } + + createVideoElement({ memberId, trackType }: { memberId: string, trackType: string }): HTMLVideoElement { + const container = trackType !== 'audio' ? document.getElementById('screen_container') : document.getElementById('audio_container') + //TODO: get htmlviewelement in sveltekit + const videoElement: HTMLVideoElement = new HTMLVideoElement()//this.renderer.createElement('video') + videoElement.setAttribute('id', `${trackType}-${memberId}`) + videoElement.setAttribute('autoplay', 'autoplay') + + const { matches: isMobile } = window.matchMedia('(max-width: 767px)') + if (videoElement) { + if (isMobile) { + videoElement.style.width = '80%' + videoElement.style.cssText = + 'scroll-snap-align: center; width: 80%!important; margin: 0 0.5rem;' + } else { + videoElement.style.width = '100%' + } + videoElement.addEventListener('dblclick', (event) => { + if (document.fullscreenElement) { + document.exitFullscreen() + } else { + videoElement.requestFullscreen() + } + }) + videoElement.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + videoElement.scrollIntoView() + }) + } + + container?.append(videoElement) + + if (isMobile) { + const allVideoElements = Array.prototype.slice.call( + container?.getElementsByTagName('video') + ) + allVideoElements.forEach((element, i) => { + if (i === 0) element.style.marginLeft = '10%' + else element.style.marginLeft = '0.5rem' + if (allVideoElements.length === i + 1) element.style.marginRight = '10%' + else element.style.marginRight = '0.5rem' + }) + } + + return videoElement + } + + attachTrack({ liveInput, memberId, trackType }: { liveInput: any, memberId: string, trackType: string }) { + const videoElement = this.createVideoElement({ memberId, trackType }) + //TODO: add WHEPClient + // const output = new WHEPClient(liveInput.webRTCPlayback.url, videoElement) + } + + detachTrack({ memberId, trackType }: { memberId: string, trackType: string }) { + const videoElement = document.getElementById(`${trackType}-${memberId}`) + videoElement?.remove() + } + + async stopScreenStream(state = 'hibernate') { + await this.deleteLiveInput({ inputId: this.userData.screenStream?.uid }) + this.streamOptions.isLiveStreaming = false + this.userData.screenStream = null + this.userData.screenState = state + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'screen' }) + this.detachTrack({ memberId: this.userData.id, trackType: 'screen' }) + this.checkForActiveTracks() + } + + async startWebcamStream() { + if (this.streamOptions.hasWaitedOneSecondWebcam) { + this.waitOneSecondWebcam() + const trackName = `webcam-${this.userData.id}` + const liveInput = await this.getLiveInput({ meta: { name: trackName }, recording: { mode: "automatic" } }) + this.userData.webcamStream = liveInput + const videoElement = this.createVideoElement({ memberId: this.userData.id, trackType: 'webcam' }) + //TODO: add WHIPClient + // const input = new WHIPClient(liveInput.webRTC.url, videoElement, 'webcam') + this.userData.screenState = 'live' + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'webcam' }) + // this.userData.webcamStream.on('stopped', () => { + // this.stopWebcamStream() + // }) + this.waitOneSecondWebcam() + this.checkForActiveTracks() + } + } + + async stopWebcamStream(state = 'hibernate') { + await this.deleteLiveInput({ inputId: this.userData.webcamStream?.uid }) + this.userData.webcamStream = null + this.userData.webcamState = state + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'webcam' }) + this.detachTrack({ memberId: this.userData.id, trackType: 'webcam' }) + this.checkForActiveTracks() + } + + async startAudioStream() { + if (this.streamOptions.hasWaitedOneSecondAudio) { + this.waitOneSecondAudio() + const trackName = `audio-${this.userData.id}` + const liveInput = await this.getLiveInput({ meta: { name: trackName }, recording: { mode: "automatic" } }) + this.userData.audioStream = liveInput + const videoElement = this.createVideoElement({ memberId: this.userData.id, trackType: 'audio' }) + //TODO: add WHIPClient + // const input = new WHIPClient(liveInput.webRTC.url, videoElement, 'audio') + this.userData.audioState = 'live' + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'audio' }) + // this.userData.audioStream.onended = () => { + // this.stopAudioStream() + // } + this.waitOneSecondAudio() + this.checkForActiveTracks() + } + } + + async stopAudioStream(state = 'hibernate') { + await this.deleteLiveInput({ inputId: this.userData.audioStream?.uid }) + this.userData.audioStream = null + this.userData.audioState = state + this.updateUserInRoom(this.userData) + this.sendDataToRoom({ type: 'toggleTrack', trackType: 'audio' }) + this.detachTrack({ memberId: this.userData.id, trackType: 'audio' }) + this.checkForActiveTracks() + } + + //TODO: uncomment when adding video recording or when time limit for live streams + checkForActiveTracks() { + // this.hasActiveTracks = this.roomMembers.some(member => member.screenStream != null || member.webcamStream != null || member.audioStream != null) + // if (!this.hasActiveTracks) this.endRecording() + } + + async leaveRoom() { + if (channelStore.currentChannel) { + this.disconnected() + this.stopObsStream() + this.stopScreenStream() + this.stopWebcamStream() + this.stopAudioStream() + //TODO: fix subscribring to room members writeable + // if (this.roomMembersSubscription) { + // this.roomMembersSubscription.unsubscribe() + // } + // if (this.userActionsSubscription) { + // this.userActionsSubscription.unsubscribe() + // } + } + } + + toggleRaiseHand() { + if (this.streamOptions.hasWaitedOneSecondRaiseHand) { + this.waitOneSecondRaiseHand() + // this.sfxService.playAudio(SoundEffect.AskedToSpeak) + this.sendDataToRoom({ + type: 'toggleRaiseHand', + userId: this.userData.id, + isHandRaised: true + }) + } + } + + toggleSilenceOnEveryone() { + if (this.streamOptions.hasWaitedOneSecondSilence) { + this.waitOneSecondSilence() + this.streamOptions.isEveryoneSilenced = !this.streamOptions.isEveryoneSilenced + this.sendDataToRoom({ + type: 'toggleSilenceOnEveryone', + isEveryoneSilenced: this.streamOptions.isEveryoneSilenced + }) + //TODO: fix channel writeable + // channelStore.updateChannelProperties({ + // channelId: channelStore.currentChannel._id, + // updatedProperties: { + // isEveryoneSilenced: this.streamOptions.isEveryoneSilenced + // } + // }) + } + } + + toggleUserType({ user, isHandRaised = false }: { user: any, isHandRaised: boolean }) { + //TODO: fix channel writeable + // if (user.userType === 'listener' || isHandRaised) { + // user.userType = 'participant' + // user.isHandRaised = false + // socketStore.emitRoomMemberUpdate({ + // channelId: channelStore.currentChannel._id, + // userData: user, + // isNewUser: true + // }) + // } else if (user.userType === 'participant') { + // user.userType = 'listener' + // socketStore.emitRoomMemberUpdate({ + // channelId: channelStore.currentChannel._id, + // userData: user, + // isNewUser: false + // }) + // } + } + + toggleRestriction({ user, featureType }: { user: any, featureType: string }) { + let featureState = 'hibernate' + switch (featureType) { + case 'screen': + if (user.screenState === 'restricted') { + featureState = 'hibernate' + } else { + featureState = 'restricted' + } + user.screenState = featureState + break + case 'webcam': + if (user.webcamState === 'restricted') { + featureState = 'hibernate' + } else { + featureState = 'restricted' + } + user.webcamState = featureState + break + case 'audio': + if (user.audioState === 'restricted') { + featureState = 'hibernate' + } else { + featureState = 'restricted' + } + user.audioState = featureState + break + } + this.sendDataToRoom({ + type: 'toggleRestriction', + userId: user.id, + featureType: featureType, + featureState: featureState + }) + } + + sendDataToRoom(message: any) { + if (channelStore.currentChannel) { + socketStore.emitUserActions({ + channelId: '',//TODO: get channelId from writeable channelStore.currentChannel._id, + userData: this.userData, + message: JSON.stringify(message) + }) + } + } + + public waitOneSecondObs() { + this.streamOptions.hasWaitedOneSecondObs = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondObs = true + }, 1500) + } + + public waitOneSecondScreen() { + this.streamOptions.hasWaitedOneSecondScreen = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondScreen = true + }, 1500) + } + + public waitOneSecondWebcam() { + this.streamOptions.hasWaitedOneSecondWebcam = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondWebcam = true + }, 1500) + } + + public waitOneSecondAudio() { + this.streamOptions.hasWaitedOneSecondAudio = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondAudio = true + }, 1500) + } + + public waitOneSecondRecord() { + this.streamOptions.hasWaitedOneSecondRecord = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondRecord = true + }, 1500) + } + + public waitOneSecondRaiseHand() { + this.streamOptions.hasWaitedOneSecondRaiseHand = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondRaiseHand = true + }, 3000) + } + + public waitOneSecondSilence() { + this.streamOptions.hasWaitedOneSecondSilence = false + setTimeout(async () => { + this.streamOptions.hasWaitedOneSecondSilence = true + }, 3000) + } + + async createLiveStream({ channelId, title }: { channelId: string, title: string }) { + return await fetch(`${PUBLIC_API_URL}/streams`, { + method: 'POST', + body: JSON.stringify({ channel: channelId, title }) + }).then(async response => { + const res = await response.json() + this.videoStreamId = res._id + }) + } + + async updateLiveStream() { + if (this.videoStreamId) { + return await fetch(`${PUBLIC_API_URL}/streams/${this.videoStreamId}/end`, {}) + } + } + + async getLiveInput(trackData: any) { + return await fetch(`${PUBLIC_API_URL}/cloudflare/live-input`, { + method: 'POST', + body: JSON.stringify(trackData) + }).then(response => response.json()) + } + + async deleteLiveInput({ inputId }: { inputId: string }) { + return await fetch(`${PUBLIC_API_URL}/cloudflare/live-input?inputId=${inputId}`, { + method: 'DELETE' + }) + } +} + +export const streamStore = new StreamStore() \ No newline at end of file From f8289be1f5c256162b67ee2a42e1189c90487f2c Mon Sep 17 00:00:00 2001 From: Gagan Suie Date: Thu, 12 Jan 2023 21:33:05 -0600 Subject: [PATCH 3/4] Feat: added socketStore --- src/lib/stores/socketStore.ts | 499 +++++++++++++++++----------------- 1 file changed, 248 insertions(+), 251 deletions(-) diff --git a/src/lib/stores/socketStore.ts b/src/lib/stores/socketStore.ts index d32accff..4f4a45ce 100644 --- a/src/lib/stores/socketStore.ts +++ b/src/lib/stores/socketStore.ts @@ -1,130 +1,100 @@ -import { PUBLIC_API_URL } from '$env/static/public' -import { writable } from "svelte/store" +import { PUBLIC_API_URL, PUBLIC_WEBSOCKET_URL } from '$env/static/public' +import { writable, type Writable } from "svelte/store" class SocketStore { + public platformSocket: WebSocket | undefined + public channelSocket: WebSocket | undefined + + constructor( + public platformConnection: Writable = writable(), + public channelConnection: Writable = writable(), + public platformMessage: Writable = writable(), + public channelMessage: Writable = writable(), + ) {} + + public async getApiSocket() { + return await fetch(`${PUBLIC_API_URL}/wsinit/wsid`, { + method: 'GET', + }).then(async response => { + const data = await response.text() + await this.setupWebsocketConnection({ websocketId: data, isChannelConnection: false }) + }) + } - constructor() { + public async getChannelSocket({ channelId }: { channelId: string }) { + return await fetch(`${PUBLIC_API_URL}/wsinit/channelid?channelId=${channelId}`, { + method: 'GET', + }).then(async response => { + const data = await response.text() + await this.setupWebsocketConnection({ websocketId: data, isChannelConnection: true }) + }) } - async setupWebsocketConnection(websocketId, isChannelConnection) { + async setupWebsocketConnection({ websocketId, isChannelConnection }: { websocketId: string, isChannelConnection: boolean }) { if (!isChannelConnection) { - return new Promise((resolve) => { - this.apiSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/wsid/${websocketId}/connect`) - - this.apiSocket.addEventListener('open', (data) => { - console.log("socket connection open") - console.log(data) - resolve(true) - }) - this.apiSocket.addEventListener('message', (data) => { - console.log("listening to messages") - console.log(data) - }) - this.apiSocket.addEventListener('error', (data) => { - console.log("socket connection error") - console.log(data) - }) - this.apiSocket.addEventListener('close', (data) => { - console.log("socket connection close") - console.log(data) - }) + this.platformSocket = new WebSocket(`${PUBLIC_WEBSOCKET_URL}/wsinit/wsid/${websocketId}/connect`) + this.platformSocket?.addEventListener('open', (data) => { + console.log("socket connection open") + console.log(data) + this.platformConnection.set('open') }) - } - if (isChannelConnection) { - - return new Promise((resolve) => { - this.channelSocket = new WebSocket(`${environment.webSocketUrl}/wsinit/channelid/${websocketId}/connect`) - - this.channelSocket.addEventListener('open', (data) => { - console.log("channel socket connection open") - console.log(data) - resolve(true) - }) - this.channelSocket.addEventListener('message', (data) => { - console.log("listening to messages") - console.log(data) - }) - this.channelSocket.addEventListener('error', (data) => { - console.log("socket connection error") - console.log(data) - }) - this.channelSocket.addEventListener('close', (data) => { - console.log("socket connection close") - console.log(data) - }) + this.platformSocket?.addEventListener('message', (data) => { + console.log("listening to messages") + console.log(data) + this.platformMessage.set(data) }) - - } - } - - setupChannelSocketConnection(channelId) { - return this.http.get(`${environment.apiUrl}/wsinit/channelid?channelId=${channelId}`, { responseType: 'text' }).toPromise() - } - - async emitUserConnection(userId: string, isOnline: boolean) { - if (!this.isBrowser) return - return new Promise((resolve) => { - this.apiSocket.send( - JSON.stringify({ - eventName: isOnline ? 'user-connect' : 'user-disconnect', - userId: userId - }) - ) - resolve(isOnline) - }) - } - - listenToUserConnection(userId: string): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `user-connection-${userId}`) { - this.sessionName = JSON.parse(data.data).user.userId - observer.next(JSON.parse(data.data)) - } + this.platformSocket?.addEventListener('error', (data) => { + console.log("socket connection error") + console.log(data) }) - }) - } - - listenToRemovedUser(channelId): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `user-removed-${channelId}`) { - observer.next(JSON.parse(data.data)) - } + this.platformSocket?.addEventListener('close', (data) => { + console.log("socket connection close") + console.log(data) + this.platformConnection.set('close') }) - }) - } - - emitRemovedUser(channelId, userId) { - this.channelSocket.send(JSON.stringify({ eventName: `user-removed`, channelId, userId })) + } else { + this.channelSocket = new WebSocket(`${PUBLIC_WEBSOCKET_URL}/wsinit/channelid/${websocketId}/connect`) + this.channelSocket?.addEventListener('open', (data) => { + console.log("channel socket connection open") + console.log(data) + this.channelConnection.set('open') + }) + this.channelSocket?.addEventListener('message', (data) => { + console.log("listening to messages") + console.log(data) + this.channelMessage.set(data) + }) + this.channelSocket?.addEventListener('error', (data) => { + console.log("socket connection error") + console.log(data) + }) + this.channelSocket?.addEventListener('close', (data) => { + console.log("socket connection close") + console.log(data) + this.channelConnection.set('close') + }) + } } - listenToChannelUpdate(channelId): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `channel-update-${channelId}`) { - observer.next(JSON.parse(data.data)) - } + async emitUserConnection(userId: string, isOnline: boolean) { + this.platformSocket?.send( + JSON.stringify({ + eventName: isOnline ? 'user-connect' : 'user-disconnect', + userId: userId }) - }) + ) } - emitChannelUpdate(channelId) { - this.channelSocket.send(JSON.stringify({ eventName: `channel-update`, channelId })) + emitRemovedUser({ channelId, userId }: { channelId: string, userId: string }) { + this.channelSocket?.send(JSON.stringify({ eventName: `user-removed`, channelId, userId })) } - listenToChannelAccessRequest({ channelId }): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `channel-access-request` && JSON.parse(data.data).channelId === channelId) { - observer.next(data) - } - }) - }) + emitChannelUpdate({ channelId }: { channelId: string }) { + this.channelSocket?.send(JSON.stringify({ eventName: `channel-update`, channelId })) } - emitChannelAccessRequest({ channelId, userId }) { - this.apiSocket.send( + emitChannelAccessRequest({ channelId, userId }: { channelId: string, userId: string }) { + this.platformSocket?.send( JSON.stringify({ eventName: `channel-access-request`, channel: channelId, @@ -133,18 +103,8 @@ class SocketStore { ) } - listenToChannelAccessResponse({ channelId }): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `channel-access-response` && JSON.parse(data.data).channelId === channelId) { - observer.next(data) - } - }) - }) - } - - emitChannelAccessResponse({ channelId, userId, isGrantedAccess }) { - this.apiSocket.send( + emitChannelAccessResponse({ channelId, userId, isGrantedAccess }: { channelId: string, userId: string, isGrantedAccess: boolean }) { + this.platformSocket?.send( JSON.stringify({ eventName: `channel-access-response`, channel: channelId, @@ -154,89 +114,32 @@ class SocketStore { ) } - /************ Recording ****************/ - emitVideoRecordingStarted({ channelId }) { - this.apiSocket.send(JSON.stringify({ eventName: `video-recording-started`, channelId })) - } - - listenToVideoRecordingStarted({ channelId }): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `video-recording-started` && JSON.parse(data.data).channelId === channelId) { - observer.next(JSON.parse(data.data)) - return data - } - }) - }) + emitVideoRecordingStarted({ channelId }: { channelId: string }) { + this.platformSocket?.send(JSON.stringify({ eventName: `video-recording-started`, channelId })) } - emitVideoRecordingEnded({ channelId, sessionCounter }) { - this.apiSocket.send( + emitVideoRecordingEnded({ channelId, sessionCounter }: { channelId: string, sessionCounter: number }) { + this.platformSocket?.send( JSON.stringify({ eventName: 'video-recording-ended', channelId, sessionCounter }) ) } - listenToCompositionStatusUpdate({ channelId }): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if ( - JSON.parse(data.data).eventName === `composition-status-update` && - JSON.parse(data.data).channelId === channelId - ) { - observer.next(JSON.parse(data.data)) - return data - } - }) - }) - } - - emitCompositionDeleted({ channelId, compositionSid }) { - this.apiSocket.send( + emitCompositionDeleted({ channelId, compositionSid }: { channelId: string, compositionSid: string }) { + this.platformSocket?.send( JSON.stringify({ eventName: 'composition-deleted', channelId, compositionSid }) ) } - listenToCompositionDeleted({ channelId }): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `composition-deleted` && JSON.parse(data.data).channelId === channelId) { - observer.next(JSON.parse(data.data)) - return data - } - }) - }) - } - /************ Chat ****************/ - listenToChatMessages(): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `message-received`) { - observer.next(JSON.parse(data.data)) - } - }) - }) - } - - emitChatMessage({ source1, source2, message }) { - this.apiSocket.send(JSON.stringify({ eventName: `message-sent`, source1, source2, message })) + emitChatMessage({ source1, source2, message }: { source1: string, source2: string, message: string }) { + this.platformSocket?.send(JSON.stringify({ eventName: `message-sent`, source1, source2, message })) } - listenToChatTyping(): Observable { - return new Observable((observer) => { - this.apiSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `chat-typing`) { - observer.next(JSON.parse(data.data)) - } - }) - }) - } - - emitChatTypingByUser(userId) { - this.apiSocket.send( + emitChatTypingByUser({ userId }: { userId: string }) { + this.platformSocket?.send( JSON.stringify({ eventName: `chat-typing`, user: userId, @@ -249,7 +152,7 @@ class SocketStore { // listenToChannel(channelId): Observable { // return new Observable((observer) => { - // this.channelSocket.addEventListener(`message`, (data) => { + // this.channelSocket?.addEventListener(`message`, (data) => { // const parsedData = JSON.parse(data.data) // switch (parsedData.eventName) { // case `channel-message-${channelId}`: @@ -260,35 +163,24 @@ class SocketStore { // }) // } - listenToChannelMessage(channelId): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `channel-message-${channelId}`) { - observer.next(JSON.parse(data.data)) - } - }) - }) - } - - emitChannelSubscribeByUser(channelId, userId) { - this.channelSocket.send( + emitChannelSubscribeByUser({ channelId, userId }: { channelId: string, userId: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `channel-subscribe`, channel: channelId, userId: userId }) ) - debugger } - emitMessageToChannel(channelId, message) { - this.channelSocket.send( + emitMessageToChannel({ channelId, message }: { channelId: string, message: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `channel-message`, channel: channelId, message }) ) } - emitDeleteMessageToChannel(channelId, message) { - this.channelSocket.send( + emitDeleteMessageToChannel({ channelId, message }: { channelId: string, message: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `delete-channel-message`, channel: channelId, @@ -297,14 +189,14 @@ class SocketStore { ) } - emitDeleteAllMessagesToChannel(channelId) { - this.channelSocket.send( + emitDeleteAllMessagesToChannel({ channelId }: { channelId: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `delete-all-channel-messages`, channel: channelId }) ) } - emitHistoryToChannel(channelId, skip) { - this.channelSocket.send( + emitHistoryToChannel({ channelId, skip }: { channelId: string, skip: number }) { + this.channelSocket?.send( JSON.stringify({ eventName: `channel-message-history`, channel: channelId, @@ -313,18 +205,8 @@ class SocketStore { ) } - listenToChannelTyping(): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - if (JSON.parse(data.data).eventName === `typing`) { - observer.next(JSON.parse(data.data)) - } - }) - }) - } - - emitChannelChatTypingByUser(channelId, typingUser) { - this.channelSocket.send( + emitChannelChatTypingByUser({ channelId, typingUser }: { channelId: string, typingUser: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `channel-chat-typing`, channel: channelId, @@ -335,20 +217,8 @@ class SocketStore { /************ Channel streaming ****************/ - listenToRoomMemberUpdate({ channelId }): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - const parsedData = JSON.parse(data.data) - if (parsedData.eventName === `channel-streaming-room-member-update-${channelId}`) { - console.log("parsedData", parsedData) - observer.next(parsedData) - } - }) - }) - } - - emitRoomMemberUpdate({ channelId, userData, isNewUser }) { - this.channelSocket.send( + emitRoomMemberUpdate({ channelId, userData, isNewUser }: { channelId: string, userData: any, isNewUser: boolean }) { + this.channelSocket?.send( JSON.stringify({ eventName: 'channel-streaming-room-member-update', channel: channelId, @@ -358,20 +228,8 @@ class SocketStore { ) } - listenToUserActions({ channelId }): Observable { - return new Observable((observer) => { - this.channelSocket.addEventListener(`message`, (data) => { - const parsedData = JSON.parse(data.data) - if (parsedData.eventName === `channel-streaming-user-actions-${channelId}`) { - console.log("parsedData", parsedData) - observer.next(parsedData) - } - }) - }) - } - - emitUserActions({ channelId, userData, message }) { - this.channelSocket.send( + emitUserActions({ channelId, userData, message }: { channelId: string, userData: any, message: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `channel-streaming-user-actions`, channel: channelId, @@ -381,8 +239,8 @@ class SocketStore { ) } - emitReactToMessage(channelId: string, message: Object, user: Object, reaction: string) { - this.channelSocket.send( + emitReactToMessage({ channelId, message, user, reaction }: { channelId: string, message: any, user: any, reaction: string }) { + this.channelSocket?.send( JSON.stringify({ eventName: `react-to-message`, channel: channelId, @@ -392,6 +250,145 @@ class SocketStore { }) ) } + + + + + + + + + + //TODO: place these everywhere we are using socket listeners + + listenToUserConnection({ userId }: { userId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `user-connection-${userId}`) { + //parsedData.user + } + }) + } + + listenToRemovedUser({ channelId }: { channelId: string }) { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `user-removed-${channelId}`) { + //parsedData.userId + } + }) + } + + listenToChannelUpdate({ channelId }: { channelId: string }) { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-update-${channelId}`) { + // this.channelService.currentChannel.description = parsedData.channel.description + // this.channelService.currentChannel.thumbnail = parsedData.channel.thumbnail + // this.channelService.currentChannel.isPrivate = parsedData.channel.isPrivate + // this.channelService.currentChannel.attachments = parsedData.channel.attachments + } + }) + } + + listenToChannelAccessRequest({ channelId }: { channelId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-access-request` && parsedData.channelId === channelId) { + console.log("parsedData", parsedData) + } + }) + } + + listenToChannelAccessResponse({ channelId }: { channelId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-access-response` && parsedData.channelId === channelId) { + console.log("parsedData", parsedData) + } + }) + } + + listenToVideoRecordingStarted({ channelId }: { channelId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `video-recording-started` && parsedData.channelId === channelId) { + console.log("parsedData", parsedData) + } + }) + } + + listenToCompositionStatusUpdate({ channelId }: { channelId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `composition-status-update` && parsedData.channelId === channelId) { + console.log("parsedData", parsedData) + } + }) + } + + listenToCompositionDeleted({ channelId }: { channelId: string }) { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `composition-deleted` && parsedData.channelId === channelId) { + console.log("parsedData", parsedData) + } + }) + } + + listenToChatMessages() { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `message-received`) { + console.log("parsedData", parsedData) + } + }) + } + + listenToChatTyping() { + this.platformMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `chat-typing`) { + console.log("parsedData", parsedData) + } + }) + } + + listenToChannelMessage({ channelId }: { channelId: string }) { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-message-${channelId}`) { + console.log("parsedData", parsedData) + } + }) + } + + listenToChannelTyping() { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `typing`) { + console.log("parsedData", parsedData) + } + }) + } + + listenToRoomMemberUpdate({ channelId }: { channelId: string }) { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-streaming-room-member-update-${channelId}`) { + console.log("parsedData", parsedData) + } + }) + } + + listenToUserActions({ channelId }: { channelId: string }) { + this.channelMessage.subscribe(value => { + const parsedData = JSON.parse(value.data) + if (parsedData.eventName === `channel-streaming-user-actions-${channelId}`) { + console.log("parsedData", parsedData) + } + }) + } } export const socketStore = new SocketStore() \ No newline at end of file From eac17434c462823d18b41627980ab9d98d564d78 Mon Sep 17 00:00:00 2001 From: Gagan Suie Date: Thu, 12 Jan 2023 21:35:13 -0600 Subject: [PATCH 4/4] Chore: socketStore formatting --- src/lib/stores/socketStore.ts | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/lib/stores/socketStore.ts b/src/lib/stores/socketStore.ts index 4f4a45ce..53b188d1 100644 --- a/src/lib/stores/socketStore.ts +++ b/src/lib/stores/socketStore.ts @@ -76,13 +76,8 @@ class SocketStore { } } - async emitUserConnection(userId: string, isOnline: boolean) { - this.platformSocket?.send( - JSON.stringify({ - eventName: isOnline ? 'user-connect' : 'user-disconnect', - userId: userId - }) - ) + async emitUserConnection({ userId, isOnline }: { userId: string, isOnline: boolean }) { + this.platformSocket?.send(JSON.stringify({ eventName: isOnline ? 'user-connect' : 'user-disconnect', userId: userId })) } emitRemovedUser({ channelId, userId }: { channelId: string, userId: string }) { @@ -94,24 +89,11 @@ class SocketStore { } emitChannelAccessRequest({ channelId, userId }: { channelId: string, userId: string }) { - this.platformSocket?.send( - JSON.stringify({ - eventName: `channel-access-request`, - channel: channelId, - user: userId - }) - ) + this.platformSocket?.send(JSON.stringify({ eventName: `channel-access-request`, channel: channelId, user: userId })) } emitChannelAccessResponse({ channelId, userId, isGrantedAccess }: { channelId: string, userId: string, isGrantedAccess: boolean }) { - this.platformSocket?.send( - JSON.stringify({ - eventName: `channel-access-response`, - channel: channelId, - user: userId, - isGrantedAccess - }) - ) + this.platformSocket?.send(JSON.stringify({ eventName: `channel-access-response`, channel: channelId, user: userId, isGrantedAccess })) } /************ Recording ****************/