-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add room and chat classes #30 #39
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work :) the changes generally outline that the Server should deal with storing the global Room object (for Server Side Rendering). Please review the client-server model that should help you when making the changes
public/js/chat-channel.js
Outdated
@@ -0,0 +1,17 @@ | |||
class ChatRoom { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps change 'ChatRoom' to just Room (as this will hold endpoints that are sending messages to each-other, as well as sending ChatRoom messages).
Perhaps the logic of this function should be built into our current client side Comms file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@esraajb
A rooms
object is now initialised in server.js
- check the latest version of master
The /create route will be responsible for everything you are doing here:
- putting a new room inside the
rooms
object, based on theroomId
- creating a new endpoint
- adding "chat" to the permissions
public/js/chat.js
Outdated
// let username = document.getElementById('username'); | ||
|
||
register.addEventListener('click', () => { | ||
// registeration proccess(creating new user, making sure the username is not exist in the room, adding the user endpoint to the specific room endpoints list) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this logic! Though it may be tricky to implement in this sprint (instead of the previously suggested method of Server Side rendering), as we'd have to deal with a lot of DOM manipulation
public/js/helpers.js
Outdated
const ErrorUsernameTaken = () => { | ||
let error = '<p>username taken</p>'; | ||
document.getElementById('message').insertAdjacentHTML('beforebegin', error); | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this would be a great implementation if we were opting for a client side rendering approach (single page app) for this sprint
public/js/new-user.js
Outdated
@@ -0,0 +1,18 @@ | |||
let users = []; | |||
|
|||
class NewUser { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class could just be called 'Users', and addUser could be a method inside this users class
public/js/new-user.js
Outdated
users.push(username) | ||
} | ||
|
||
isValid() { //should edit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Though instead of calling seperate functions, this isValid function should probably just return true or false, then the successUserName function will check whether the isValid function has returned true or false
src/chat-handler.js
Outdated
const chatHandler = (route, data) => { | ||
switch (route) { | ||
case ('CHATROOM.REGISTER') : { | ||
newuser = new NewUser(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This switch case will be called when a new socket is registering itself (against an existing endpoint in our data store). So a student journey could look like this;
- Student registers themselves when first visiting the site (post request to /join)
- Server registers the user/endpoint in rooms module
- Server sends client view
- Client side js fires Websocket for the first time (msg with chatroom.register)
- Server adds the sockets id to the rooms object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call this join
rather than register
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@njsfield 's point 5 above refers to no. 11 in the mentor journey of the client/server model. So the server-side chat.js
needs to contain method like addSocket
, which puts the appropriate socketId into the endpoints
object.
src/chat-handler.js
Outdated
}; | ||
|
||
io.on('connection', (socket) => { | ||
socket.on('message', (message) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Perhaps on 'disconnect', a message is sent into the above switch statement with 'chat.disconnect' message? Then the clientid will get removed from the room?
public/js/new-user.js
Outdated
@@ -0,0 +1,18 @@ | |||
let users = []; | |||
|
|||
class NewUser { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon the class should be 'users' rather than 'NewUser'? In the same way that we have class 'ChatRoom', not 'NewChatRoom'
a new user is just an instance of 'users'
public/js/chat-channel.js
Outdated
@@ -0,0 +1,17 @@ | |||
class ChatRoom { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@esraajb
A rooms
object is now initialised in server.js
- check the latest version of master
The /create route will be responsible for everything you are doing here:
- putting a new room inside the
rooms
object, based on theroomId
- creating a new endpoint
- adding "chat" to the permissions
public/js/chat.js
Outdated
|
||
comms.registerHandler('CHATROOM', 'REGISTER', /*TODO*/); | ||
comms.registerHandler('CHATROOM', 'MESSAGE', /*TODO*/); | ||
comms.registerHandler('CHATROOM', 'DISCONNECT', /*TODO*/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comms.js
comes in at no. 8 & 9 (of latest docs for mentor journey https://github.com/foundersandcoders/Live-Peers/blob/2545e0358926c863e5293e147874e3822a5f4c63/docs/sprint1/client-server-model/1.%20Mentor%20View.png).
I reckon registerHandler
is better than send
(see no. 9), but addApp
might be better?
src/chat-handler.js
Outdated
const chatHandler = (route, data) => { | ||
switch (route) { | ||
case ('CHATROOM.REGISTER') : { | ||
newuser = new NewUser(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we call this join
rather than register
?
src/chat-handler.js
Outdated
const chatHandler = (route, data) => { | ||
switch (route) { | ||
case ('CHATROOM.REGISTER') : { | ||
newuser = new NewUser(data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@njsfield 's point 5 above refers to no. 11 in the mentor journey of the client/server model. So the server-side chat.js
needs to contain method like addSocket
, which puts the appropriate socketId into the endpoints
object.
Instead of chatHandler, I created chat class const appendP = (output, comms, from, message) => {
output.appendChild(elt('p', from + ' : ' + message));
};
class Chat {
constructor (comms, input, output, form) {
this.comms = comms;
this.input = input;
this.output = output;
this.form = form;
this.app = 'CHATROOM';
this.sys = 'SYSTEM';
comms.send(this.app, 'REGISTER', this.sys, 'JOINED');
comms.registerHandler(this.app, 'REGISTER', appendP.bind(null, output));
comms.registerHandler(this.app, 'MESSAGE', appendP.bind(null, output));
comms.registerHandler(this.app, 'DISCONNECT', appendP.bind(null, output));
this.form.onsubmit = (e) => {
e.preventDefault();
if (this.input.value) {
this.comms.send(this.app, 'MESSAGE', this.sys, this.input.value);
this.input.value = '';
}
};
this.input.onkeydown = (e) => {
if (e.which === 13 && this.input.value) {
this.comms.send(this.app, 'MESSAGE', this.sys, this.input.value);
this.input.value = '';
}
};
}
} const elt = (type, msg) => {
const newElt = document.createElement(type);
newElt.innerHTML = msg;
return newElt;
}; room class // Global room class
class Room {
constructor (roomname) {
this.roomname = roomname;
this.endpoints = {};
}
addEndpoint (endpointId) {
this.endpoints[endpointId] = {
name: '',
permissions: 'CHAT',
commsid: ''
};
}
updateEndpointName (endpointId, Name) {
this.endpoints[endpointId].name = Name;
}
updateEndpointPermissions (endpointId, permissions) {
this.endpoints[endpointId].permissions = permissions;
}
updateEndpointCommsID (endpointId, commsid) {
this.endpoints[endpointId].commsid = commsid;
}
removeEndpoint (endpointId) {
delete this.endpoints[endpointId];
}
getRoomName () {
return this.roomname;
}
getEndpointNameFromCommsID (commsid) {
for (let props in this.endpoints) {
if (this.endpoints[props].commsid === commsid) {
return props;
}
}
}
}
module.exports = Room; big credit to nick |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really cool @esraajb
I started writing this class myself, because I needed to call its methods with the routes. But I got myself in a few knots. This looks really clean 😄
Just a few changes before we can merge
src/room.js
Outdated
}; | ||
} | ||
updateEndpointName (endpointId, Name) { | ||
this.endpoints[endpointId].name = Name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason why Name
starts with a capital?
src/room.js
Outdated
}; | ||
} | ||
updateEndpointName (endpointId, Name) { | ||
this.endpoints[endpointId].name = Name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- this is not the "endpoint name", this is the user's username. Can we change this variable to
username
@njsfield? - any reason why the parameter
Name
starts with a capital letter?
src/room.js
Outdated
this.endpoints[endpointId] = { | ||
name: '', | ||
permissions: 'CHAT', | ||
commsid: '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than initialising endpoints with some empty strings, we could either have a few more methods:
- addUsername
- addPermissions
- addCommsId
Or change the "update" methods so that they can also be used for adding username
etc when they don't yet exist
src/room.js
Outdated
updateEndpointName (endpointId, Name) { | ||
this.endpoints[endpointId].name = Name; | ||
} | ||
updateEndpointPermissions (endpointId, permissions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming is slightly redundant. Can we just change these to:
- updateUsername
- updatePermissions
- updateCommsId
?
src/room.js
Outdated
}; | ||
} | ||
updateEndpointName (endpointId, Name) { | ||
this.endpoints[endpointId].name = Name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- this is not the "endpoint name", this is the user's username. @njsfield @esraajb Can we change this variable to
username
? - @esraajb any reason why the parameter
Name
starts with a capital letter?
src/room.js
Outdated
this.endpoints[endpointId] = { | ||
name: '', | ||
permissions: 'CHAT', | ||
commsid: '' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than initialising endpoints with some empty strings, we could either:
- have a few more methods:
- addUsername
- addPermissions
- addCommsId
- change the "update" methods so that they can also be used for adding new username/permissions/commsId. For example:
updateUsername (endpointId, username) {
this.endpoints[endpointId][username] = username;
}
src/room.js
Outdated
updateEndpointPermissions (endpointId, permissions) { | ||
this.endpoints[endpointId].permissions = permissions; | ||
} | ||
updateEndpointCommsID (endpointId, commsid) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this sounds really pedantic 😅, but please can we be consistent with capitalising: commsID
vs commsId
vs commsid
.
Everywhere else, we have capital I
, lowercase d
👍
public/js/chat.js
Outdated
@@ -0,0 +1,34 @@ | |||
const appendP = (output, comms, from, message) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove 'comms' argument. This will be the implementation of Comms.js on the client side...
The chatroom/webrtc module constructors will take the comms instance, so for our comms.js module instead of this-
self.handlers[msg.app + '.' + msg.method](this, msg.from, msg.params);
The comms.js will be calling its handlers like this-
self.handlers[msg.app + '.' + msg.method](msg.from, msg.params);
@esraajb Can you change the name of this pull to be descriptive about what you're actually asking to be merged, and update the body to say that it relates to the relevant issue, please? |
@jsms90 please see last two commits |
src/room.js
Outdated
commsId: '' | ||
}; | ||
} | ||
updateUsernameame (endpointId, username) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spelling should be updateUsername
if (this.endpoints[props].commsId === commsId) { | ||
return props; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also have a getCommsId method, that takes an endpointId as its argument and returns the endpoints comms id
public/js/chat.js
Outdated
this.input = input; | ||
this.output = output; | ||
this.form = form; | ||
this.app = 'CHATROOM'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHAT instead of CHATROOM now
src/room.js
Outdated
this.endpoints = {}; | ||
} | ||
addEndpoint (endpointId) { | ||
this.endpoints[endpointId] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still got this issue from before:
Rather than initialising endpoints with some empty strings, we should just have this.endpoints = {}
Whereas the addEndpoint
method should create a new endpointId, like I have done here:
addEndpoint () {
let endpointId = // function to create a random string
this.endpoints[endpointId] = {};
}
And then we need a few more methods:
- addUsername
- addPermissions
- addCommsId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im not sure we need to add these new functions.
I think the update functions will do the job as they will create the property if its not already exist.
all we need to do is use brackets as you said.
updateUsername (endpointId, username) {
this.endpoints[endpointId]['username'] = username;
}
src/room.js
Outdated
}; | ||
} | ||
updateUsername (endpointId, username) { | ||
this.endpoints[endpointId].username = username; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to use bracket syntax, if username
is not already defined? So:
this.endpoints[endpointId].username = username
(Same for the other update
functions)
@njsfield @esraajb I might be wrong about that? But I think it wasn't working for me when I used dot syntax like this elsewhere.
this.endpoints = {}; | ||
} | ||
addEndpoint (endpointId) { | ||
this.endpoints[endpointId] = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think it would be better to have an the endpointId
string being created by this addEndpoint
method. That way, the apps themselves aren't left to declare an endpointId
in whatever form they choose. @njsfield @esraajb Do you disagree?
See my last comment:
the addEndpoint
method should create a new endpointId, like I have done here:
addEndpoint () {
let endpointId = // function to create a random string
this.endpoints[endpointId] = {};
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or you could separate it further, if you wanted to be pure with your functions:
createEndpoint () {
let endpointId = Math.random().toString(36).slice(2);
return endpointId;
}
addEndpoint (endpointId) {
this.endpoints[endpointId] = {};
}
But there's little point, since you'll never create an endpoint, separately from adding it to the endpoints
object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like some of the changes I suggested earlier still stand, but it's probably just worth merging this now and dealing with it later, if we need to 👍
this.endpoints = {}; | ||
} | ||
addEndpoint (endpointId) { | ||
this.endpoints[endpointId] = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or you could separate it further, if you wanted to be pure with your functions:
createEndpoint () {
let endpointId = Math.random().toString(36).slice(2);
return endpointId;
}
addEndpoint (endpointId) {
this.endpoints[endpointId] = {};
}
But there's little point, since you'll never create an endpoint, separately from adding it to the endpoints
object
Add chat and room classes.
relates to #30
Ok, so Ive been working on this issue for last days.
Here is where Iam currently:
When i think about the whole process, I can see that we should have two classes:
couple of things about these classes:
io[username]=username (we can move username with a socket from the client side to the server side). im not sure which approach we should follow.
CHAT HANDLERS:
Client side:
A) the CB function at the registerHandler. i didnt really know what i should implement in it. in one hand i would redirect to the router at the backend, but because we are using websockets, im doing that at the router file (see example below).
B) im not sure how to start the registration process
Server Side:
I) Im not sure if i can chatHandler('CHATROOM.REGISTRATION', data) after io.on('connection, (scoket) =>{
help with that would be appreciated (this issue also refers to point B)
I didnt have time to setup a server and work with it.
at the beginning i build the whole chat with websockets and express server and i could implement alot of things, when i switched and started working with the comms file things got a little bit more complicated.
would love to hear what you think and help with it :)