diff --git a/src/snek/static/app.js b/src/snek/static/app.js index 810e6bc..1d56076 100644 --- a/src/snek/static/app.js +++ b/src/snek/static/app.js @@ -51,12 +51,12 @@ class Messages { class Room { - name = null + name = null messages = [] - constructor(name){ - this.name = name + constructor(name) { + this.name = name } - setMessages(list){ + setMessages(list) { } @@ -65,9 +65,9 @@ class Room { class InlineAppElement extends HTMLElement { - - constructor(){ - // this. + + constructor() { + // this. } } @@ -78,38 +78,38 @@ class Page { } class RESTClient { - debug = false - - async get(url, params){ - params = params ? params : {} + debug = false + + async get(url, params) { + params = params ? params : {} const encodedParams = new URLSearchParams(params); - if(encodedParams) + if (encodedParams) url += '?' + encodedParams - const response = await fetch(url,{ + const response = await fetch(url, { method: 'GET', headers: { - 'Content-Type': 'application/json' + 'Content-Type': 'application/json' } - }); - const result = await response.json() - if(this.debug){ - console.debug({url:url,params:params,result:result}) - } - return result + }); + const result = await response.json() + if (this.debug) { + console.debug({ url: url, params: params, result: result }) + } + return result } async post(url, data) { - const response = await fetch(url,{ - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + }); - const result = await response.json() - if(this.debug){ - console.debug({url:url,params:params,result:result}) - } + const result = await response.json() + if (this.debug) { + console.debug({ url: url, params: params, result: result }) + } return result } } @@ -117,17 +117,17 @@ const rest = new RESTClient() class EventHandler { - constructor(){ + constructor() { this.subscribers = {} } - addEventListener(type,handler){ - if(!this.subscribers[type]) + addEventListener(type, handler) { + if (!this.subscribers[type]) this.subscribers[type] = [] this.subscribers[type].push(handler) } - emit(type,...data){ - if(this.subscribers[type]) - this.subscribers[type].forEach(handler=>handler(...data)) + emit(type, ...data) { + if (this.subscribers[type]) + this.subscribers[type].forEach(handler => handler(...data)) } } @@ -136,182 +136,182 @@ class Chat extends EventHandler { constructor() { super() - this._url = window.location.hostname == 'localhost' ? 'ws://localhost/chat.ws' : 'wss://' + window.location.hostname +'/chat.ws' - this._socket = null - this._wait_connect = null + this._url = window.location.hostname == 'localhost' ? 'ws://localhost/chat.ws' : 'wss://' + window.location.hostname + '/chat.ws' + this._socket = null + this._wait_connect = null this._promises = {} } - connect(){ - if(this._wait_connect) + connect() { + if (this._wait_connect) return this._wait_connect - - const me = this - return new Promise(async (resolve,reject)=>{ - me._wait_connect = resolve - me._socket = new WebSocket(me._url) - console.debug("Connecting..") - - me._socket.onconnect = ()=>{ - me._connected() - me._wait_socket(me) - } - }) - + + const me = this + return new Promise(async (resolve, reject) => { + me._wait_connect = resolve + me._socket = new WebSocket(me._url) + console.debug("Connecting..") + + me._socket.onconnect = () => { + me._connected() + me._wait_socket(me) + } + }) + } generateUniqueId() { return 'id-' + Math.random().toString(36).substr(2, 9); // Example: id-k5f9zq7 } - call(method,...args){ - const me = this - return new Promise(async (resolve,reject)=>{ - try{ - const command = {method:method,args:args,message_id:me.generateUniqueId()} + call(method, ...args) { + const me = this + return new Promise(async (resolve, reject) => { + try { + const command = { method: method, args: args, message_id: me.generateUniqueId() } me._promises[command.message_id] = resolve - await me._socket.send(JSON.stringify(command)) - - }catch(e){ + await me._socket.send(JSON.stringify(command)) + + } catch (e) { reject(e) } }) } _connected() { - const me = this + const me = this this._socket.onmessage = (event) => { const message = JSON.parse(event.data) - if(message.message_id && me._promises[message.message_id]){ + if (message.message_id && me._promises[message.message_id]) { me._promises[message.message_id](message) delete me._promises[message.message_id] - }else{ - me.emit("message",me, message) + } else { + me.emit("message", me, message) } //const room = this.rooms.find(room=>room.name == message.room) //if(!room){ - // this.rooms.push(new Room(message.room)) + // this.rooms.push(new Room(message.room)) } this._socket.onclose = (event) => { - me._wait_socket = null - me._socket = null - me.emit('close',me) + me._wait_socket = null + me._socket = null + me.emit('close', me) } } async privmsg(room, text) { - await rest.post("/api/privmsg",{ - room:room, - text:text + await rest.post("/api/privmsg", { + room: room, + text: text }) } } class Socket extends EventHandler { - ws = null + ws = null isConnected = null isConnecting = null url = null connectPromises = [] constructor() { super() - this.url = window.location.hostname == 'localhost' ? 'ws://localhost:8081/rpc.ws' : 'wss://' + window.location.hostname +'/rpc.ws' - this.ensureConnection() + this.url = window.location.hostname == 'localhost' ? 'ws://localhost:8081/rpc.ws' : 'wss://' + window.location.hostname + '/rpc.ws' + this.ensureConnection() } _camelToSnake(str) { return str - .replace(/([a-z])([A-Z])/g, '$1_$2') - .toLowerCase(); + .replace(/([a-z])([A-Z])/g, '$1_$2') + .toLowerCase(); } get client() { const me = this const proxy = new Proxy( {}, { - get(target, prop) { - return (...args) => { - let functionName = me._camelToSnake(prop) - return me.call(functionName, ...args); - }; - }, + get(target, prop) { + return (...args) => { + let functionName = me._camelToSnake(prop) + return me.call(functionName, ...args); + }; + }, } - ); + ); return proxy } - ensureConnection(){ + ensureConnection() { return this.connect() } generateUniqueId() { - return 'id-' + Math.random().toString(36).substr(2, 9); + return 'id-' + Math.random().toString(36).substr(2, 9); } - connect(){ - const me = this - if(!this.isConnected && !this.isConnecting){ - this.isConnecting = true - }else if (this.isConnecting){ - return new Promise((resolve,reject)=>{ + connect() { + const me = this + if (!this.isConnected && !this.isConnecting) { + this.isConnecting = true + } else if (this.isConnecting) { + return new Promise((resolve, reject) => { me.connectPromises.push(resolve) - }) - }else if(this.isConnected){ - return new Promise((resolve,reject)=>{ + }) + } else if (this.isConnected) { + return new Promise((resolve, reject) => { resolve(me) }) } - return new Promise((resolve,reject)=>{ + return new Promise((resolve, reject) => { me.connectPromises.push(resolve) - + const ws = new WebSocket(this.url) ws.onopen = (event) => { - me.ws = ws - me.isConnected = true + me.ws = ws + me.isConnected = true me.isConnecting = false ws.onmessage = (event) => { me.onData(JSON.parse(event.data)) } - ws.onclose = (event) =>{ + ws.onclose = (event) => { me.onClose() - + } - me.connectPromises.forEach(resolve=>{ - resolve(me) + me.connectPromises.forEach(resolve => { + resolve(me) }) } }) } - onData(data){ - if(data.callId){ + onData(data) { + if (data.callId) { this.emit(data.callId, data.data) } - if(data.channel_uid){ - this.emit(data.channel_uid,data.data) - this.emit("channel-message",data) + if (data.channel_uid) { + this.emit(data.channel_uid, data.data) + this.emit("channel-message", data) } - + } - async sendJson(data){ - return await this.connect().then((api)=>{ + async sendJson(data) { + return await this.connect().then((api) => { api.ws.send(JSON.stringify(data)) }) } - async call(method,...args){ - const call= { + async call(method, ...args) { + const call = { callId: this.generateUniqueId(), method: method, args: args } - - const me = this - return new Promise(async(resolve,reject)=>{ - me.addEventListener(call.callId,(data)=>{ - resolve(data) - }) - await me.sendJson(call) - + const me = this + return new Promise(async (resolve, reject) => { + me.addEventListener(call.callId, (data) => { + resolve(data) }) + await me.sendJson(call) + + + }) } - onClose(){ + onClose() { console.info("Connection lost. Reconnecting.") - this.isConnected = false + this.isConnected = false this.isConnecting = false - this.ensureConnection().then(()=>{ + this.ensureConnection().then(() => { console.info("Reconnected.") }) } @@ -320,38 +320,53 @@ class Socket extends EventHandler { class App extends EventHandler { rooms = [] - rest = rest - ws = null - rpc = null + rest = rest + ws = null + rpc = null + sounds = ["/audio/soundfx.d_beep3.mp3"] + playSound(soundIndex) { + if (!soundIndex) + soundIndex = 0 + + const player = new Audio(this.sounds[soundIndex]); + + player.play() + .then(() => { + console.debug("Gave sound notification") + }) + .catch((error) => { + console.error("Notification failed:", error); + }); + } constructor() { super() this.rooms.push(new Room("General")) this.ws = new Socket() - this.rpc = this.ws.client - const me = this + this.rpc = this.ws.client + const me = this this.ws.addEventListener("channel-message", (data) => { - me.emit(data.channel_uid,data) - }) + me.emit(data.channel_uid, data) + }) } - async benchMark(times,message) { - if(!times) + async benchMark(times, message) { + if (!times) times = 100 - if(!message) + if (!message) message = "Benchmark Message" let promises = [] - const me = this - for(let i = 0; i < times; i++){ - promises.push(this.rpc.getChannels().then(channels=>{ - channels.forEach(channel=>{ - me.rpc.sendMessage(channel.uid,`${message} ${i}`).then(data=>{ - + const me = this + for (let i = 0; i < times; i++) { + promises.push(this.rpc.getChannels().then(channels => { + channels.forEach(channel => { + me.rpc.sendMessage(channel.uid, `${message} ${i}`).then(data => { + }) }) })) - + } //return await Promise.all(promises) - + } diff --git a/src/snek/static/audio/soundfx.d_alarm1.mp3 b/src/snek/static/audio/soundfx.d_alarm1.mp3 new file mode 100644 index 0000000..372e3b4 Binary files /dev/null and b/src/snek/static/audio/soundfx.d_alarm1.mp3 differ diff --git a/src/snek/static/audio/soundfx.d_alarm2.mp3 b/src/snek/static/audio/soundfx.d_alarm2.mp3 new file mode 100644 index 0000000..85bb50a Binary files /dev/null and b/src/snek/static/audio/soundfx.d_alarm2.mp3 differ diff --git a/src/snek/static/audio/soundfx.d_beep1.mp3 b/src/snek/static/audio/soundfx.d_beep1.mp3 new file mode 100644 index 0000000..0aae9fd Binary files /dev/null and b/src/snek/static/audio/soundfx.d_beep1.mp3 differ diff --git a/src/snek/static/audio/soundfx.d_beep2.mp3 b/src/snek/static/audio/soundfx.d_beep2.mp3 new file mode 100644 index 0000000..171f0e4 Binary files /dev/null and b/src/snek/static/audio/soundfx.d_beep2.mp3 differ diff --git a/src/snek/static/audio/soundfx.d_beep3.mp3 b/src/snek/static/audio/soundfx.d_beep3.mp3 new file mode 100644 index 0000000..883c5d3 Binary files /dev/null and b/src/snek/static/audio/soundfx.d_beep3.mp3 differ diff --git a/src/snek/static/chat-window.js b/src/snek/static/chat-window.js index 0727225..9e0e648 100644 --- a/src/snek/static/chat-window.js +++ b/src/snek/static/chat-window.js @@ -51,6 +51,7 @@ class ChatWindowElement extends HTMLElement { }) const me = this channelElement.addEventListener("message",(message)=>{ + app.playSound(0) message.detail.element.scrollIntoView() }) diff --git a/src/snek/static/message-list.js b/src/snek/static/message-list.js index 29e8a0b..a6fc835 100644 --- a/src/snek/static/message-list.js +++ b/src/snek/static/message-list.js @@ -66,6 +66,7 @@ class MessageListElement extends HTMLElement { this.messageEventSchedule.delay(() => { me.dispatchEvent(new CustomEvent("message", {detail:obj,bubbles:true})) + })