I am implementing web socket notifications into my Django project and am having trouble with passing the user the the amount of unread notifications that they currently have.
My solution to this problem was to simply send all objects in the notification model class to the user once they connected to the web socket as messages in the web socket itself, which initially worked, but breaks if there are more then one tab open as each new tab connects to the web socket again which in turn will send the web socket messages again to any other open tab logged in to that user. ending up with duplicates of the same notification.
What I need is a way display all notifications on each page when it is loaded. Preferably without sending it through the context of a view.
consumers.py:
@database_sync_to_async
def create_notification(notification):
"""
function to create a notification.
:param notification: notification in json format to create notification object
"""
user = User.objects.get(username=notification["target"])
NotificationsModel.objects.create(
target=user,
sender=notification["sender"],
alertType=notification["alertType"],
title=notification["title"],
message=notification["message"],
)
class NotificationConsumer(AsyncWebsocketConsumer):
async def websocket_connect(self, event: dict) -> None:
if self.scope["user"].is_anonymous:
await self.close()
else:
self.group_code = self.scope["url_route"]["kwargs"]["group_code"]
await self.channel_layer.group_add(self.group_code, self.channel_name)
await self.accept()
# Since removed the send notifications from here as they encountered the problem described above
async def websocket_receive(self, event: dict) -> None:
message = event["text"] # anything sent to websocket_receive has {"type": "websocket.receive", "text": "foo"}
type_of_handler = json.loads(message)
type_of_handler = type_of_handler["type"]
await self.channel_layer.group_send(self.group_code, {"type": type_of_handler, "message": message})
async def websocket_disconnect(self, event: dict) -> None:
await self.channel_layer.group_discard(self.group_code, self.channel_name)
await self.close()
# custom message handlers called based on "type" of message sent
async def send_notification(self, event: dict) -> None:
await self.send(json.dumps({"type": "websocket.send", "message": event}))
async def notify_and_create(self, event: dict) -> None:
message = json.loads(event["message"])
await create_notification(message["notification"])
notification = json.dumps(message["notification"])
await self.channel_layer.group_send(
str(message["notification"]["target_id"]), {"type": "notification", "message": notification}
)
async def notification(self, event: dict) -> None:
await self.send(text_data=json.dumps(event["message"]))
javascript:
try{
var groupCode = document.getElementById("user");
var user = groupCode.getAttribute('user')
}catch(err){
throw Error('notifications not active (do not worry about this error)')
}
var loc = window.location;
var wsStart = "ws://";
if (loc.protocol == "https:"){
wsStart = "wss://";
}
var webSocketEndpoint = wsStart + loc.host + '/ws/notifications/' + user + '/'; // ws : wss // Websocket URL, Same on as mentioned in the routing.py
var socket = new WebSocket(webSocketEndpoint) // Creating a new Web Socket Connection
console.log('CONNECTED TO: ', webSocketEndpoint)
var counter = 0;
// Socket On receive message Functionality
socket.onmessage = function(e){
document.getElementById("no-alerts").innerHTML = "";
console.log('message recieved')
const obj = JSON.parse(e.data);
const object = JSON.parse(obj);
console.log(object)
var toastElList = [].slice.call(document.querySelectorAll('.toast'))
var toastList = toastElList.map(function (toastEl) {
return new bootstrap.Toast(toastEl)
})
counter = counter + 1;
document.getElementById("badge-counter").innerHTML = counter;
if (counter < 4) {
// stuff to show notifications in html
}
}
// Socket Connect Functionality
socket.onopen = function(e){
document.getElementById("no-alerts").append("No New Alerts!");
console.log('open', e)
}
// Socket Error Functionality
socket.onerror = function(e){
console.log('error', e)
}
// Socket close Functionality
socket.onclose = function(e){
console.log('closed', e)
}
Any ideas to point me in the right direction?