Announcements
W8 + W9: Chatbook!
***Catbook with Chat***
Michael Kuoch & Andrew Liu
Chatbook: weblab.is/example
The story so far...
Card
Comments
Block
SingleStory
Feed
NewStory
App
Navbar
Profile
Single
Comment
New
Comment
CatHappiness
NotFound
Next couple of days!
ChatList
SingleMessage
SingleUser
Chatbook
Chat
NewMessage
Chatbook Frontend Plan
Refer back to this for a big picture overview
Chatbook: The whole page
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Chatbook divides into ChatList and Chat
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
ChatList
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Chat (focus of W8)
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Props and State...
ChatData refers to {
messages: Array of MessageObjs
recipient: A UserObj
}
MessageObj refers to {
sender: A UserObj
content: A String
}
UserObj refers to {
_id: id (stored as string)
name: A String
}
Who we are chatting with
App
Chatbook Backend Plan
Refer back to this for a big picture overview
Endpoints
server
// Get all of the messages
router.get("/chat", (req, res) => {
});
// Send a message to everyone
router.post("/message", (req, res) => {
});
Teach me how to deal with these requests!!! I don't know what to do!
Endpoints
server
client 1
client 2
post("/api/message", {content: "uwu"})
get("/api/chat", {recipient_id: "25"})
I gotchu
Chatbook Design Recap
Recap (Frontend)
ChatData refers to {
messages: Array of MessageObjs
recipient: A UserObj
}
MessageObj refers to {
sender: A UserObj
content: A String
}
UserObj refers to {
_id: id (stored as string)
name: A String
}
Who we are chatting with
App
Recap (Backend)
server
// Get all of the messages
router.get("/chat", (req, res) => {
});
// Send a message to everyone
router.post("/message", (req, res) => {
});
Teach me how to deal with these requests!!! I don't know what to do!
Let’s make Chatbook!
TODO
exit out of vscode
rm -rf catbook-react
re-clone the repo
(link @ weblab.is/catbook)
19
Let's make Chatbook!!
git fetch
git reset --hard�git checkout w8-step1
npm install
npm start + npm run hotloader
20
Now, the Chat page is empty
git fetch; git reset --hard; git checkout w8-step1
Step 1: Display
git fetch; git reset --hard; git checkout w8-step1
Types & APIs: weblab.to/chatbook-docs
NewMessage
SingleMessage
Step 1 - Let’s Break it Down
App.js
ChatData refers to {
messages: Array of MessageObjs
recipient: A UserObj
}
MessageObj refers to {
sender: A UserObj
content: A String
}
UserObj refers to {
_id: id (stored as string)
name: A String
}
Who we are chatting
1.1
1.2
1.3
1.4
1.5
1.6
Step 1 - Where is everything?
App.js
1.1
1.2
1.3
1.4
1.5
1.6
Step 1.1 & Step 1.2 at bottom of NewMessage in NewPostInput.js
Step 1.3 in SingleMessage.js
Step 1.4 in Chat.js
Step 1.5 in Chatbook.js at bottom
Step 1.6 in Chatbook.js at top
Your Turn
git reset --hard�git checkout w8-step2
25
Step 2: Add the state activeChat to Chatbook
git reset --hard; git checkout w8-step2
2.1
File: Chatbook.js
Lines: 48, 67
Types & APIs: weblab.to/chatbook-docs
2.2
Step 2: Add the state activeChat to Chatbook
const [state, setState] = useState({
<initialState>
});
git reset --hard; git checkout w8-step2
Types & APIs: weblab.to/chatbook-docs
File: Chatbook.js
Lines: 48, 67
Let's get on the same page
git reset --hard�git checkout w8-step3
28
Step 3 - Implement the API endpoints
server
// Get all of the messages
router.get("/chat", (req, res) => {
});
// Send a message to everyone
router.post("/message", (req, res) => {
});
Teach me how to deal with these requests!!! I don't know what to do!
3.3
3.2
What does a message look like though
git reset --hard; git checkout w8-step3
3.1
Step 3: Add Backend for Messages
git reset --hard; git checkout w8-step3
Types & APIs: weblab.to/chatbook-docs
Step 3: Add Backend for Messages
git reset --hard; git checkout w8-step3
Types & APIs: weblab.to/chatbook-docs
Your Turn
git reset --hard�git checkout w8-step4
32
Step 4: Complete sendMessage
git reset --hard; git checkout w8-step4
Types & APIs: weblab.to/chatbook-docs
File: NewPostInput.js
Line: 95
server
client 1
*clicks submit*
(NewMessage)
post the message "Hey I am chatting"
4.1
Ok
Step 4: Complete sendMessage
post(“<route>”, {param: param_val, param: param_val ..})
git reset --hard; git checkout w8-step4
Types & APIs: weblab.to/chatbook-docs
File: NewPostInput.js
Line: 95
Let's get on the same page
git reset --hard�git checkout w8-step5
35
Step 5: Load Messages from Database
git reset --hard; git checkout w8-step5
Types & APIs: weblab.to/chatbook-docs
server
Hey get me all the chat messages to show
Ok
5.1, 5.2
client 1
*loads page*
See the final product
git reset --hard�git checkout w8-complete
37
W9: Sockets
Michael Kuoch & Andrew Liu
Games!!
Live Interaction!!
Chat!!
Announcements
Let’s see what Chatbook looks like so far
41
42
Chat solved
Storytime
85% True Story*
*Some details may be exaggerated for dramatic effect
During beta testing
CEO of Catbook
Unfortunately, our customers are mad that you have to refresh the page to see new feed and messages.
They want live interaction and CHAT. Please make something for them!
I gotchu, bro
During Lunch
CEO of Catbook
Bruh.
You still have to refresh the page to see new messages :(
Real Time Chatbook with Socket.io
Finally what you came for!
How we want it to work
Fluffy
Whiskers
Joe
POST /api/message “meow”
server
How we want it to work
Fluffy
Whiskers
Joe
POST hey Fluffy just said meow
server
Doesn’t work!
Fluffy
Whiskers
Joe
X
X
server
i can't initiate conversations :(
Limitation of HTTP
Client sends request to Server
Server responds to Client
Server can’t send data to the client unless a request is made
GET /api/chat
response
How do we fix this?
Polling: Ask the server every (x) seconds
Joe
(GET) any new messages?
nope nothing yet
(GET) any new messages?
nope nothing yet
(GET) any new messages?
Yes! Fluffy said meow
Just teach the server to initiate conversations
We can teach the server to initiate!
A real-time library that uses WebSocket
Lunch Break
Until
1:00
56
Lunch Logistics
Catbook CEO
Open portal.weblab.is
and log in, showing us that you are registered for the class
Eat outside the classroom,
Return at 1:00 :)
1 burrito / bowl only for now
Lunch Logistics
Open portal.weblab.is
and log in, showing us that you are registered for the class
Eat outside the classroom,
Return at 1:00 :)
1 piece only for now
Socket IO
Joe
Hey let’s socket (handshake)
ok bet (upgrade)
Fluffy said meow
(WOW I can initiate conversations now!)
...later
Socket IO
Server
Client
Socket IO
Server
Client
Client
Client
Socket IO
Server
Client
Client
Client
Broadcast using sockets
Fluffy
Whiskers
Joe
POST /api/message “meow”
Broadcast using sockets
Fluffy
Whiskers
Joe
new msg “meow”
(ws)
new msg “meow”
(ws)
new msg “meow”
(ws)
Basic Usage
Broadcast a message from server to everyone connected
socketManager.getIo().emit("event_name", data)
The Title The data
(object, list, string, etc)
We coded this for you!
Basic Usage
Broadcast a message from server to everyone connected
socketManager.getIo().emit("event_name", data)
Listen for messages on client
socket.on("event_name", someFunction)
The Title The data
(object, list, string, etc)
The Title what to do when you get a socket emit of that title
will look like (data) => { do something with data }
We coded this for you!
Professor
Students
On "new_pset",
start working
Emit ("new_pset", pset_obj)
Professor
Students
emit(‘new_pset’, {
due: ‘1/20/23’,
questions: [
‘what is 9 + 10’,
‘does P = NP?’
]
});
on(‘new_pset’, (pset) => {
while (pset.due !== tomorrow) {
procrastinate();
}
solve(pset.questions);
});
Whiskers
Joe
socketManager.getIo().emit(‘message’, messageObj)
socket.on(‘message’, cb)
socket.on(‘message’, cb)
Let’s Socket-ify Chatbook!
Let’s recap Chatbook design
Chatbook Front End Roadmap
ChatList
SingleMessage
SingleUser
Chatbook
Chat
NewMessage
Chatbook Frontend Plan
Refer back to this for a big picture overview
Chatbook: The whole page
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Chatbook divides into ChatList and Chat
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Chat
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
ChatList
Chatbook
ChatList
SingleMessage
SingleUser
Chat
NewMessage
Props and State...
ChatData refers to {
messages: Array of MessageObjs
recipient: A UserObj
}
MessageObj refers to {
sender: A UserObj
content: A String
}
UserObj refers to {
_id: id (stored as string)
name: A String
}
Who we are chatting with
App
Chatbook Backend
Refer back to this for a big picture overview
Endpoints
server
// Get all of the messages
router.get("/chat", (req, res) => {
});
// Send a message to everyone
router.post("/message", (req, res) => {
});
Endpoints
server
client 1
client 2
client 3
get("/api/chat")
post("/api/message", {content: "uwu"})
get("/api/chat", {recipient_id: "25"})
I gotchu
(**We’ll add this!**)
Chatbook Design Recap
Summary (Frontend)
ChatData refers to {
messages: Array of MessageObjs
recipient: A UserObj
}
MessageObj refers to {
sender: A UserObj
content: A String
}
UserObj refers to {
_id: id (stored as string)
name: A String
}
Who we are chatting with
App
Summary (Backend)
server
// Get all of the messages
router.get("/chat", (req, res) => {
});
// Send a message to everyone
router.post("/message", (req, res) => {
});
Now We’re Ready to Socket-ify Chatbook!
Go to catbook-react!
git fetch
git reset --hard
git checkout w9-starter
git pull
npm install
Start the hotloader and server
86
Chatbook! (part 2)
Information: weblab.is/socket-guide
Side Slides: weblab.is/socket-docs
87
Chatbook! (part 2)
Main Slides: weblab.is/w9-slides
Side Slides: weblab.is/w9-context
88
Basic Usage
Broadcast a message from server to everyone connected
socketManager.getIo().emit("event_name", data)
The Title The data
(object, list, string, etc)
We coded this for you!
Basic Usage
Broadcast a message from server to everyone connected
socketManager.getIo().emit("event_name", data)
Listen for messages on client
socket.on("event_name", someFunction)
The Title The data
(object, list, string, etc)
The Title what to do when you get a socket emit of that title
will look like (data) => { do something with data }
We coded this for you!
Step 0: Add Sockets to See Messages Instantly!
git reset --hard; git checkout w9-starter
Step 0: Add Sockets to See Messages Instantly!
Backend:
git reset --hard; git checkout w9-starter
...
Files: api.js, line 98
server
*shouts to everyone*
Step 0: Add Sockets to See Messages Instantly!
Backend:
Frontend:
git reset --hard; git checkout w9-starter
...
Files: api.js, line 98; Chatbook.js, line 67
server
*shouts to everyone*
client 1
*when i hears server's shout, do something with the data*
this callback function is defined for you!
Step 0: Add Sockets to See Messages Instantly!
Backend:
Frontend:
git reset --hard; git checkout w9-starter
...
Files: api.js, line 98; Chatbook.js, line 67
server
*shouts to everyone*
client 1
*when i hears server's shout, do something with the data*
these strings must match (it’s the name of the communication)
this callback function is defined for you!
Broadcast using sockets
Fluffy
Whiskers
Joe
POST /api/message “meow”
Broadcast using sockets
Fluffy
Whiskers
Joe
new msg “meow”
(ws)
new msg “meow”
(ws)
new msg “meow”
(ws)
See demo
git reset --hard�git checkout w9-step1
97
But what about sending DMs? 🤔
98
The problem of identity
99
Fluffy
Joe
POST /api/meow “FOOD”
To Whiskers
Whiskers
The problem of identity
100
Fluffy
Joe
Whiskers
new meow “FOOD”
(ws)
The problem of identity
101
Fluffy
Joe
new meow “FOOD”
(ws)
io.emit alone is public to all sockets, so we need more!
Whiskers
POST /api/meow “FOOD”
To Whiskers
io.emit behind the scenes
102
Fluffy
Joe
Whiskers
POST /api/meow “FOOD”
To Whiskers
socketManager.getIo().emit(“meow”, “FOOD”)
(ws)
io.emit behind the scenes
103
Fluffy
Joe
Whiskers
Joe’s socket
Whiskers’
socket
POST /api/meow “FOOD”
To Whiskers
io.emit behind the scenes
104
Fluffy
Joe
Whiskers
socket
socket
IO Object
socketManager.getIo()
POST /api/meow “FOOD”
To Whiskers
io.emit behind the scenes
105
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
socket1.emit(“meow”, “FOOD”)
socket2.emit(“meow”, “FOOD”)
POST /api/meow “FOOD”
To Whiskers
Problem: server doesn’t know Whiskers’ socket
106
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
Socket initialized by the client
107
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
(on initial connection)
https handshake:
we agree to follow some protocols
related to this new connection
Socket initialized by the client
108
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
(on initial connection)
https handshake:
we agree to follow some protocols
related to this new connection
does not include information about the user!
server adds socket to io object blindly
But Whiskers knows its socket!
109
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
(on initial connection)
POST /api/initsocket hi it’s whiskers, my socket is socket1
Tell server which socket the user is
110
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
POST /api/initsocket hi it’s whiskers, my socket is socket1
Server can check with req.user!
(on initial connection)
Tell server which socket the user is
111
Fluffy
Joe
Whiskers
socket2
socket1
IO Object
Server can check with req.user!
socketManager.addUser(whiskers, socket1)
(on initial connection)
Tell server which socket the user is
112
Fluffy
Joe
Whiskers
IO Object
Server can check with req.user!
Whiskers’
socket
Joe’s socket
socketManager.addUser(whiskers, socket1)
(on initial connection)
getSocketFromUserID
113
Fluffy
Joe
Whiskers
Joe’s socket
Whiskers’
socket
IO Object
We can now use socketManager.getSocketFromUserID
to get a user’s socket!
(this function is given to you by staff)
POST /api/meow “FOOD”
To Whiskers
getSocketFromUserID
114
Fluffy
Joe
Whiskers
Joe’s socket
Whiskers’
socket
IO Object
We can now use socketManager.getSocketFromUserID
to get a user’s socket!
(this function is given to you by staff)
socketManager
.getSocketFromUserID(“whiskers_id”)
.emit(“meow”, “FOOD”)
POST /api/meow “FOOD”
To Whiskers
weblab.is/chatbook-docs
weblab.is/socket-guide
115
YAY! We now have everything we need for DMs
Let’s talk about the plan ^___^
weblab.is/example
116
Chatbook Component Tree
117
ChatList
SingleMessage
SingleUser
Chatbook
Chat
NewMessage
Chatbook Component Tree
118
ChatList
SingleMessage
SingleUser
Chatbook
Chat
NewMessage
119
ChatList
SingleUser
Chatbook
120
ChatList
SingleUser
Chatbook
activeChat: ChatData
activeUsers: array of UserObject}
Props: {
setActiveUser: callback function,
userId: String,
users: array of UserObject,
active: UserObject
}
Props: {
setActiveUser: callback function,
user: UserObject,
active: Boolean
}
App
userId: String
Props: {userId: String}
121
UserObject: {
_id: String,
name: String
}
ChatData: {
messages: array of MessageObject,
recipient: UserObject
}
ChatList
SingleUser
Chatbook
activeChat: ChatData
activeUsers: array of UserObject}
Props: {
setActiveUser: callback function,
userId: String,
users: array of UserObject,
active: UserObject
}
Props: {
setActiveUser: callback function,
user: UserObject,
active: Boolean
}
App
userId: String
Props: {userId: String}
Backend API
122
123
client
Socket connection
124
client
Socket connection
POST /api/initsocket
125
client
login
POST /api/initsocket
126
client
login
POST /api/initsocket
emit(“activeUsers”, <list of users>)
client
127
client
GET /api/activeUsers
Now let’s code it up!
128
Catch Up!
git reset --hard�git checkout w9-step1
129
[Live Coding]
130
Step 1: Create the initsocket endpoint
131
git reset --hard; git checkout w9-step1
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 77
Whiskers
socket1
IO Object
(on initial connection)
POST /api/initsocket hi it’s whiskers, my socket is socket1
Step 2: Build SingleUser Buttons
132
git reset --hard; git checkout w9-step2
Types & APIs: weblab.is/chatbook-docs
File: SingleUser.js
Line: 14
Step 2: Build List of Users (ChatList)
133
git reset --hard; git checkout w9-step2
Types & APIs: weblab.is/chatbook-docs
File: ChatList.js
Line: 16
134
UserObject: {
_id: String,
name: String
}
ChatData: {
messages: array of MessageObject,
recipient: UserObject
}
ChatList
SingleUser
Chatbook
activeChat: ChatData
activeUsers: array of UserObject}
Props: {
setActiveUser: callback function,
userId: String,
users: array of UserObject,
active: UserObject
}
Props: {
setActiveUser: callback function,
user: UserObject,
active: Boolean
}
App
userId: String
Props: {userId: String}
Step 3: Add ChatList component to Chatbook
<ComponentName prop1name=prop1val prop2name=prop2val ../>
135
git reset --hard; git checkout w9-step3
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 86
Step 3: Add ChatList component to Chatbook
<ComponentName prop1name=prop1val prop2name=prop2val ../>
136
git reset --hard; git checkout w9-step3
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 86
Step 3: Add ChatList component to Chatbook
<ComponentName prop1name=prop1val prop2name=prop2val ../>
137
git reset --hard; git checkout w9-step3
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 86
Step 3: Add ChatList component to Chatbook
<ComponentName prop1name=prop1val prop2name=prop2val ../>
138
git reset --hard; git checkout w9-step3
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 86
Step 4: Implement /api/activeUsers
139
git reset --hard; git checkout w9-step4
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 103
Step 4: Implement /api/activeUsers
140
git reset --hard; git checkout w9-step4
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 103
Step 4: Implement /api/activeUsers
141
git reset --hard; git checkout w9-step4
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 103
[Live Coding]
142
Step 5: Call /activeUsers
143
git reset --hard; git checkout w9-step5
Types & APIs: weblab.is/chatbook-docs
File: ChatBook.js
Line: 69
Step 6: Listen for the activeUsers event
144
git reset --hard; git checkout w9-step6
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 85
Step 6: Listen for the activeUsers event
145
git reset --hard; git checkout w9-step6
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 85
Step 7: Implement setActiveUser
146
git reset --hard; git checkout w9-step7
Types & APIs: weblab.is/chatbook-docs
File: Chatbook.js
Line: 96
[Live Coding]
147
Step 8: Update /getChat
148
git reset --hard; git checkout w9-step8
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 82
let query;
if (req.query.recipient_id === "ALL_CHAT") {
query = { "recipient._id": "ALL_CHAT" };
} else {
// get messages that are from me->you OR you->me
query = {
$or: [
{ "sender._id": req.user._id, "recipient._id": req.query.recipient_id },
{ "sender._id": req.query.recipient_id, "recipient._id": req.user._id },
],
};
}
Step 9: Emit a message event to relevant users
149
git reset --hard; git checkout w9-step9
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 113
Step 9: Emit a message event to relevant users
150
git reset --hard; git checkout w9-step9
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 113
Step 9: Emit a message event to relevant users
151
git reset --hard; git checkout w9-step9
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 113
Step 9: Emit a message event to relevant users
152
git reset --hard; git checkout w9-step9
Types & APIs: weblab.is/chatbook-docs
File: api.js
Line: 113
Step 10: Filter some messages at on the client side
153
git reset --hard; git checkout w9-step10
Types & APIs: weblab.is/chatbook-docs
File:
Line:
Now you try! Catch the forceDisconnect event
154
SHOUT: socketManager.getIO()
whisper: socketManager.getSocketFromUserId()
155
client-socket & server-socket
156
Sockets in Practice
// Client, inside useEffect() with cleanup!
socket.on("eventName", (data) => {
// Do stuff with data
});
// Server, probably inside an API call or helper function
socketManager.getIo().emit("eventName", data); // SHOUT
// whisper
socketManager.getSocketFromUserID(userID).emit("eventName", data);
157
Details: weblab.is/socket-guide
Be Back at 1:00pm :)
Do not eat in the lecture hall :)
EOD Announcements