Skip to content

Commit 0eb53c3

Browse files
author
Duy Nguyen
committed
Add new express server for livechat message
1 parent 3ae739c commit 0eb53c3

18 files changed

+3204
-0
lines changed

.env.default

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
YOUTUBE_API_KEY=test
2+
YOUTUBE_CHANNEL_ID=test
3+
MESSAGE_API_URL=https://youtube.googleapis.com/youtube/v3/liveChat/messages
4+
SEARCH_API_URL=https://www.googleapis.com/youtube/v3/search
5+
VIDEO_API_URL=https://www.googleapis.com/youtube/v3/videos
6+
PORT=3458

.eslintrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"parser": "@typescript-eslint/parser",
3+
"extends": ["plugin:@typescript-eslint/recommended"],
4+
"parserOptions": { "ecmaVersion": 2018, "sourceType": "module" },
5+
"rules": {}
6+
}

.gitignore

+188
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
2+
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,dotenv
3+
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,dotenv
4+
5+
### dotenv ###
6+
.env
7+
8+
### macOS ###
9+
# General
10+
.DS_Store
11+
.AppleDouble
12+
.LSOverride
13+
14+
# Icon must end with two \r
15+
Icon
16+
17+
18+
# Thumbnails
19+
._*
20+
21+
# Files that might appear in the root of a volume
22+
.DocumentRevisions-V100
23+
.fseventsd
24+
.Spotlight-V100
25+
.TemporaryItems
26+
.Trashes
27+
.VolumeIcon.icns
28+
.com.apple.timemachine.donotpresent
29+
30+
# Directories potentially created on remote AFP share
31+
.AppleDB
32+
.AppleDesktop
33+
Network Trash Folder
34+
Temporary Items
35+
.apdisk
36+
37+
### Node ###
38+
# Logs
39+
logs
40+
*.log
41+
npm-debug.log*
42+
yarn-debug.log*
43+
yarn-error.log*
44+
lerna-debug.log*
45+
46+
# Diagnostic reports (https://nodejs.org/api/report.html)
47+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
48+
49+
# Runtime data
50+
pids
51+
*.pid
52+
*.seed
53+
*.pid.lock
54+
55+
# Directory for instrumented libs generated by jscoverage/JSCover
56+
lib-cov
57+
58+
# Coverage directory used by tools like istanbul
59+
coverage
60+
*.lcov
61+
62+
# nyc test coverage
63+
.nyc_output
64+
65+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
66+
.grunt
67+
68+
# Bower dependency directory (https://bower.io/)
69+
bower_components
70+
71+
# node-waf configuration
72+
.lock-wscript
73+
74+
# Compiled binary addons (https://nodejs.org/api/addons.html)
75+
build/Release
76+
77+
# Dependency directories
78+
node_modules/
79+
jspm_packages/
80+
81+
# TypeScript v1 declaration files
82+
typings/
83+
84+
# TypeScript cache
85+
*.tsbuildinfo
86+
87+
# Optional npm cache directory
88+
.npm
89+
90+
# Optional eslint cache
91+
.eslintcache
92+
93+
# Optional stylelint cache
94+
.stylelintcache
95+
96+
# Microbundle cache
97+
.rpt2_cache/
98+
.rts2_cache_cjs/
99+
.rts2_cache_es/
100+
.rts2_cache_umd/
101+
102+
# Optional REPL history
103+
.node_repl_history
104+
105+
# Output of 'npm pack'
106+
*.tgz
107+
108+
# Yarn Integrity file
109+
.yarn-integrity
110+
111+
# dotenv environment variables file
112+
.env.test
113+
.env*.local
114+
115+
# parcel-bundler cache (https://parceljs.org/)
116+
.cache
117+
.parcel-cache
118+
119+
# Next.js build output
120+
.next
121+
122+
# Nuxt.js build / generate output
123+
.nuxt
124+
dist
125+
126+
# Storybook build outputs
127+
.out
128+
.storybook-out
129+
storybook-static
130+
131+
# rollup.js default build output
132+
dist/
133+
134+
# Gatsby files
135+
.cache/
136+
# Comment in the public line in if your project uses Gatsby and not Next.js
137+
# https://nextjs.org/blog/next-9-1#public-directory-support
138+
# public
139+
140+
# vuepress build output
141+
.vuepress/dist
142+
143+
# Serverless directories
144+
.serverless/
145+
146+
# FuseBox cache
147+
.fusebox/
148+
149+
# DynamoDB Local files
150+
.dynamodb/
151+
152+
# TernJS port file
153+
.tern-port
154+
155+
# Stores VSCode versions used for testing VSCode extensions
156+
.vscode-test
157+
158+
# Temporary folders
159+
tmp/
160+
temp/
161+
162+
### Windows ###
163+
# Windows thumbnail cache files
164+
Thumbs.db
165+
Thumbs.db:encryptable
166+
ehthumbs.db
167+
ehthumbs_vista.db
168+
169+
# Dump file
170+
*.stackdump
171+
172+
# Folder config file
173+
[Dd]esktop.ini
174+
175+
# Recycle Bin used on file shares
176+
$RECYCLE.BIN/
177+
178+
# Windows Installer files
179+
*.cab
180+
*.msi
181+
*.msix
182+
*.msm
183+
*.msp
184+
185+
# Windows shortcuts
186+
*.lnk
187+
188+
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,dotenv

.prettierrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "all",
4+
"singleQuote": true,
5+
"printWidth": 120,
6+
"tabWidth": 2
7+
}

package.json

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"name": "server",
3+
"version": "1.0.0",
4+
"main": "server.ts",
5+
"license": "MIT",
6+
"scripts": {
7+
"start": "nodemon src/server.ts",
8+
"build": "tsc --project src/",
9+
"lint": "eslint src/**/*.ts",
10+
"format": "eslint src/**/*.ts --fix"
11+
},
12+
"husky": {
13+
"hooks": {
14+
"pre-commit": "yarn lint"
15+
}
16+
},
17+
"dependencies": {
18+
"axios": "^0.21.1",
19+
"cors": "^2.8.5",
20+
"dotenv": "^9.0.2",
21+
"express": "^4.17.1",
22+
"helmet": "^4.6.0",
23+
"husky": "^6.0.0",
24+
"module-alias": "^2.2.2",
25+
"monk": "^7.3.4",
26+
"monk-middleware-wrap-non-dollar-update": "^0.2.1",
27+
"morgan": "^1.10.0",
28+
"socket.io": "^4.1.2",
29+
"tslog": "^3.2.0"
30+
},
31+
"devDependencies": {
32+
"@types/express": "^4.17.11",
33+
"@types/morgan": "^1.9.2",
34+
"@types/node": "^15.3.0",
35+
"@typescript-eslint/eslint-plugin": "^4.24.0",
36+
"@typescript-eslint/parser": "^4.24.0",
37+
"eslint": "^7.26.0",
38+
"nodemon": "^2.0.7",
39+
"prettier": "^2.3.0",
40+
"ts-node": "^9.1.1",
41+
"typescript": "^4.2.4"
42+
}
43+
}

src/db.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import monk from 'monk';
2+
import { MongoDbUrl } from './env';
3+
import { logger, crashReporter, wrapNonDollarUpdateMiddleware } from './middlewares/query';
4+
5+
const db = monk(MongoDbUrl);
6+
db.addMiddleware(logger);
7+
db.addMiddleware(crashReporter);
8+
db.addMiddleware(wrapNonDollarUpdateMiddleware)
9+
export default db;

src/env.ts

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { YoutubeConfigType } from "./modules/youtube-chat/types";
2+
import dotenv from 'dotenv';
3+
dotenv.config();
4+
export default function getEnv(key: string): string | undefined {
5+
return process.env[key];
6+
}
7+
8+
export const PORT = getEnv('PORT') || 3000;
9+
10+
11+
export function getYoutubeConfig(): YoutubeConfigType {
12+
const API_KEY = getEnv('YOUTUBE_API_KEY');
13+
const YOUTUBE_CHANNEL_ID = getEnv('YOUTUBE_CHANNEL_ID')
14+
const MESSAGE_API_URL = getEnv('MESSAGE_API_URL')
15+
const SEARCH_API_URL = getEnv('SEARCH_API_URL')
16+
const VIDEO_API_URL = getEnv('VIDEO_API_URL')
17+
18+
if(!API_KEY || !YOUTUBE_CHANNEL_ID || !MESSAGE_API_URL || !SEARCH_API_URL || !VIDEO_API_URL) {
19+
throw new Error(`Some of youtube env var are missing, please check \n
20+
ApiKey: ${API_KEY}\n
21+
ChannelId: ${YOUTUBE_CHANNEL_ID}\n
22+
MessageApiUrl: ${MESSAGE_API_URL}\n
23+
SearchApiUrl: ${SEARCH_API_URL}\n
24+
VideoApiUrl: ${VIDEO_API_URL}\n
25+
`);
26+
}
27+
28+
return {
29+
API_KEY,
30+
YOUTUBE_CHANNEL_ID,
31+
MESSAGE_API_URL,
32+
SEARCH_API_URL,
33+
VIDEO_API_URL
34+
}
35+
}
36+
37+
export function getMongoUrl(): string {
38+
const MONGO_DB_URL = getEnv('MONGO_DB_URL');
39+
if (!MONGO_DB_URL) {
40+
throw new Error(`Mongo db url is undefined.`);
41+
}
42+
return MONGO_DB_URL;
43+
}
44+
45+
export const MongoDbUrl = getMongoUrl();
46+
47+
export const YoutubeConfig = getYoutubeConfig();

src/logger.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { Logger } from "tslog";
2+
const log: Logger = new Logger();
3+
4+
export default log;

src/middlewares/query.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { TMiddleware } from "monk"
2+
import log from "@/logger"
3+
4+
export const logger: TMiddleware = context => next => (args, method) => {
5+
log.info(method, args)
6+
return next(args, method).then((res) => {
7+
log.info(method + ' result', res)
8+
return res
9+
})
10+
}
11+
12+
export const crashReporter: TMiddleware = context => next => (args, method) => {
13+
return next(args, method).catch((err) => {
14+
log.error('Caught an exception!', err)
15+
throw err
16+
})
17+
}
18+
19+
export const wrapNonDollarUpdateMiddleware: TMiddleware = context => next => (args: any, method) => {
20+
const wrap = (args.options || {}).wrapNon$UpdateField
21+
if (typeof wrap !== 'undefined') {
22+
delete args.options.wrapNon$UpdateField
23+
}
24+
if (wrap !== true || !args.update) {
25+
return next(args, method)
26+
}
27+
28+
if (Object.keys(args.update).some(function (k) {
29+
return k.indexOf('$') !== 0
30+
})) {
31+
args.update = { $set: args.update }
32+
}
33+
34+
return next(args, method)
35+
}
36+

0 commit comments

Comments
 (0)