Skip to content
This repository was archived by the owner on Nov 22, 2023. It is now read-only.

Commit 5f58a03

Browse files
committed
change basic
0 parents  commit 5f58a03

20 files changed

+1077
-0
lines changed

.gitignore

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.DS_Store
2+
node_modules
3+
/dist
4+
5+
6+
# local env files
7+
.env.local
8+
.env.*.local
9+
10+
# Log files
11+
npm-debug.log*
12+
yarn-debug.log*
13+
yarn-error.log*
14+
pnpm-debug.log*
15+
16+
# Editor directories and files
17+
.idea
18+
.vscode
19+
*.suo
20+
*.ntvs*
21+
*.njsproj
22+
*.sln
23+
*.sw?
24+
package-lock.json
25+
26+
config.json

README.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
## Running the frontend
3+
4+
```
5+
npm install
6+
npm run serve
7+
```
8+
9+
### Running the server
10+
11+
```
12+
cd server
13+
npm install
14+
npm start
15+
```

babel.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
presets: [
3+
'@vue/cli-plugin-babel/preset'
4+
]
5+
}

package.json

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"name": "private-messaging",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"serve": "vue-cli-service serve",
7+
"build": "vue-cli-service build",
8+
"lint": "vue-cli-service lint"
9+
},
10+
"dependencies": {
11+
"core-js": "^3.6.5",
12+
"socket.io-client": "^3.1.1",
13+
"vue": "^2.6.11"
14+
},
15+
"devDependencies": {
16+
"@vue/cli-plugin-babel": "~4.5.0",
17+
"@vue/cli-plugin-eslint": "~4.5.0",
18+
"@vue/cli-service": "~4.5.0",
19+
"babel-eslint": "^10.1.0",
20+
"eslint": "^6.7.2",
21+
"eslint-plugin-vue": "^6.2.2",
22+
"vue-template-compiler": "^2.6.11"
23+
},
24+
"eslintConfig": {
25+
"root": true,
26+
"env": {
27+
"node": true
28+
},
29+
"extends": [
30+
"plugin:vue/essential",
31+
"eslint:recommended"
32+
],
33+
"parserOptions": {
34+
"parser": "babel-eslint"
35+
},
36+
"rules": {}
37+
},
38+
"browserslist": [
39+
"> 1%",
40+
"last 2 versions",
41+
"not dead"
42+
]
43+
}

public/favicon.ico

4.19 KB
Binary file not shown.

public/fonts/Lato-Regular.ttf

73.4 KB
Binary file not shown.

public/index.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width,initial-scale=1.0">
7+
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
8+
<title>Private messaging with Socket.IO</title>
9+
</head>
10+
<body>
11+
<noscript>
12+
<strong>We're sorry but this application doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
13+
</noscript>
14+
<div id="app"></div>
15+
<!-- built files will be auto injected -->
16+
</body>
17+
</html>

server/index.js

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
const requestHandler = require('./requestHandler')
2+
3+
const httpServer = require('http').createServer(requestHandler)
4+
5+
const io = require("socket.io")(httpServer, {
6+
cors: {
7+
origin: "http://localhost:8080",
8+
},
9+
})
10+
11+
12+
const crypto = require("crypto")
13+
const randomId = () => crypto.randomBytes(8).toString("hex")
14+
15+
const { InMemorySessionStore } = require("./sessionStore")
16+
const sessionStore = new InMemorySessionStore()
17+
18+
const { InMemoryMessageStore } = require("./messageStore")
19+
const messageStore = new InMemoryMessageStore()
20+
21+
io.use((socket, next) => {
22+
const sessionID = socket.handshake.auth.sessionID
23+
if (sessionID) {
24+
const session = sessionStore.findSession(sessionID)
25+
if (session) {
26+
socket.sessionID = sessionID
27+
socket.userID = session.userID
28+
socket.username = session.username
29+
return next()
30+
}
31+
}
32+
const username = socket.handshake.auth.username
33+
if (!username) {
34+
return next(new Error("invalid username"))
35+
}
36+
socket.sessionID = randomId()
37+
socket.userID = randomId()
38+
socket.username = username
39+
next()
40+
})
41+
42+
io.on("connection", (socket) => {
43+
// persist session
44+
sessionStore.saveSession(socket.sessionID, {
45+
userID: socket.userID,
46+
username: socket.username,
47+
connected: true,
48+
})
49+
50+
// emit session details
51+
socket.emit("session", {
52+
sessionID: socket.sessionID,
53+
userID: socket.userID,
54+
})
55+
56+
// join the "userID" room
57+
socket.join(socket.userID)
58+
59+
// fetch existing users
60+
const users = []
61+
const messagesPerUser = new Map()
62+
messageStore.findMessagesForUser(socket.userID).forEach((message) => {
63+
const { from, to } = message
64+
const otherUser = socket.userID === from ? to : from
65+
if (messagesPerUser.has(otherUser)) {
66+
messagesPerUser.get(otherUser).push(message)
67+
} else {
68+
messagesPerUser.set(otherUser, [message])
69+
}
70+
})
71+
sessionStore.findAllSessions().forEach((session) => {
72+
users.push({
73+
userID: session.userID,
74+
username: session.username,
75+
connected: session.connected,
76+
messages: messagesPerUser.get(session.userID) || [],
77+
})
78+
})
79+
socket.emit("users", users)
80+
81+
// notify existing users
82+
socket.broadcast.emit("user connected", {
83+
userID: socket.userID,
84+
username: socket.username,
85+
connected: true,
86+
messages: [],
87+
})
88+
89+
// forward the private message to the right recipient (and to other tabs of the sender)
90+
socket.on("private message", ({ content, to }) => {
91+
const message = {
92+
content,
93+
from: socket.userID,
94+
to,
95+
}
96+
socket.to(to).to(socket.userID).emit("private message", message)
97+
messageStore.saveMessage(message)
98+
})
99+
100+
// notify users upon disconnection
101+
socket.on("disconnect", async () => {
102+
const matchingSockets = await io.in(socket.userID).allSockets()
103+
const isDisconnected = matchingSockets.size === 0
104+
if (isDisconnected) {
105+
// notify other users
106+
socket.broadcast.emit("user disconnected", socket.userID)
107+
// update the connection status of the session
108+
sessionStore.saveSession(socket.sessionID, {
109+
userID: socket.userID,
110+
username: socket.username,
111+
connected: false,
112+
})
113+
}
114+
})
115+
})
116+
117+
const PORT = process.env.PORT || 3000
118+
119+
httpServer.listen(PORT, () =>
120+
console.log(`server listening at http://localhost:${PORT}`)
121+
)

server/messageStore.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* abstract */ class MessageStore {
2+
saveMessage(message) {}
3+
findMessagesForUser(userID) {}
4+
}
5+
6+
class InMemoryMessageStore extends MessageStore {
7+
constructor() {
8+
super();
9+
this.messages = [];
10+
}
11+
12+
saveMessage(message) {
13+
this.messages.push(message);
14+
}
15+
16+
findMessagesForUser(userID) {
17+
return this.messages.filter(
18+
({ from, to }) => from === userID || to === userID
19+
);
20+
}
21+
}
22+
23+
module.exports = {
24+
InMemoryMessageStore,
25+
};

server/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "server",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "node index.js"
8+
},
9+
"author": "Damien Arrachequesne <[email protected]>",
10+
"license": "MIT",
11+
"dependencies": {
12+
"mongodb": "^4.1.1",
13+
"socket.io": "^3.1.1"
14+
}
15+
}

0 commit comments

Comments
 (0)