UNPKG

librecast-live

Version:

Live Streaming Video Platform with IPv6 Multicast

126 lines (111 loc) 3.94 kB
// eslint-disable-next-line no-unused-vars class Chat { constructor (lctx) { this.lctx = lctx this.sockets = {} this.channels = {} this.sockidx = {} this.lastmsgs = [] this.lastmsg = 0 store.subscribe('state.chat', this.chatStateUpdated) store.subscribe('state.activeChannel', this.changeChannel) } chatStateUpdated () { console.log('Chat.chatStateUpdated') } changeChannel = () => { console.log('Chat.changeChannel') if (this.channels[store.state.activeChannel] === undefined) { this.join(store.state.activeChannel) } } join = channelName => { this.lctx.onconnect.then(() => { const p = [] this.sockets[channelName] = new LIBRECAST.Socket(this.lctx) this.channels[channelName] = new LIBRECAST.Channel(this.lctx, channelName) p.push(this.sockets[channelName].oncreate) p.push(this.channels[channelName].oncreate) Promise.all(p).then(() => { console.log('socket and channel ready') this.sockidx[this.sockets[channelName].id] = channelName store.mutate(`chat.channels.${channelName}.status`, 'ready') this.channels[channelName].bind(this.sockets[channelName]) .then(() => { this.channels[channelName].join() }) this.sockets[channelName].listen(this.packetDecode) }) }) } isDuplicate = msg => { const hash = sodium.crypto_generichash(64, sodium.from_string(JSON.stringify(msg))) const hex = sodium.to_hex(hash) for (let i = 0; i < 100; i++) { if (this.lastmsgs[i] === undefined) break if (this.lastmsgs[i] === hex) { console.warn('suppressing duplicate message') return true } } console.log('hashed msg' + this.lastmsg) this.lastmsgs[this.lastmsg++] = hex if (this.lastmsg > 99) { this.lastmsg = 0 } return false } findUser = (channelName, key) => { console.log("searching for key '" + key + "'") return store.state.chat.channels[channelName].users.find(user => user.key === key) } packetDecode = pkt => { console.log('message received, decoding') const msg = new LIBRECAST.Message(pkt) const chatState = store.state.chat const decoder = new TextDecoder('utf-8') const newmsg = JSON.parse(decoder.decode(new Uint8Array(pkt.payload))) console.log('message received on socket ' + pkt.id) // de-duplicate msgs // we shouldn't be receiving duplicates, but as this is UDP, we might if (this.isDuplicate(newmsg)) { return } // messages must have user if (newmsg.user === undefined) { return } newmsg.received = Date.now() // identify channel for this socket const channelName = this.sockidx[pkt.id] console.log(`socket ${pkt.id} => channel '${channelName}'`) chatState.channels[channelName].msgs.push(newmsg) // append user to user list for channel if (newmsg.user.key !== undefined && !this.findUser(channelName, newmsg.user.key)) { chatState.channels[channelName].users.push(newmsg.user) } // update stats if (chatState.channels[channelName].bytin === undefined) { chatState.channels[channelName].bytin = 0 } chatState.channels[channelName].bytin += pkt.len store.mutate('chat', chatState) } send = (channelName, msgText) => { console.log(`${channelName}: '${msgText}'`) const user = { nick: store.state.nick, key: 1234 } const msg = { timestamp: Date.now(), username: store.state.nick, user, msg: msgText, id: this.lctx.token } const jstr = JSON.stringify(msg) this.channels[channelName].send(jstr) // update stats const chatState = store.state.chat if (chatState.channels[channelName].bytout === undefined) { chatState.channels[channelName].bytout = 0 } chatState.channels[channelName].bytout += jstr.length store.mutate('chat', chatState) } }