Add basic chatroom
This commit is contained in:
parent
b01ee46748
commit
6d59ddaa1a
4 changed files with 106 additions and 4 deletions
|
@ -12,8 +12,9 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="center-video">
|
||||
<h1 class="text-center">Best livestream website ever</h1>
|
||||
<div class="first-ui-row">
|
||||
<div>
|
||||
<video id="livestream" class="video-js" controls preload="auto" data-setup="{}">
|
||||
<source src="/media/stream.mpd" type="application/dash+xml" />
|
||||
<p class="vjs-no-js">
|
||||
|
@ -23,7 +24,16 @@
|
|||
</p>
|
||||
</video>
|
||||
</div>
|
||||
<div class="chatbox">
|
||||
<div id="messages"></div>
|
||||
<div>
|
||||
<input id="message-input" type="text" placeholder="Enter a message" autocomplete="off">
|
||||
<button id="message-submit" type="submit">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<h2 class="text-center">Currently playing: <span id="currently_playing">Nothing</span></h2>
|
||||
<h2 class="text-center">Viewers: <span id="viewers">1</span></h2>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,26 @@
|
|||
.center-video {
|
||||
.first-ui-row {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
align-self: end;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#messages .message {
|
||||
padding: 5px;
|
||||
margin: 10px;
|
||||
align-self: end;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#messages .message .message-username {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#messages .message .message-content {
|
||||
text-align: end;
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
const WebsocketMessageTypeViewers = 0;
|
||||
const WebsocketMessageTypeCurrentlyPlaying = 1;
|
||||
const WebsocketMessageTypeChatMessage = 2;
|
||||
|
||||
const messages = document.getElementById("messages");
|
||||
const messageInput = document.getElementById("message-input");
|
||||
const messageSubmit = document.getElementById("message-submit");
|
||||
|
||||
let stream = videojs('livestream');
|
||||
|
||||
|
@ -12,6 +17,24 @@ if (location.protocol === 'https:') {
|
|||
|
||||
let websocket = new WebSocket(wsurl)
|
||||
|
||||
function sendInput() {
|
||||
let message = {
|
||||
type: WebsocketMessageTypeChatMessage,
|
||||
message: messageInput.value,
|
||||
};
|
||||
|
||||
messageInput.value = "";
|
||||
|
||||
websocket.send(JSON.stringify(message));
|
||||
}
|
||||
messageInput.addEventListener("keyup", function(e) {
|
||||
if (e.key === "Enter") {
|
||||
sendInput()
|
||||
}
|
||||
});
|
||||
|
||||
messageSubmit.addEventListener("click", (e) => sendInput())
|
||||
|
||||
websocket.onmessage = (event) => {
|
||||
let data = JSON.parse(event.data)
|
||||
|
||||
|
@ -28,6 +51,22 @@ websocket.onmessage = (event) => {
|
|||
console.log("trying again")
|
||||
})
|
||||
|
||||
break
|
||||
case WebsocketMessageTypeChatMessage:
|
||||
let message = document.createElement("div");
|
||||
message.className = "message";
|
||||
|
||||
let username = document.createElement("div");
|
||||
username.className = "message-username";
|
||||
username.innerText = data.message.username;
|
||||
message.appendChild(username);
|
||||
|
||||
let content = document.createElement("div");
|
||||
content.className = "message-content";
|
||||
content.innerText = data.message.content;
|
||||
message.appendChild(content);
|
||||
|
||||
messages.appendChild(message);
|
||||
break
|
||||
}
|
||||
};
|
||||
|
|
33
websocket.go
33
websocket.go
|
@ -13,11 +13,12 @@ type WebsocketMessageType = int
|
|||
const (
|
||||
WebsocketMessageTypeViewers WebsocketMessageType = iota
|
||||
WebsocketMessageTypeCurrentlyPlaying
|
||||
WebsocketMessageTypeChatMessage
|
||||
)
|
||||
|
||||
type WebsocketMessage struct {
|
||||
Type WebsocketMessageType `json:"type"`
|
||||
Message string `json:"message"`
|
||||
Message any `json:"message"`
|
||||
}
|
||||
|
||||
func (w WebsocketMessage) Encode() []byte {
|
||||
|
@ -29,6 +30,11 @@ func (w WebsocketMessage) Encode() []byte {
|
|||
return m
|
||||
}
|
||||
|
||||
type WebsocketSendMessage struct {
|
||||
Username string `json:"username"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
|
||||
func (state *State) setupWebsocket() {
|
||||
state.Websocket = melody.New()
|
||||
|
||||
|
@ -49,6 +55,31 @@ func (state *State) setupWebsocket() {
|
|||
}.Encode())
|
||||
})
|
||||
|
||||
state.Websocket.HandleMessage(func(s *melody.Session, b []byte) {
|
||||
var genericMessage WebsocketMessage
|
||||
if err := json.Unmarshal(b, &genericMessage); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
switch genericMessage.Type {
|
||||
case WebsocketMessageTypeChatMessage:
|
||||
content, valid := genericMessage.Message.(string)
|
||||
if !valid {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: turn IP into hash hex and get color from name
|
||||
state.Websocket.Broadcast(WebsocketMessage{
|
||||
Type: WebsocketMessageTypeChatMessage,
|
||||
Message: WebsocketSendMessage{
|
||||
Username: s.RemoteAddr().String(),
|
||||
Content: content,
|
||||
},
|
||||
}.Encode())
|
||||
}
|
||||
})
|
||||
|
||||
state.Websocket.HandleDisconnect(func(s *melody.Session) {
|
||||
viewers, err := state.ViewersAmount()
|
||||
if err != nil {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue