]> git.mar77i.info Git - chat/commitdiff
simplify ws connecting and reconnecting master
authormar77i <mar77i@protonmail.ch>
Tue, 19 Nov 2024 14:27:07 +0000 (15:27 +0100)
committermar77i <mar77i@protonmail.ch>
Tue, 19 Nov 2024 14:39:04 +0000 (15:39 +0100)
chat/static/chat/chat.js
todo.txt

index a1198225fcb542ca0651edf1e796e7f64ba6a11b..75ae76dc5e98bb753531d89a2fcf637a4e528248 100644 (file)
             {
                 "abort": function (msg) {
                     console.log(msg);
+                    messages_manager.stick_to_bottom();
                     new Message({"text": msg, "user": "xhr_abort"}, null);
+                    messages_manager.bottom_callback();
                 },
                 "error": function (msg) {
                     console.log(msg);
+                    messages_manager.stick_to_bottom();
                     new Message({"text": msg, "user": "xhr_error"}, null);
+                    messages_manager.bottom_callback();
                 },
                 "load": function () {
                     var response_data;
         messages_footer.children[0].disabled = true;
     }
 
+    function load_msgs_callback(msgs) {
+        messages_manager.load_msgs_callback(msgs);
+    }
+
     function set_channel(field_value) {
         clear_channel();
         if (this === window) {
                 + "?" + this.msg_dest_field
                 + "=" + field_value.toString()
             ),
-            function (msgs) {
-                messages_manager.load_msgs_callback(msgs);
-                messages_manager.scroll_to_bottom();
-            }
+            load_msgs_callback
         );
     }
 
         this.items_url = "/api/user/";
         this.items_classname = "users";
         this.items_per_id = {};
-        this.items_reload = function () {
+        this.items_reload = function (callback) {
             _.clear_children(_.dgEBCN0(this.items_classname).children[0]);
             _.clear_attributes(this.items_per_id);
             xhr(
                         }
                     );
                     update_channel_header.call(outer);
+                    if (callback) {
+                        callback();
+                    }
                 }
             );
         };
             _.foreach_arr(
                 this.items_per_id[this.msg_data.channel_id].users,
                 function (user_id) {
-                    var item = private_manager.items_per_id[user_id];
-                    var li = make_tag_with_data_id("li", item.id);
+                    var li = make_tag_with_data_id("li", user_id);
                     var a = make_callback_a(
                         function () {
-                            private_manager.set_channel(item.id);
+                            private_manager.set_channel(user_id);
                         }
                     );
-                    a.appendChild(private_manager.item_to_tn(item));
+                    a.appendChild(
+                        private_manager.item_to_tn(
+                            private_manager.items_per_id[user_id]
+                        )
+                    );
                     li.appendChild(a);
                     messages_header.children[1].appendChild(li);
                 }
         this.items_url = "/api/channel/";
         this.items_classname = "channels";
         this.items_per_id = {};
-        this.items_reload = function () {
+        this.items_reload = function (callback) {
             _.clear_children(_.dgEBCN0(this.items_classname).children[0]);
             _.clear_attributes(this.items_per_id);
             xhr(
                         items_reload_callback.bind(outer)
                     );
                     update_channel_header.call(outer);
+                    if (callback) {
+                        callback();
+                    }
                 }
             );
         };
             messages.insertBefore(p, messages.firstElementChild);
             p.appendChild(button);
         };
+        function no_bottom_callback() {
+            this.bottom_callback = no_bottom_callback;
+        }
+        this.bottom_callback = no_bottom_callback;
+        this.is_at_the_bottom = function () {
+            return messages.clientHeight + messages.scrollTop
+            === messages.scrollHeight;
+        };
         this.load_msgs_callback = function (msgs, next) {
+            var is_at_the_bottom = this.is_at_the_bottom();
             this.previous_button(msgs.previous);
+            no_bottom_callback();
             _.foreach_arr(msgs.result, function (msg) {
                 new Message(msg, next);
             });
+            if (is_at_the_bottom) {
+                this.scroll_to_bottom();
+            }
         };
-        function no_bottom_callback() {
-            messages_manager.bottom_callback = no_bottom_callback;
-        }
-        this.bottom_callback = no_bottom_callback;
         this.stick_to_bottom = function () {
-            if (
-                messages.clientHeight + messages.scrollTop
-                === messages.scrollHeight
-            ) {
-                messages_manager.bottom_callback = function () {
-                    messages_manager.scroll_to_bottom();
-                    no_bottom_callback();
-                };
+            if (this.is_at_the_bottom()) {
+                this.bottom_callback = messages_manager.scroll_to_bottom;
             } else {
                 no_bottom_callback();
             }
             messages.scrollTop = (
                 messages.scrollHeight - messages.clientHeight
             );
+            no_bottom_callback();
         };
     }
 
                 }
             },
             INSERT: function (data) {
-                messages_manager.stick_to_bottom();
                 xhr(
                     "get",
                     current_channel.msg_url + data.obj.id + "/",
                 if (!messages_manager.by_id(data.obj.id)) {
                     return;
                 }
-                messages_manager.stick_to_bottom();
                 xhr(
                     "get",
                     (
                 messages_manager.bottom_callback();
             },
             update_callback: function (data) {
-                console.log(messages_manager.by_id(data.id));
                 messages_manager.by_id(data.id).update(data);
                 messages_manager.bottom_callback();
             }
         };
-        var ws = new WebSocket(
-            ws_schemas[window.location.protocol]
-            + "//"
-            + window.location.host
-            + "/"
-        );
         function ws_receive(msg) {
             var data;
             try {
                 private_manager.items_reload();
             }
             if (current_channel && current_channel.match_channel(data)) {
+                messages_manager.stick_to_bottom();
                 ws_receive_msg[data.op](data);
             }
         }
-        ws.addEventListener("message", ws_receive);
-        ws.addEventListener("close", function (event) {
-            event = event || window.event;
-            new Message({"text": "Closed", "user": "ws_close"}, null);
-            // display reconnect button here
-        });
-        ws.addEventListener("error", function (event) {
-            event = event || window.event;
-            console.log(event);
-            new Message({"text": event, "user": "ws_error"}, null);
-            // display reconnect button here
-        });
+        function connect() {
+            var ws = new WebSocket(
+                ws_schemas[window.location.protocol]
+                + "//"
+                + window.location.host
+                + "/"
+            );
+            ws.addEventListener("message", ws_receive);
+            ws.addEventListener("close", function () {
+                messages_manager.stick_to_bottom();
+                new Message({"text": "Closed", "user": "ws_close"}, null);
+                messages_manager.bottom_callback();
+                toggle_reconnect_button();
+            });
+            ws.addEventListener("error", function (event) {
+                event = event || window.event;
+                console.log(event);
+                messages_manager.stick_to_bottom();
+                new Message({"text": event, "user": "ws_error"}, null);
+                messages_manager.bottom_callback();
+                toggle_reconnect_button();
+            });
+            return ws;
+        }
+        function try_reconnect() {
+            var messages_footer = _.dgEBCN0("messages_footer");
+            var ws;
+            if (messages_footer.children.length <= 2) {
+                return;
+            }
+            messages_footer.children[2].setAttribute("disabled", "");
+            ws = connect();
+            ws.addEventListener("open", function () {
+                var prev_channel;
+                var prev_id;
+                if (
+                    current_channel !== null
+                    && current_channel.hasOwnProperty("msg_data")
+                    && current_channel.hasOwnProperty("msg_dest_field")
+                ) {
+                    prev_channel = current_channel;
+                    prev_id = current_channel.msg_data[
+                        current_channel.msg_dest_field
+                    ];
+                } else {
+                    prev_channel = window;
+                    prev_id = null;
+                }
+                toggle_reconnect_button();
+                private_manager.items_reload(function () {
+                    channel_manager.items_reload(function () {
+                        set_channel.call(prev_channel, prev_id);
+                    });
+                });
+            });
+            function reenable_reconnect() {
+                if (messages_footer.children > 2) {
+                    messages_footer.children[2].removeAttribute("disabled");
+                }
+            }
+            ws.addEventListener("close", reenable_reconnect);
+            ws.addEventListener("error", reenable_reconnect);
+        }
+        function toggle_reconnect_button() {
+            var messages_footer = _.dgEBCN0("messages_footer");
+            if (messages_footer.children[0].style.display === "none") {
+                messages_footer.children[0].style.display = "";
+                messages_footer.children[1].style.display = "";
+                _.clear_after(messages_footer.children[1]);
+            } else {
+                messages_footer.children[0].style.display = "none";
+                messages_footer.children[1].style.display = "none";
+                messages_footer.appendChild(document.createElement("button"));
+                messages_footer.children[2].appendChild(_.dcTN("Reconnect"));
+                messages_footer.children[2].style.width = "100%";
+                messages_footer.children[2].addEventListener(
+                    "click",
+                    try_reconnect
+                );
+            }
+        }
+        connect();
     }
 
     function send_msg() {
index a82254176bdf666164ee534d7831c6ab42fba777..425e1741b5540c29bb0b9e91316f5cbb2bf1cafc 100644 (file)
--- a/todo.txt
+++ b/todo.txt
@@ -1,23 +1,25 @@
 [ ] display a reconnect button when ws is disconnected
-   - if reconnect is successful, reload all loaded messages, channel list and user list
+   - if reconnect is successful, reload channel list and user list and channel messages
 [ ] show message edit/delete menus
    - privileged users can edit / delete any message
 [ ] edit/delete existing messages
 [ ] new message(s) indicators in left panel
 
 [ ] update address bar per channel #channel:<id> / #user:<id> for now?
+   - update for requested hash
 [ ] channel management: channel admin
-[ ] write email to user
+[ ] write email to user with email
 
 [ ] ws client infrastructure:
    - notify-throttle
    - automatic reconnects?
-[ ] server-side throttling, that then needs to be accounted for on the client
+[ ] server-side throttling, and add a retry mechanism on the client
 
 [ ] tests for pg-trigger→notify websocket
    - somehow test each trigger statement individually, that is 4 statements * 5 models
 [ ] ws and chat tests?
+
 [ ] media uploads and view methods: download, image, video/audio player
 [ ] games: connect 4, battleship...
 
-[ ] moderation: report messages to MANAGERS, including private ones
+[ ] moderation: report messages to MANAGERS, including private messages