librecast-live
Version:
Live Streaming Video Platform with IPv6 Multicast
126 lines (111 loc) • 3.94 kB
JavaScript
// 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)
}
}