Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.DS_Store
3 changes: 0 additions & 3 deletions README.md

This file was deleted.

182 changes: 182 additions & 0 deletions sprint3 prep tasks/chat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
const chatFeedDiv = document.getElementById("chat-feed");
const fullMsgInChat = document.querySelector(".div-for-each-msg");
const msgInChat = document.querySelector(".msg-text-in-chat-view");
const usernameInChat = document.querySelector(".username-in-chat-view");

const refreshBtn = document.getElementById("refresh-btn");
const sendBtn = document.getElementById("send-msg-btn");
const pollBtn = document.getElementById("poll-btn");

const addMsgUsernameInput = document.getElementById("add-msg-username");
const addMsgTextInput = document.getElementById("add-msg-text");
const confirmToUser = document.getElementById("confirm-to-user");

// const url = "http://localhost:3000";
const url = "https://katchatapp.hosting.codeyourfuture.io";

// generatequote and show to user
const seeAllMessages = async () => {
// const selectedQuote = pickFromArray(quotes);
const response = await fetch(url);
const allMessages = await response.json();

//this fixes the messages not showing on live sitwe
state.messages = allMessages;
// quote.innerHTML = selectedQuote.quote;
// author.innerHTML = selectedQuote.author;
// change greetingi am keeping everythign as is and jusy want to
// document.getElementById("greeting").innerHTML = "Your quote is:";
// document.getElementById("greeting").style = "size: 1rem";
chatFeedDiv.innerHTML = "";
allMessages.forEach((msg) => {
chatFeedDiv.innerHTML += `
<div class="div-for-each-msg">
<p class="msg-in-chat-view">${msg.msgText}</p>
<p class="username-in-chat-view">${msg.username}</p>
</div>`;
});
};

//show to user on click of new quote
refreshBtn.addEventListener("click", seeAllMessages);

const sendMsg = async () => {
//removing whitespace or special characters
const addMsgText = addMsgTextInput.value
.trim()
.replace(/[^a-zA-Z0-9,.;:?! ]/g, "");
const addMsgUsername = addMsgUsernameInput.value
.trim()
.replace(/[^a-zA-Z0-9,.;:?! ]/g, "")
.toUpperCase();

//check if empty or too long
if (!addMsgText || !addMsgUsername) {
confirmToUser.innerHTML = "Please add message text and your username.";
return;
}

if (addMsgText.length > 400 || addMsgUsername.length > 40) {
confirmToUser.innerHTML =
"Message must be up to 400 chars and username must be less than 40 chars.";
return;
}

// so macthes backend (typeof body != "object" || !("quote" in body) || !("author" in body))
const addingMsg = {
msgText: addMsgText,
username: addMsgUsername,
};

const responseFromAdd = await fetch(url, {
method: "POST",
headers: {
//so backedn can parde body as json
"Content-Type": "application/json",
},
//turn obj into str typeof body != "object"
body: JSON.stringify(addingMsg),
});

// quotes.push(newQuoteAuthor, newQuoteText); - rhtis alsready in the backed so no need
// tell user
if (responseFromAdd.ok === true) {
confirmToUser.innerHTML = "Your message has been sent.";
//clear input
addMsgTextInput.value = "";
addMsgUsernameInput.value = "";
} else {
//take error message frrom response grab from heree
// console.error(`Failed to extract quote and author from post body: ${bodyString}`);
// res.status(400).send("Expected body to be a JSON object containing keys quote and author.");
// return;
const errorToShow = await responseFromAdd.text();
confirmToUser.innerHTML = `${errorToShow} Please try again.`;
}
};

sendBtn.addEventListener("click", sendMsg);

// auto refresh
// setInterval(seeAllMessages, 2000);

//polling coursework
// const keepFetchingMessages = async () => {
// const lastMessageTime = state.messages.length > 0 ? state.messages[state.messages.length - 1].timestamp : null;
// const queryString = lastMessageTime ? `?since=${lastMessageTime}` : "";
// const url = `${server}/messages${queryString}`;
// const rawResponse = await fetch(url);
// const response = await rawResponse.json();
// state.messages.push(...response);
// render();
// setTimeout(keepFetchingMessages, 100);
// }

let messages = [];
const state = { messages: [] };

//render defining from coursework example build from
const render = () => {
chatFeedDiv.innerHTML = "";
state.messages.forEach((msg) => {
chatFeedDiv.innerHTML += `
<div class="div-for-each-msg">
<p class="msg-in-chat-view">${msg.msgText}</p>
<p class="username-in-chat-view">${msg.username}</p>
</div>`;
});
};

//polling coursework
const keepFetchingMessages = async () => {
const lastMessageTime =
state.messages.length > 0
? state.messages[state.messages.length - 1].timestamp
: null;
const queryString = lastMessageTime ? `?since=${lastMessageTime}` : "";
const urlQueryMod = `${url}/messages${queryString}`;
const rawResponse = await fetch(urlQueryMod);
const response = await rawResponse.json();
state.messages.push(...response);
render();
setTimeout(keepFetchingMessages, 100);
};

pollBtn.addEventListener("click", keepFetchingMessages);

//test long poll
const longPollBtn = document.getElementById("long-poll-btn");

const testLongPoll = async () => {
const lastMessageTime =
state.messages.length > 0
? state.messages[state.messages.length - 1].timestamp
: null;
const queryString = lastMessageTime ? `?since=${lastMessageTime}` : "";
const urlQueryMod = `${url}/long-poll${queryString}`;
const rawResponse = await fetch(urlQueryMod);
const response = await rawResponse.json();
state.messages.push(...response);
render();
testLongPoll();
};
longPollBtn.addEventListener("click", testLongPoll);

//addiitonal privacy feature hide messages
const hideMessages = document.getElementById("hide-btn");

hideMessages.addEventListener("click", () => {
if (chatFeedDiv.style.display === "none") {
chatFeedDiv.style.display = "block";
hideMessages.textContent = "Hide chat";
} else {
chatFeedDiv.style.display = "none";
hideMessages.textContent = "Show chat";
}
});

// seeAllMessages();
// but with long poll
seeAllMessages().then(() => {
testLongPoll();
});
53 changes: 53 additions & 0 deletions sprint3 prep tasks/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tremendous Chat</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container to-hide">
<h1 id="greeting">Chat feed</h1>
<div id="chat-feed">
<div class="div-for-each-msg">
<p class="msg-text-in-chat-view"></p>
<p class="username-in-chat-view"></p>
</div>
</div>
<button type="button" class="secondary-btn" id="refresh-btn">
Get latest messages
</button>
<button type="button" class="secondary-btn" id="hide-btn">Hide messages</btn>
<button style="opacity: 0" type="button" class="secondary-btn" id="test-ws">Test websocket</btn>
</div>

<div class="container add-message">
<h2>Send a message</h2>
<input
class="input"
type="text"
id="add-msg-text"
placeholder="Add your message"
required
/>
<input
class="input"
type="text"
id="add-msg-username"
placeholder="Add the username"
required
/>
<button type="button" id="send-msg-btn">Send</button>
<p id="confirm-to-user"></p>
</div>

<button type="button" class="secondary-btn" id="poll-btn">Poll btn</button>
<button type="button" class="secondary-btn" id="long-poll-btn">
Long poll btn
</button>

<!-- <script src="chat.js"></script> -->
<script src="websocket.js"></script>
</body>
</html>
154 changes: 154 additions & 0 deletions sprint3 prep tasks/serverWEBSCOKETNOTES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import express from "express";
import cors from "cors";
import { on } from "events";
import http from "http";
import { server as WebSocketServer } from "websocket";

const app = express();
const port = process.env.PORT || 3000;

app.use(cors());

const server = http.createServer(app);
const webSocketServer = new WebSocketServer({ httpServer: server });

const messages = [
{
id: 1,
username: "annonymous",
msgText: "First chat message",
timestamp: Date.now(),
},
];

const getRecentMessages = (since) => {
return messages.filter((msg) => msg.timestamp > since);
};

app.get("/", (req, res) => {
res.json(messages);
});

//get recent messages polling
app.get("/messages", (req, res) => {
//This is the problem:
// sincetimestapm Teach your backend how to answer “since when” queries.
const since = parseInt(req.query.since);
if (since) {
res.json(getRecentMessages(since));
return;
}
res.json(messages);
});

//messages with long polling
const callbacksForNewMessages = [];
app.get("/long-poll", (req, res) => {
const since = parseInt(req.query.since);
let messagesToSend = [];

if (since) {
messagesToSend = getRecentMessages(since);
}

if (messagesToSend.length === 0) {
callbacksForNewMessages.push((value) => res.send(value));
} else {
res.send(messagesToSend);
}
});

//add msg to chat
app.post("/", (req, res) => {
const bodyBytes = [];
req.on("data", (chunk) => bodyBytes.push(...chunk));
req.on("end", () => {
const bodyString = String.fromCharCode(...bodyBytes);
let body;
try {
body = JSON.parse(bodyString);
} catch (error) {
console.error(`Failed to parse body ${bodyString} as JSON: ${error}`);
res.status(400).send("Expected body to be JSON.");
return;
}
if (
typeof body != "object" ||
!("username" in body) ||
!("msgText" in body)
) {
console.error(
`Failed to extract username and message text from body: ${bodyString}`
);
res
.status(400)
.send(
"Expected body to be a JSON object containing keys username and message text."
);
return;
}

body.msgText = body.msgText.trim().replace(/[^a-zA-Z0-9,.;:?! ]/g, "");
body.username = body.username.trim().replace(/[^a-zA-Z0-9,.;:?! ]/g, "");

if (!body.msgText || !body.username) {
res.status(400).send("Please add a quote and an username.");
return;
}

if (body.msgText.length > 400 || body.username.length >= 40) {
res
.status(400)
.send(
"Message text must be up to 400 chars and username must be less than 40 chars."
);
return;
}

const newId = messages.length + 1;

const newMessage = {
id: newId,
msgText: body.msgText,
username: body.username,
timestamp: Date.now(),
};

messages.push(newMessage);

while (callbacksForNewMessages.length > 0) {
const callback = callbacksForNewMessages.pop();
callback([newMessage]);
}

res.send("ok");
});
});

app.listen(port, () => {
console.error(`Chat server listening on port ${port}`);
});

websocket.addEventListener("open", () => {
log("CONNECTED");
pingInterval = setInterval(() => {
log(`SENT: ping: ${counter}`);
websocket.send("ping");
}, 1000);
});

websocket.addEventListener("message", (e) => {
log(`RECEIVED: ${e.data}: ${counter}`);
counter++;
});

websocket.addEventListener("message", (e) => {
const message = JSON.parse(e.data);
log(`RECEIVED: ${message.iteration}: ${message.content}`);
counter++;
});

websocket.addEventListener("close", () => {
log("DISCONNECTED");
clearInterval(pingInterval);
});
Loading