Added notification sound.

This commit is contained in:
retoor 2025-01-28 17:24:10 +01:00
parent 4f1a48c197
commit 5aee606d5d
8 changed files with 161 additions and 144 deletions

View File

@ -51,12 +51,12 @@ class Messages {
class Room { class Room {
name = null name = null
messages = [] messages = []
constructor(name){ constructor(name) {
this.name = name this.name = name
} }
setMessages(list){ setMessages(list) {
} }
@ -65,9 +65,9 @@ class Room {
class InlineAppElement extends HTMLElement { class InlineAppElement extends HTMLElement {
constructor(){ constructor() {
// this. // this.
} }
} }
@ -78,38 +78,38 @@ class Page {
} }
class RESTClient { class RESTClient {
debug = false debug = false
async get(url, params){ async get(url, params) {
params = params ? params : {} params = params ? params : {}
const encodedParams = new URLSearchParams(params); const encodedParams = new URLSearchParams(params);
if(encodedParams) if (encodedParams)
url += '?' + encodedParams url += '?' + encodedParams
const response = await fetch(url,{ const response = await fetch(url, {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}); });
const result = await response.json() const result = await response.json()
if(this.debug){ if (this.debug) {
console.debug({url:url,params:params,result:result}) console.debug({ url: url, params: params, result: result })
} }
return result return result
} }
async post(url, data) { async post(url, data) {
const response = await fetch(url,{ const response = await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify(data) body: JSON.stringify(data)
}); });
const result = await response.json() const result = await response.json()
if(this.debug){ if (this.debug) {
console.debug({url:url,params:params,result:result}) console.debug({ url: url, params: params, result: result })
} }
return result return result
} }
} }
@ -117,17 +117,17 @@ const rest = new RESTClient()
class EventHandler { class EventHandler {
constructor(){ constructor() {
this.subscribers = {} this.subscribers = {}
} }
addEventListener(type,handler){ addEventListener(type, handler) {
if(!this.subscribers[type]) if (!this.subscribers[type])
this.subscribers[type] = [] this.subscribers[type] = []
this.subscribers[type].push(handler) this.subscribers[type].push(handler)
} }
emit(type,...data){ emit(type, ...data) {
if(this.subscribers[type]) if (this.subscribers[type])
this.subscribers[type].forEach(handler=>handler(...data)) this.subscribers[type].forEach(handler => handler(...data))
} }
} }
@ -136,182 +136,182 @@ class Chat extends EventHandler {
constructor() { constructor() {
super() super()
this._url = window.location.hostname == 'localhost' ? 'ws://localhost/chat.ws' : 'wss://' + window.location.hostname +'/chat.ws' this._url = window.location.hostname == 'localhost' ? 'ws://localhost/chat.ws' : 'wss://' + window.location.hostname + '/chat.ws'
this._socket = null this._socket = null
this._wait_connect = null this._wait_connect = null
this._promises = {} this._promises = {}
} }
connect(){ connect() {
if(this._wait_connect) if (this._wait_connect)
return this._wait_connect return this._wait_connect
const me = this const me = this
return new Promise(async (resolve,reject)=>{ return new Promise(async (resolve, reject) => {
me._wait_connect = resolve me._wait_connect = resolve
me._socket = new WebSocket(me._url) me._socket = new WebSocket(me._url)
console.debug("Connecting..") console.debug("Connecting..")
me._socket.onconnect = ()=>{ me._socket.onconnect = () => {
me._connected() me._connected()
me._wait_socket(me) me._wait_socket(me)
} }
}) })
} }
generateUniqueId() { generateUniqueId() {
return 'id-' + Math.random().toString(36).substr(2, 9); // Example: id-k5f9zq7 return 'id-' + Math.random().toString(36).substr(2, 9); // Example: id-k5f9zq7
} }
call(method,...args){ call(method, ...args) {
const me = this const me = this
return new Promise(async (resolve,reject)=>{ return new Promise(async (resolve, reject) => {
try{ try {
const command = {method:method,args:args,message_id:me.generateUniqueId()} const command = { method: method, args: args, message_id: me.generateUniqueId() }
me._promises[command.message_id] = resolve me._promises[command.message_id] = resolve
await me._socket.send(JSON.stringify(command)) await me._socket.send(JSON.stringify(command))
}catch(e){ } catch (e) {
reject(e) reject(e)
} }
}) })
} }
_connected() { _connected() {
const me = this const me = this
this._socket.onmessage = (event) => { this._socket.onmessage = (event) => {
const message = JSON.parse(event.data) 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) me._promises[message.message_id](message)
delete me._promises[message.message_id] delete me._promises[message.message_id]
}else{ } else {
me.emit("message",me, message) me.emit("message", me, message)
} }
//const room = this.rooms.find(room=>room.name == message.room) //const room = this.rooms.find(room=>room.name == message.room)
//if(!room){ //if(!room){
// this.rooms.push(new Room(message.room)) // this.rooms.push(new Room(message.room))
} }
this._socket.onclose = (event) => { this._socket.onclose = (event) => {
me._wait_socket = null me._wait_socket = null
me._socket = null me._socket = null
me.emit('close',me) me.emit('close', me)
} }
} }
async privmsg(room, text) { async privmsg(room, text) {
await rest.post("/api/privmsg",{ await rest.post("/api/privmsg", {
room:room, room: room,
text:text text: text
}) })
} }
} }
class Socket extends EventHandler { class Socket extends EventHandler {
ws = null ws = null
isConnected = null isConnected = null
isConnecting = null isConnecting = null
url = null url = null
connectPromises = [] connectPromises = []
constructor() { constructor() {
super() super()
this.url = window.location.hostname == 'localhost' ? 'ws://localhost:8081/rpc.ws' : 'wss://' + window.location.hostname +'/rpc.ws' this.url = window.location.hostname == 'localhost' ? 'ws://localhost:8081/rpc.ws' : 'wss://' + window.location.hostname + '/rpc.ws'
this.ensureConnection() this.ensureConnection()
} }
_camelToSnake(str) { _camelToSnake(str) {
return str return str
.replace(/([a-z])([A-Z])/g, '$1_$2') .replace(/([a-z])([A-Z])/g, '$1_$2')
.toLowerCase(); .toLowerCase();
} }
get client() { get client() {
const me = this const me = this
const proxy = new Proxy( const proxy = new Proxy(
{}, {},
{ {
get(target, prop) { get(target, prop) {
return (...args) => { return (...args) => {
let functionName = me._camelToSnake(prop) let functionName = me._camelToSnake(prop)
return me.call(functionName, ...args); return me.call(functionName, ...args);
}; };
}, },
} }
); );
return proxy return proxy
} }
ensureConnection(){ ensureConnection() {
return this.connect() return this.connect()
} }
generateUniqueId() { generateUniqueId() {
return 'id-' + Math.random().toString(36).substr(2, 9); return 'id-' + Math.random().toString(36).substr(2, 9);
} }
connect(){ connect() {
const me = this const me = this
if(!this.isConnected && !this.isConnecting){ if (!this.isConnected && !this.isConnecting) {
this.isConnecting = true this.isConnecting = true
}else if (this.isConnecting){ } else if (this.isConnecting) {
return new Promise((resolve,reject)=>{ return new Promise((resolve, reject) => {
me.connectPromises.push(resolve) me.connectPromises.push(resolve)
}) })
}else if(this.isConnected){ } else if (this.isConnected) {
return new Promise((resolve,reject)=>{ return new Promise((resolve, reject) => {
resolve(me) resolve(me)
}) })
} }
return new Promise((resolve,reject)=>{ return new Promise((resolve, reject) => {
me.connectPromises.push(resolve) me.connectPromises.push(resolve)
const ws = new WebSocket(this.url) const ws = new WebSocket(this.url)
ws.onopen = (event) => { ws.onopen = (event) => {
me.ws = ws me.ws = ws
me.isConnected = true me.isConnected = true
me.isConnecting = false me.isConnecting = false
ws.onmessage = (event) => { ws.onmessage = (event) => {
me.onData(JSON.parse(event.data)) me.onData(JSON.parse(event.data))
} }
ws.onclose = (event) =>{ ws.onclose = (event) => {
me.onClose() me.onClose()
} }
me.connectPromises.forEach(resolve=>{ me.connectPromises.forEach(resolve => {
resolve(me) resolve(me)
}) })
} }
}) })
} }
onData(data){ onData(data) {
if(data.callId){ if (data.callId) {
this.emit(data.callId, data.data) this.emit(data.callId, data.data)
} }
if(data.channel_uid){ if (data.channel_uid) {
this.emit(data.channel_uid,data.data) this.emit(data.channel_uid, data.data)
this.emit("channel-message",data) this.emit("channel-message", data)
} }
} }
async sendJson(data){ async sendJson(data) {
return await this.connect().then((api)=>{ return await this.connect().then((api) => {
api.ws.send(JSON.stringify(data)) api.ws.send(JSON.stringify(data))
}) })
} }
async call(method,...args){ async call(method, ...args) {
const call= { const call = {
callId: this.generateUniqueId(), callId: this.generateUniqueId(),
method: method, method: method,
args: args 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.") console.info("Connection lost. Reconnecting.")
this.isConnected = false this.isConnected = false
this.isConnecting = false this.isConnecting = false
this.ensureConnection().then(()=>{ this.ensureConnection().then(() => {
console.info("Reconnected.") console.info("Reconnected.")
}) })
} }
@ -320,38 +320,53 @@ class Socket extends EventHandler {
class App extends EventHandler { class App extends EventHandler {
rooms = [] rooms = []
rest = rest rest = rest
ws = null ws = null
rpc = 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() { constructor() {
super() super()
this.rooms.push(new Room("General")) this.rooms.push(new Room("General"))
this.ws = new Socket() this.ws = new Socket()
this.rpc = this.ws.client this.rpc = this.ws.client
const me = this const me = this
this.ws.addEventListener("channel-message", (data) => { this.ws.addEventListener("channel-message", (data) => {
me.emit(data.channel_uid,data) me.emit(data.channel_uid, data)
}) })
} }
async benchMark(times,message) { async benchMark(times, message) {
if(!times) if (!times)
times = 100 times = 100
if(!message) if (!message)
message = "Benchmark Message" message = "Benchmark Message"
let promises = [] let promises = []
const me = this const me = this
for(let i = 0; i < times; i++){ for (let i = 0; i < times; i++) {
promises.push(this.rpc.getChannels().then(channels=>{ promises.push(this.rpc.getChannels().then(channels => {
channels.forEach(channel=>{ channels.forEach(channel => {
me.rpc.sendMessage(channel.uid,`${message} ${i}`).then(data=>{ me.rpc.sendMessage(channel.uid, `${message} ${i}`).then(data => {
}) })
}) })
})) }))
} }
//return await Promise.all(promises) //return await Promise.all(promises)
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -51,6 +51,7 @@ class ChatWindowElement extends HTMLElement {
}) })
const me = this const me = this
channelElement.addEventListener("message",(message)=>{ channelElement.addEventListener("message",(message)=>{
app.playSound(0)
message.detail.element.scrollIntoView() message.detail.element.scrollIntoView()
}) })

View File

@ -66,6 +66,7 @@ class MessageListElement extends HTMLElement {
this.messageEventSchedule.delay(() => { this.messageEventSchedule.delay(() => {
me.dispatchEvent(new CustomEvent("message", {detail:obj,bubbles:true})) me.dispatchEvent(new CustomEvent("message", {detail:obj,bubbles:true}))
}) })