diff --git a/chat-signaling-server/static/index.css b/chat-signaling-server/static/index.css index e7da6c2..9f7d427 100644 --- a/chat-signaling-server/static/index.css +++ b/chat-signaling-server/static/index.css @@ -9,6 +9,7 @@ #message-list { width: 100%; flex-grow: 1; + max-height: 100%; overflow-y: scroll; } diff --git a/chat-signaling-server/static/style.css b/chat-signaling-server/static/style.css index f3b05a8..07d2c10 100644 --- a/chat-signaling-server/static/style.css +++ b/chat-signaling-server/static/style.css @@ -11,4 +11,6 @@ body { #content { width: 100%; flex-grow: 1; + max-height: 100%; + overflow: hidden; } \ No newline at end of file diff --git a/chat-signaling-server/templates/index.html b/chat-signaling-server/templates/index.html index 20ff16a..ef0b3b7 100644 --- a/chat-signaling-server/templates/index.html +++ b/chat-signaling-server/templates/index.html @@ -13,6 +13,7 @@ + {% endblock %} @@ -22,6 +23,7 @@ let message_list = document.getElementById("message-list") let peers = document.getElementById("peers") let inputbox = document.getElementById("message-input") + let sendfile = document.getElementById("sendfile") let search = new URLSearchParams(location.search); let sender = search.get("name") || ""; @@ -41,10 +43,62 @@ const MessageSessionAnswer = "SessionAnswer"; const MessageICECandidate = "IceCandidate"; - const display = (message) => { - let newNode = document.createElement("div") - newNode.innerHTML = `${new Date().toTimeString()}: ${message}`; - message_list.appendChild(newNode) + let updateSendfile = () => { + if (peers.value != "") { + sendfile.removeAttribute("disabled") + } else { + sendfile.setAttribute("disabled", "") + } + } + peers.addEventListener("change", updateSendfile) + sendfile.addEventListener("change", async (ev) => { + let file = sendfile.files[0] + sendfile.value = "" + + let peer = peerMap.get(peers.value) + if (!peer) { + return + } + display(`你给 ${peers.value} 传了一个文件: ${file.name}。传输中...`) + + let reader = new FileReader() + let dc = peer.createDataChannel(`file:${file.name}`) + reader.addEventListener("load", (ev) => { + dc.send(reader.result) + dc.close() + }) + dc.addEventListener("open", () => { + reader.readAsArrayBuffer(file) + }) + }) + + const createNode = (tag, ...children) => { + let node = document.createElement(tag) + children.forEach(child => { + if(typeof child === "string") { + let inner = document.createElement("span") + inner.innerHTML = child + node.appendChild(inner) + } else if (child instanceof HTMLElement) { + node.appendChild(child) + } else { + console.log("child is not a node: ", child, typeof child) + } + }) + return node + } + + const display = (...message) => { + let scrollToBottom = Math.abs(message_list.scrollHeight - message_list.scrollTop - message_list.clientHeight) < 1; + message_list.appendChild(createNode("div", + `${new Date().toTimeString()}: `, + ...message + )) + if(scrollToBottom) { + message_list.scrollTo({ + top: message_list.scrollHeight + }) + } } inputbox.addEventListener("keyup", (e) => { @@ -59,30 +113,34 @@ return } - console.log(`You -> ${peers.value}: ${inputbox.value}`) - display(`You -> ${peers.value}: ${inputbox.value}`) + display(`你 -> ${peers.value}: ${inputbox.value}`) channel.send(inputbox.value) inputbox.value = "" }) const addPeer = (peerName) => { + display(`连接上了 ${peerName}`) + let newNode = document.createElement("option") newNode.id = peerName newNode.setAttribute("value", peerName) - newNode.innerText = peerName; newNode.innerHTML = peerName; peers.appendChild(newNode) + + updateSendfile() } const removePeer = (peerName) => { + display(`${peerName} 走了...`) let el = document.getElementById(peerName); if(el) el.remove() + + updateSendfile() } let timeout; let reconnect = () => { if(ws && (ws.readyState == WebSocket.CONNECTING || ws.readyState == WebSocket.OPEN)) { - console.log("ws ok", ws) return; } @@ -99,7 +157,7 @@ handle_ws_message(JSON.parse(data)) }) ws.addEventListener("open", () => { - display("server connected. waiting for a name to be assigned for you...") + display("服务器连上啦。你等等,给你起个名字...") ws.send(JSON.stringify({ message: { type: MessageBootstrap, @@ -108,7 +166,6 @@ sender, })) }) - console.log("connecting...") } let handle_ws_message = (wsMessage) => { @@ -154,17 +211,37 @@ console.log("gather", peer.iceGatheringState) }) peer.addEventListener("datachannel", ({channel}) => { - channelMap.set(peerName, channel); - channel.addEventListener("open", (ev) => { - display("connected in event") - addPeer(peerName) - }) - channel.addEventListener("message", (ev) => { - display(`${peerName} -> You: ${ev.data}`) - }) - channel.addEventListener("close", () => { - removePeer(peerName) - }) + if(channel.label === "chat") { + channelMap.set(peerName, channel); + channel.addEventListener("open", (ev) => { + addPeer(peerName) + }) + channel.addEventListener("message", (ev) => { + display(`${peerName} -> You: ${ev.data}`) + }) + channel.addEventListener("close", () => { + removePeer(peerName) + }) + } else if (channel.label.startsWith("file:")) { + let filename = channel.label.substr(5) + let buffers = []; + channel.addEventListener("open", ev => { + display(`${peerName} 给你发了一个文件: ${filename}。 接收中...`) + }) + channel.addEventListener("message", ev => { + buffers.push(ev.data) + }) + channel.addEventListener("close", () => { + var link = document.createElement('a'); + link.href = window.URL.createObjectURL(new Blob(buffers)); + link.download = filename; + link.innerHTML = filename + display( + "文件:", + link, + ) + }) + } }) peerMap.set(peerName, peer); @@ -175,11 +252,10 @@ if(wsMessage.message.type === MessageDiscoverResponse) { let channel = peer.createDataChannel("chat"); channel.addEventListener("open", (ev) => { - display("connected in event") addPeer(peerName) }) channel.addEventListener("message", (ev) => { - display(`${peerName} -> You: ${ev.data}`) + display(`${peerName} -> 你: ${ev.data}`) }) channel.addEventListener("close", () => { removePeer(peerName) @@ -225,10 +301,10 @@ room, sender: wsMessage.sender, })) - display(`You are ${sender}. Searching for peers...`) + display(`决定了,就叫 ${sender}. 我们等等小伙伴吧...`) break; case MessageDiscoverRequest: - display("connecting to peer " + wsMessage.sender) + display(`正在尝试连接 ${wsMessage.sender}`) ws.send(JSON.stringify({ message: { type: MessageDiscoverResponse, @@ -245,7 +321,6 @@ recreateAndSetupPeer(wsMessage.sender) break case MessageSessionAnswer: - display("receiving connection to peer: " + wsMessage.sender) console.log("set remote answer") peer.setRemoteDescription(JSON.parse(wsMessage.message.sdp)) peer.restartIce() @@ -261,7 +336,6 @@ } reconnect() - console.log("document loaded") })() {% endblock %} \ No newline at end of file