Simple Chat
Video Lecture
Description
Creating a simple chat client and server.
./src/server/randomScreenNameGenerator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 export default class RandomScreenNameGenerator {
private animals = [
'Cat' ,
'Dog' ,
'Bird' ,
'Tiger' ,
'Giraffe' ,
'Elephant' ,
'Koala' ,
'Bee' ,
'Fly' ,
'Fish' ,
'Frog'
]
private colours = [ 'Red' , 'Green' , 'Blue' , 'Yellow' , 'Orange' , 'Purple' ]
public generateRandomScreenName () {
let colour = this . colours [ Math . floor ( Math . random () * this . colours . length )]
let animal = this . animals [ Math . floor ( Math . random () * this . animals . length )]
let screenName = {
name : colour + ' ' + animal ,
abbreviation : colour [ 0 ] + animal [ 0 ]
}
return screenName
}
}
./src/server/server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 import { createServer } from 'http'
import { Server } from 'socket.io'
import * as express from 'express'
import * as path from 'path'
import RandomScreenNameGenerator from './randomScreenNameGenerator'
const port = 3000
const app = express ()
app . use ( express . static ( path . join ( __dirname , '../client' )))
const server = createServer ( app )
const io = new Server ( server )
const randomScreenNameGenerator = new RandomScreenNameGenerator ()
io . on ( 'connection' , ( socket ) => {
console . log ( 'a user connected : ' + socket . id )
let screenName = randomScreenNameGenerator . generateRandomScreenName ()
socket . emit ( 'screenName' , screenName )
socket . broadcast . emit ( 'systemMessage' , screenName . name + ' has joined the chat' )
socket . on ( 'disconnect' , () => {
console . log ( 'socket disconnected : ' + socket . id )
socket . broadcast . emit ( 'systemMessage' , screenName . name + ' has left the chat' )
})
socket . on ( 'chatMessage' , ( message : ChatMessage ) => {
socket . broadcast . emit ( 'chatMessage' , message )
})
})
server . listen ( port , () => {
console . log ( 'Server listening on port ' + port )
})
./src/typings/index.d.ts
type ScreenName = {
name : string
abbreviation : string
}
type ChatMessage = {
message : string
from : string
}
./src/server/tsconfig.json
{
"compilerOptions" : {
"target" : "ES6" ,
"module" : "commonjs" ,
"outDir" : "../../dist/server" ,
"strict" : true
},
"include" : [ "**/*.ts" , "../typings/*" ]
}
./src/client/client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 import { io } from 'socket.io-client'
let screenName : ScreenName
const messageList = document . getElementById ( 'messageList' ) as HTMLOListElement
const messageText = document . getElementById ( 'messageText' ) as HTMLInputElement
const sendButton = document . getElementById ( 'sendButton' ) as HTMLButtonElement
const socket = io ()
socket . on ( 'connect' , () => {
console . log ( 'connect' )
})
socket . on ( 'disconnect' , ( message ) => {
console . log ( 'disconnect ' + message )
})
socket . on ( 'screenName' , ( message : ScreenName ) => {
screenName = message
;( document . getElementsByClassName ( 'screenName' )[ 0 ] as HTMLSpanElement ). innerText =
screenName . name
})
socket . on ( 'chatMessage' , ( message : ChatMessage ) => {
const li = document . createElement ( 'li' )
li . innerHTML =
"<span class='circle' style='float: right;'>" +
message . from +
"</span><div class='otherMessage'>" +
message . message +
'</div>'
messageList . appendChild ( li )
scrollChatWindow ()
})
socket . on ( 'systemMessage' , ( message ) => {
const li = document . createElement ( 'li' )
li . innerHTML = "<div class='systemMessage'>" + message + '</div>'
messageList . appendChild ( li )
scrollChatWindow ()
})
messageText . addEventListener ( 'keypress' , ( e ) => {
if ( e . code === 'Enter' ) {
sendMessage ()
return false
}
})
function sendMessage () {
if ( messageText . value . length > 0 ) {
socket . emit ( 'chatMessage' , < ChatMessage > {
message : messageText.value ,
from : screenName.abbreviation
})
const li = document . createElement ( 'li' )
li . innerHTML =
"<span class='circle' style='float: left;'>" +
screenName . abbreviation +
"</span><div class='myMessage'>" +
messageText . value +
'</div>'
messageList . appendChild ( li )
messageText . value = ''
scrollChatWindow ()
}
}
sendButton . addEventListener ( 'click' , () => {
sendMessage ()
})
function scrollChatWindow () {
const count = document . querySelectorAll ( '#messageList li' ). length
if ( count > 10 ) {
messageList . removeChild ( messageList . firstChild as HTMLLIElement )
}
messageList . scrollTo ({ top : messageList.scrollHeight , behavior : 'smooth' })
}
./src/client/tsconfig.json
{
"compilerOptions" : {
"target" : "ES2022" ,
"module" : "ES2022" ,
"outDir" : "../../dist/client/" ,
"moduleResolution" : "Bundler" ,
"strict" : true
},
"include" : [ "**/*.ts" , "../typings/*" ]
}
./dist/client/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127 <!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title >
Simple Chat : Socket.IO TypeScript Tutorials by Sean Bradley :
https://sbcode.net/tssock/
</ title >
< style >
body {
font-family : Arial ;
}
. chatPanel {
border : solid 1 px gray ;
border-radius : 20 px 0 px 4 px 4 px ;
box-shadow : 15 px 10 px #dddddd ;
background : rgb ( 34 , 193 , 195 );
background : linear-gradient (
56 deg ,
rgba ( 34 , 193 , 195 , 0.49193275943189773 ) 0 % ,
rgba ( 253 , 187 , 45 , 0.494733879880077 ) 100 %
);
position : relative ;
width : 500 px ;
}
. chatMessageInputDiv {
position : absolute ;
bottom : 0 px ;
width : 100 % ;
}
# messageText {
width : 400 px ;
font-size : 21 px ;
}
# sendButton {
position : absolute ;
right : 0 px ;
width : 93 px ;
height : 31 px ;
border-radius : 0 ;
border : 0 px ;
color : #fff ;
background-color : #17a2b8 ;
border-color : #17a2b8 ;
font-size : 21 px ;
}
# messageList {
padding-left : 0 ;
overflow : hidden ;
height : 338 px ;
margin-bottom : 40 px ;
}
# messageList li {
list-style-type : none ;
margin-bottom : 30 px ;
padding : 6 px 6 px 6 px 6 px ;
display : block ;
}
. otherMessage {
background : #ffcda3 ;
border : solid 1 px gray ;
margin : 0 px 5 px 5 px 0 px ;
float : right ;
padding : 0 px 6 px 0 px 6 px ;
border-radius : 10 px 10 px 0 10 px ;
font-size : 21 px ;
}
. myMessage {
background : #1bffbb ;
border : solid 1 px gray ;
margin : 0 px 5 px 5 px 5 px ;
float : left ;
padding : 0 px 6 px 0 px 6 px ;
border-radius : 10 px 10 px 10 px 0 ;
font-size : 21 px ;
}
. systemMessage {
background : #dddddd ;
border : solid 1 px gray ;
margin : 0 px 5 px 5 px 0 px ;
float : right ;
padding : 0 px 6 px 0 px 6 px ;
border-radius : 10 px 10 px 0 10 px ;
font-size : 21 px ;
}
. screenName {
padding : 6 px 6 px 6 px 6 px ;
border-radius : 10 px 10 px 10 px 10 px ;
font-weight : bold ;
background : #1bffbb ;
}
. circle {
padding : 6 px ;
background : gray ;
border-radius : 50 px ;
}
</ style >
</ head >
< body >
< h1 > Your Screen Name is < span class = "screenName" ></ span ></ h1 >
< div class = "chatPanel" >
< ol id = "messageList" ></ ol >
< div class = "chatMessageInputDiv" >
< div >
< input id = "messageText" placeholder = "Enter Chat Message" />
< span >
< button id = "sendButton" > Send</ button >
</ span >
</ div >
</ div >
</ div >
< script type = "module" src = "bundle.js" ></ script >
</ body >
</ html >