├── .gitattributes
├── .gitignore
├── Chapter 1
└── fiboapp.js
├── Chapter 10
├── compose
│ └── docker-compose.yml
├── db-auth
│ └── Dockerfile
├── db-notes
│ └── Dockerfile
├── notes
│ ├── Dockerfile
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── bower.json
│ ├── brand_guideline_logos_0.zip
│ ├── cyborg
│ │ ├── _bootswatch.scss
│ │ ├── _variables.scss
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ ├── bootswatch.less
│ │ └── variables.less
│ ├── ecosystem.json
│ ├── models
│ │ ├── Note.js
│ │ ├── messages-sequelize.js
│ │ ├── mysql-create-db.sql
│ │ ├── notes-events.js
│ │ ├── notes-fs.js
│ │ ├── notes-levelup.js
│ │ ├── notes-memory.js
│ │ ├── notes-mongodb.js
│ │ ├── notes-sequelize.js
│ │ ├── notes-sqlite3.js
│ │ ├── schema-sqlite3.sql
│ │ ├── sequelize-docker-mysql.yaml
│ │ ├── sequelize-mysql.yaml
│ │ ├── sequelize-server-mysql.yaml
│ │ ├── sequelize-sqlite.yaml
│ │ ├── sqlite3-exec.js
│ │ ├── sqlite3-utils.js
│ │ ├── users-rest.js
│ │ └── users-sequelize.js
│ ├── notes-sequelize.sqlite3
│ ├── package.json
│ ├── public
│ │ ├── images
│ │ │ └── twitter-brand-logos
│ │ │ │ ├── TwitterLogo_#55acee.eps
│ │ │ │ ├── TwitterLogo_#55acee.png
│ │ │ │ ├── TwitterLogo_white.eps
│ │ │ │ └── TwitterLogo_white.png
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── index.js
│ │ ├── notes.js
│ │ └── users.js
│ ├── variables.less
│ └── views
│ │ ├── error.ejs.html
│ │ ├── footer.ejs
│ │ ├── headerStuff.ejs
│ │ ├── index.ejs.html
│ │ ├── login.ejs.html
│ │ ├── not-logged-in.ejs
│ │ ├── notedestroy.ejs.html
│ │ ├── noteedit.ejs.html
│ │ ├── noteview.ejs.html
│ │ └── pageHeader.ejs.html
└── users
│ ├── Dockerfile
│ ├── mysql-create-db.sql
│ ├── package.json
│ ├── sequelize-docker-mysql.yaml
│ ├── sequelize-mysql.yaml
│ ├── sequelize-server-mysql.yaml
│ ├── sequelize-sqlite.yaml
│ ├── user-server.js
│ ├── users-add.js
│ ├── users-delete.js
│ ├── users-find.js
│ ├── users-list.js
│ └── users-sequelize.js
├── Chapter 11
├── assert
│ ├── deleteFile.js
│ └── test-deleteFile.js
├── compose
│ └── docker-compose.yml
├── db-auth
│ └── Dockerfile
├── db-notes
│ └── Dockerfile
├── notes
│ ├── Dockerfile
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── bower.json
│ ├── brand_guideline_logos_0.zip
│ ├── chap11.sqlite3
│ ├── cyborg
│ │ ├── _bootswatch.scss
│ │ ├── _variables.scss
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ ├── bootswatch.less
│ │ └── variables.less
│ ├── ecosystem.json
│ ├── models
│ │ ├── Note.js
│ │ ├── messages-sequelize.js
│ │ ├── mysql-create-db.sql
│ │ ├── notes-events.js
│ │ ├── notes-fs.js
│ │ ├── notes-levelup.js
│ │ ├── notes-memory.js
│ │ ├── notes-mongodb.js
│ │ ├── notes-sequelize.js
│ │ ├── notes-sqlite3.js
│ │ ├── schema-sqlite3.sql
│ │ ├── sequelize-docker-mysql.yaml
│ │ ├── sequelize-mysql.yaml
│ │ ├── sequelize-server-mysql.yaml
│ │ ├── sequelize-sqlite.yaml
│ │ ├── sqlite3-exec.js
│ │ ├── sqlite3-utils.js
│ │ ├── users-rest.js
│ │ └── users-sequelize.js
│ ├── package.json
│ ├── public
│ │ ├── images
│ │ │ └── twitter-brand-logos
│ │ │ │ ├── TwitterLogo_#55acee.eps
│ │ │ │ ├── TwitterLogo_#55acee.png
│ │ │ │ ├── TwitterLogo_white.eps
│ │ │ │ └── TwitterLogo_white.png
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── index.js
│ │ ├── notes.js
│ │ └── users.js
│ ├── variables.less
│ └── views
│ │ ├── error.ejs.html
│ │ ├── footer.ejs
│ │ ├── headerStuff.ejs
│ │ ├── index.ejs.html
│ │ ├── login.ejs.html
│ │ ├── not-logged-in.ejs
│ │ ├── notedestroy.ejs.html
│ │ ├── noteedit.ejs.html
│ │ ├── noteview.ejs.html
│ │ └── pageHeader.ejs.html
├── test-compose
│ ├── docker-compose.yml
│ ├── notesmodel
│ │ ├── sequelize-docker-mysql.yaml
│ │ ├── sequelize-mysql.yaml
│ │ ├── sequelize-sqlite.yaml
│ │ └── test-model.js
│ ├── notesui
│ │ └── uitest.js
│ ├── reports-notes
│ │ ├── notes-fs.json
│ │ ├── notes-levelup.json
│ │ ├── notes-memory.json
│ │ ├── notes-sequelize-mysql.json
│ │ ├── notes-sequelize-sqlite.json
│ │ ├── notes-sqlite3.json
│ │ └── notesui.xml
│ ├── reports-userauth
│ │ └── userauth.json
│ ├── run.sh
│ └── userauth
│ │ ├── sequelize-docker-mysql.yaml
│ │ └── test.js
└── users
│ ├── Dockerfile
│ ├── mysql-create-db.sql
│ ├── package.json
│ ├── sequelize-docker-mysql.yaml
│ ├── sequelize-mysql.yaml
│ ├── sequelize-server-mysql.yaml
│ ├── sequelize-sqlite.yaml
│ ├── user-server.js
│ ├── users-add.js
│ ├── users-delete.js
│ ├── users-find.js
│ ├── users-list.js
│ └── users-sequelize.js
├── Chapter 2
├── app.js
├── ls.js
└── ls2.js
├── Chapter 3
├── module1.js
├── module2.js
└── simple.js
├── Chapter 4
├── app1
│ ├── app1.js
│ └── server.js
├── events
│ ├── httpsniffer.js
│ └── pulser.js
├── fibonacci
│ ├── _gitignore
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── fiboclient.js
│ ├── fiboserver.js
│ ├── fibotimes.js
│ ├── math.js
│ ├── package.json
│ ├── public
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── fibonacci.js
│ │ └── index.js
│ └── views
│ │ ├── bottom.ejs
│ │ ├── error.ejs.html
│ │ ├── fibonacci.ejs
│ │ ├── index.ejs
│ │ └── top.ejs.html
└── wget.js
├── Chapter 5
└── notes
│ ├── app.js
│ ├── bin
│ └── www
│ ├── models
│ ├── Note.js
│ └── notes-memory.js
│ ├── package.json
│ ├── public
│ └── stylesheets
│ │ └── style.css
│ ├── routes
│ ├── index.js
│ ├── notes.js
│ └── users.js
│ └── views
│ ├── error.ejs.html
│ ├── footer.ejs
│ ├── headerStuff.ejs.html
│ ├── index.ejs.html
│ ├── notedestroy.ejs.html
│ ├── noteedit.ejs.html
│ ├── noteview.ejs.html
│ └── pageHeader.ejs.html
├── Chapter 6
└── notes
│ ├── app.js
│ ├── bin
│ └── www
│ ├── bower.json
│ ├── cyborg
│ ├── _bootswatch.scss
│ ├── _variables.scss
│ ├── bootstrap.css
│ ├── bootstrap.min.css
│ ├── bootswatch.less
│ └── variables.less
│ ├── models
│ ├── Note.js
│ └── notes-memory.js
│ ├── package.json
│ ├── public
│ └── stylesheets
│ │ └── style.css
│ ├── routes
│ ├── index.js
│ ├── notes.js
│ └── users.js
│ ├── variables.less
│ └── views
│ ├── error.ejs.html
│ ├── footer.ejs
│ ├── headerStuff.ejs
│ ├── index.ejs.html
│ ├── notedestroy.ejs.html
│ ├── noteedit.ejs.html
│ ├── noteview.ejs.html
│ └── pageHeader.ejs.html
├── Chapter 7
└── notes
│ ├── app.js
│ ├── bin
│ └── www
│ ├── bower.json
│ ├── cyborg
│ ├── _bootswatch.scss
│ ├── _variables.scss
│ ├── bootstrap.css
│ ├── bootstrap.min.css
│ ├── bootswatch.less
│ └── variables.less
│ ├── models
│ ├── Note.js
│ ├── notes-fs.js
│ ├── notes-levelup.js
│ ├── notes-memory.js
│ ├── notes-mongodb.js
│ ├── notes-sequelize.js
│ ├── notes-sqlite3.js
│ ├── schema-sqlite3.sql
│ ├── sequelize-mysql.yaml
│ ├── sequelize-sqlite.yaml
│ ├── sqlite3-exec.js
│ └── sqlite3-utils.js
│ ├── notes-count.js
│ ├── package.json
│ ├── routes
│ ├── index.js
│ ├── notes.js
│ └── users.js
│ ├── variables.less
│ └── views
│ ├── error.ejs.html
│ ├── footer.ejs
│ ├── headerStuff.ejs
│ ├── index.ejs.html
│ ├── notedestroy.ejs.html
│ ├── noteedit.ejs.html
│ ├── noteview.ejs.html
│ └── pageHeader.ejs.html
├── Chapter 8
├── notes
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── bower.json
│ ├── cyborg
│ │ ├── _bootswatch.scss
│ │ ├── _variables.scss
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ ├── bootswatch.less
│ │ └── variables.less
│ ├── models
│ │ ├── Note.js
│ │ ├── notes-fs.js
│ │ ├── notes-levelup.js
│ │ ├── notes-memory.js
│ │ ├── notes-mongodb.js
│ │ ├── notes-sequelize.js
│ │ ├── notes-sqlite3.js
│ │ ├── schema-sqlite3.sql
│ │ ├── sequelize-mysql.yaml
│ │ ├── sequelize-sqlite.yaml
│ │ ├── sqlite3-exec.js
│ │ ├── sqlite3-utils.js
│ │ ├── users-rest.js
│ │ └── users-sequelize.js
│ ├── notes-sequelize.sqlite3
│ ├── package.json
│ ├── public
│ │ ├── images
│ │ │ └── twitter-brand-logos
│ │ │ │ ├── TwitterLogo_#55acee.eps
│ │ │ │ ├── TwitterLogo_#55acee.png
│ │ │ │ ├── TwitterLogo_white.eps
│ │ │ │ └── TwitterLogo_white.png
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── index.js
│ │ ├── notes.js
│ │ └── users.js
│ ├── variables.less
│ └── views
│ │ ├── error.ejs.html
│ │ ├── footer.ejs
│ │ ├── headerStuff.ejs
│ │ ├── index.ejs.html
│ │ ├── login.ejs.html
│ │ ├── not-logged-in.ejs
│ │ ├── notedestroy.ejs.html
│ │ ├── noteedit.ejs.html
│ │ ├── noteview.ejs.html
│ │ └── pageHeader.ejs.html
└── users
│ ├── package.json
│ ├── sequelize-mysql.yaml
│ ├── sequelize-sqlite.yaml
│ ├── user-server.js
│ ├── users-add.js
│ ├── users-delete.js
│ ├── users-find.js
│ ├── users-list.js
│ └── users-sequelize.js
├── Chapter 9
├── notes
│ ├── app.js
│ ├── bin
│ │ └── www
│ ├── bower.json
│ ├── brand_guideline_logos_0.zip
│ ├── cyborg
│ │ ├── _bootswatch.scss
│ │ ├── _variables.scss
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ ├── bootswatch.less
│ │ └── variables.less
│ ├── models
│ │ ├── Note.js
│ │ ├── messages-sequelize.js
│ │ ├── notes-events.js
│ │ ├── notes-fs.js
│ │ ├── notes-levelup.js
│ │ ├── notes-memory.js
│ │ ├── notes-mongodb.js
│ │ ├── notes-sequelize.js
│ │ ├── notes-sqlite3.js
│ │ ├── schema-sqlite3.sql
│ │ ├── sequelize-mysql.yaml
│ │ ├── sequelize-sqlite.yaml
│ │ ├── sqlite3-exec.js
│ │ ├── sqlite3-utils.js
│ │ ├── users-rest.js
│ │ └── users-sequelize.js
│ ├── package.json
│ ├── public
│ │ ├── images
│ │ │ └── twitter-brand-logos
│ │ │ │ ├── TwitterLogo_#55acee.eps
│ │ │ │ ├── TwitterLogo_#55acee.png
│ │ │ │ ├── TwitterLogo_white.eps
│ │ │ │ └── TwitterLogo_white.png
│ │ └── stylesheets
│ │ │ └── style.css
│ ├── routes
│ │ ├── index.js
│ │ ├── notes.js
│ │ └── users.js
│ ├── variables.less
│ └── views
│ │ ├── error.ejs.html
│ │ ├── footer.ejs
│ │ ├── headerStuff.ejs
│ │ ├── index.ejs.html
│ │ ├── login.ejs.html
│ │ ├── not-logged-in.ejs
│ │ ├── notedestroy.ejs.html
│ │ ├── noteedit.ejs.html
│ │ ├── noteview.ejs.html
│ │ └── pageHeader.ejs.html
└── users
│ ├── package.json
│ ├── sequelize-mysql.yaml
│ ├── sequelize-sqlite.yaml
│ ├── user-server.js
│ ├── users-add.js
│ ├── users-delete.js
│ ├── users-find.js
│ ├── users-list.js
│ └── users-sequelize.js
├── README.md
└── Software and hardware list.docx
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/Chapter 1/fiboapp.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var url = require('url');
3 |
4 | var fibonacci = function(n) {
5 | if (n === 1 || n === 2)
6 | return 1;
7 | else
8 | return fibonacci(n-1) + fibonacci(n-2);
9 | }
10 |
11 | http.createServer(function (req, res) {
12 | var urlP = url.parse(req.url, true);
13 | var fibo;
14 | res.writeHead(200, {'Content-Type': 'text/plain'});
15 | if (urlP.query['n']) {
16 | fibo = fibonacci(urlP.query['n']);
17 | res.end('Fibonacci '+ urlP.query['n'] +'='+ fibo);
18 | } else {
19 | res.end('USAGE: http://127.0.0.1:8124?n=## where ## is the Fibonacci number desired');
20 | }
21 | }).listen(8124, '127.0.0.1');
22 | console.log('Server running at http://127.0.0.1:8124');
23 |
--------------------------------------------------------------------------------
/Chapter 10/compose/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 |
4 | db-auth:
5 | build: ../db-auth
6 | container_name: db-auth
7 | networks:
8 | - authnet
9 | volumes:
10 | - db-auth-data:/var/lib/mysql
11 | # - ../db-auth/data:/var/lib/mysql
12 |
13 | userauth:
14 | build: ../users
15 | container_name: userauth
16 | networks:
17 | - authnet
18 | - notesauth
19 | expose:
20 | - 3333
21 | depends_on:
22 | - db-auth
23 | restart: on-failure:10
24 |
25 | db-notes:
26 | build: ../db-notes
27 | container_name: db-notes
28 | networks:
29 | - frontnet
30 | volumes:
31 | - db-notes-data:/var/lib/mysql
32 | # - ../db-notes/data:/var/lib/mysql
33 |
34 | notesapp:
35 | build: ../notes
36 | container_name: notesapp
37 | networks:
38 | - frontnet
39 | - notesauth
40 | expose:
41 | - 3000
42 | ports:
43 | - "3000:3000"
44 | depends_on:
45 | - db-notes
46 | - userauth
47 | restart: on-failure:10
48 |
49 | networks:
50 | authnet:
51 | driver: bridge
52 | frontnet:
53 | driver: bridge
54 | notesauth:
55 | driver: bridge
56 |
57 | volumes:
58 | db-auth-data:
59 | db-notes-data:
--------------------------------------------------------------------------------
/Chapter 10/db-auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.7
2 |
3 | ENV MYSQL_RANDOM_ROOT_PASSWORD=yes
4 | ENV MYSQL_DATABASE=userauth
5 | ENV MYSQL_USER=userauth
6 | ENV MYSQL_PASSWORD=userauth
7 |
8 | RUN sed -i "s/^#bind-address.*$/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
9 | RUN sed -i "s/^pid-file/# pid-file/" /etc/mysql/my.cnf
10 | RUN sed -i "s/^socket/# socket/" /etc/mysql/my.cnf
11 |
12 | VOLUME /var/lib/mysql
13 |
14 | EXPOSE 3306
15 | CMD ["mysqld"]
16 |
--------------------------------------------------------------------------------
/Chapter 10/db-notes/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.7
2 |
3 | ENV MYSQL_RANDOM_ROOT_PASSWORD=yes
4 | ENV MYSQL_DATABASE=notes
5 | ENV MYSQL_USER=notes
6 | ENV MYSQL_PASSWORD=notes
7 |
8 | RUN sed -i "s/^#bind-address.*$/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
9 | RUN sed -i "s/^pid-file/# pid-file/" /etc/mysql/my.cnf
10 | RUN sed -i "s/^socket/# socket/" /etc/mysql/my.cnf
11 |
12 | VOLUME /var/lib/mysql
13 |
14 | EXPOSE 3306
15 | CMD ["mysqld"]
16 |
--------------------------------------------------------------------------------
/Chapter 10/notes/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:5.9.0
2 |
3 | ENV DEBUG="notes:*,messages:*"
4 | ENV SEQUELIZE_CONNECT="models/sequelize-docker-mysql.yaml"
5 | ENV NOTES_MODEL="models/notes-sequelize"
6 | ENV USERS_MODEL="models/users-rest"
7 | ENV USER_SERVICE_URL="http://userauth:3333"
8 | ENV PORT="3000"
9 | ENV NOTES_SESSIONS_DIR="/sessions"
10 |
11 | RUN mkdir -p /usr/src/app
12 | COPY . /usr/src/app/
13 | WORKDIR /usr/src/app
14 | RUN apt-get update -y \
15 | && apt-get -y install curl python build-essential git ca-certificates \
16 | && npm install --unsafe-perm
17 |
18 | VOLUME /sessions
19 |
20 | EXPOSE 3000
21 |
22 | CMD npm run docker
23 |
--------------------------------------------------------------------------------
/Chapter 10/notes/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('notes:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 | require('../messages').connect(server);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 | server.listen(port);
30 | server.on('error', onError);
31 | server.on('listening', onListening);
32 |
33 | /**
34 | * Normalize a port into a number, string, or false.
35 | */
36 |
37 | function normalizePort(val) {
38 | var port = parseInt(val, 10);
39 |
40 | if (isNaN(port)) {
41 | // named pipe
42 | return val;
43 | }
44 |
45 | if (port >= 0) {
46 | // port number
47 | return port;
48 | }
49 |
50 | return false;
51 | }
52 |
53 | /**
54 | * Event listener for HTTP server "error" event.
55 | */
56 |
57 | function onError(error) {
58 | if (error.syscall !== 'listen') {
59 | throw error;
60 | }
61 |
62 | var bind = typeof port === 'string'
63 | ? 'Pipe ' + port
64 | : 'Port ' + port;
65 |
66 | // handle specific listen errors with friendly messages
67 | switch (error.code) {
68 | case 'EACCES':
69 | console.error(bind + ' requires elevated privileges');
70 | process.exit(1);
71 | break;
72 | case 'EADDRINUSE':
73 | console.error(bind + ' is already in use');
74 | process.exit(1);
75 | break;
76 | default:
77 | throw error;
78 | }
79 | }
80 |
81 | /**
82 | * Event listener for HTTP server "listening" event.
83 | */
84 |
85 | function onListening() {
86 | var addr = server.address();
87 | var bind = typeof addr === 'string'
88 | ? 'pipe ' + addr
89 | : 'port ' + addr.port;
90 | debug('Listening on ' + bind);
91 | }
92 |
--------------------------------------------------------------------------------
/Chapter 10/notes/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "notes",
3 | "description": "",
4 | "main": "",
5 | "license": "MIT",
6 | "moduleType": [],
7 | "homepage": "",
8 | "ignore": [
9 | "**/.*",
10 | "node_modules",
11 | "bower_components",
12 | "test",
13 | "tests"
14 | ],
15 | "dependencies": {
16 | "bootstrap": "3.3.6"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Chapter 10/notes/brand_guideline_logos_0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/brand_guideline_logos_0.zip
--------------------------------------------------------------------------------
/Chapter 10/notes/ecosystem.json:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | * Application configuration section
4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/
5 | */
6 | apps : [
7 |
8 | // First application
9 | {
10 | name : "API",
11 | script : "app.js",
12 | env: {
13 | COMMON_VARIABLE: "true"
14 | },
15 | env_production : {
16 | NODE_ENV: "production"
17 | }
18 | },
19 |
20 | // Second application
21 | {
22 | name : "WEB",
23 | script : "web.js"
24 | }
25 | ],
26 |
27 | /**
28 | * Deployment section
29 | * http://pm2.keymetrics.io/docs/usage/deployment/
30 | */
31 | deploy : {
32 | production : {
33 | user : "node",
34 | host : "212.83.163.1",
35 | ref : "origin/master",
36 | repo : "git@github.com:repo.git",
37 | path : "/var/www/production",
38 | "post-deploy" : "npm install ; pm2 startOrRestart ecosystem.json --env production"
39 | },
40 | dev : {
41 | user : "node",
42 | host : "212.83.163.1",
43 | ref : "origin/master",
44 | repo : "git@github.com:repo.git",
45 | path : "/var/www/development",
46 | "post-deploy" : "npm install ; pm2 startOrRestart ecosystem.json --env dev",
47 | env : {
48 | NODE_ENV: "dev"
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/Note.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 |
5 | const log = require('debug')('notes:Note');
6 | const error = require('debug')('notes:error');
7 |
8 | module.exports = class Note {
9 | constructor(key, title, body) {
10 | this.key = key;
11 | this.title = title;
12 | this.body = body;
13 | }
14 |
15 | get JSON() {
16 | return JSON.stringify({
17 | key: this.key, title: this.title, body: this.body
18 | });
19 | }
20 |
21 | static fromJSON(json) {
22 | var data = JSON.parse(json);
23 | var note = new Note(data.key, data.title, data.body);
24 | log(json +' => '+ util.inspect(note));
25 | return note;
26 | }
27 | };
--------------------------------------------------------------------------------
/Chapter 10/notes/models/mysql-create-db.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE notes;
2 | CREATE USER 'notes'@'localhost' IDENTIFIED BY 'notes';
3 | GRANT ALL PRIVILEGES ON notes.* TO 'notes'@'localhost' WITH GRANT OPTION;
--------------------------------------------------------------------------------
/Chapter 10/notes/models/notes-events.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EventEmitter = require('events');
4 | const util = require('util');
5 |
6 | const log = require('debug')('notes:router-events');
7 | const error = require('debug')('notes:error');
8 |
9 | class NotesEmitter extends EventEmitter {}
10 |
11 | module.exports = new NotesEmitter();
12 |
13 | module.exports.noteCreated = function(note) {
14 | log('noteCreated '+ util.inspect(note));
15 | module.exports.emit('notecreated', note);
16 | };
17 |
18 | module.exports.noteUpdate = function(note) {
19 | log('noteUpdate '+ util.inspect(note));
20 | module.exports.emit('noteupdate', note);
21 | };
22 |
23 | module.exports.noteDestroy = function(data) {
24 | log('noteDestroy '+ util.inspect(data));
25 | module.exports.emit('notedestroy', data);
26 | };
27 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/notes-levelup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const levelup = require('levelup');
5 |
6 | const log = require('debug')('notes:levelup-model');
7 | const error = require('debug')('notes:error');
8 |
9 | const Note = require('./Note');
10 |
11 | var db; // store the database connection here
12 |
13 | function connectDB() {
14 | return new Promise((resolve, reject) => {
15 | if (db) return resolve(db);
16 | levelup(process.env.LEVELUP_DB_LOCATION || 'notes.levelup', {
17 | createIfMissing: true,
18 | valueEncoding: "json"
19 | },
20 | (err, _db) => {
21 | if (err) return reject(err);
22 | db = _db;
23 | resolve();
24 | });
25 | });
26 | }
27 |
28 | exports.update = exports.create = function(key, title, body) {
29 | return connectDB().then(() => {
30 | var note = new Note(key, title, body);
31 | return new Promise((resolve, reject) => {
32 | db.put(key, note, err => {
33 | if (err) reject(err);
34 | else resolve(note);
35 | });
36 | });
37 | });
38 | };
39 |
40 | exports.read = function(key) {
41 | return connectDB().then(() => {
42 | return new Promise((resolve, reject) => {
43 | db.get(key, (err, note) => {
44 | if (err) reject(err);
45 | else resolve(new Note(note.key, note.title, note.body));
46 | });
47 | });
48 | });
49 | };
50 |
51 | exports.destroy = function(key) {
52 | return connectDB().then(() => {
53 | return new Promise((resolve, reject) => {
54 | db.del(key, err => {
55 | if (err) reject(err);
56 | else resolve();
57 | });
58 | });
59 | });
60 | };
61 |
62 | exports.keylist = function() {
63 | return connectDB().then(() => {
64 | var keyz = [];
65 | return new Promise((resolve, reject) => {
66 | db.createReadStream()
67 | .on('data', data => keyz.push(data.key))
68 | .on('error', err => reject(err))
69 | .on('end', () => resolve(keyz));
70 | });
71 | });
72 | };
73 |
74 | exports.count = function() {
75 | return connectDB().then(() => {
76 | var total = 0;
77 | return new Promise((resolve, reject) => {
78 | db.createReadStream()
79 | .on('data', data => total++)
80 | .on('error', err => reject(err))
81 | .on('end', () => resolve(total));
82 | });
83 | });
84 | };
85 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/notes-memory.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const Note = require('./Note');
5 |
6 | var notes = [];
7 |
8 | exports.update = exports.create = function(key, title, body) {
9 | return new Promise((resolve, reject) => {
10 | notes[key] = new Note(key, title, body);
11 | resolve(notes[key]);
12 | });
13 | };
14 |
15 | exports.read = function(key) {
16 | return new Promise((resolve, reject) => {
17 | if (notes[key]) resolve(notes[key]);
18 | else reject(`Note ${key} does not exist`);
19 | });
20 | };
21 |
22 | exports.destroy = function(key) {
23 | return new Promise((resolve, reject) => {
24 | if (notes[key]) {
25 | delete notes[key];
26 | resolve();
27 | } else reject(`Note ${key} does not exist`);
28 | });
29 | };
30 |
31 | exports.keylist = function() {
32 | return new Promise((resolve, reject) => {
33 | resolve(Object.keys(notes));
34 | });
35 | };
36 |
37 | exports.count = function() {
38 | return new Promise((resolve, reject) => {
39 | resolve(notes.length);
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/schema-sqlite3.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS notes (
2 | notekey VARCHAR(255),
3 | title VARCHAR(255),
4 | author VARCHAR(255),
5 | body TEXT
6 | );
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: db-notes
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sequelize-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sequelize-server-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sequelize-sqlite.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username:
3 | password:
4 | params:
5 | dialect: sqlite
6 | storage: notes-sequelize.sqlite3
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sqlite3-exec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const sqlite3Utils = require('./sqlite3-utils');
5 |
6 | sqlite3Utils.connectDB()
7 | .then(db => {
8 | return new Promise((resolve, reject) => {
9 | fs.readFile(process.argv[2], 'utf8', (err, sql) => {
10 | if (err) reject(err);
11 | else resolve({ db: db, sql: sql });
12 | });
13 | });
14 | })
15 | .then(data => {
16 | return new Promise((resolve, reject) => {
17 | data.db.exec(data.sql, err => {
18 | if (err) reject(err);
19 | else resolve();
20 | });
21 | });
22 | })
23 | .catch(err => { console.error(err); });
--------------------------------------------------------------------------------
/Chapter 10/notes/models/sqlite3-utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const sqlite3 = require('sqlite3');
4 |
5 | const log = require('debug')('notes:sqlite3-utils');
6 | const error = require('debug')('notes:error');
7 |
8 | exports.db = undefined;
9 |
10 | exports.connectDB = function() {
11 | return new Promise((resolve, reject) => {
12 | if (exports.db) return resolve(exports.db);
13 | var dbfile = process.env.SQLITE_FILE || "notes.sqlite3";
14 | exports.db = new sqlite3.Database(dbfile,
15 | sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
16 | err => {
17 | if (err) reject(err);
18 | else {
19 | log('Opened SQLite3 database '+ dbfile);
20 | resolve(exports.db);
21 | }
22 | });
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/Chapter 10/notes/notes-sequelize.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/notes-sequelize.sqlite3
--------------------------------------------------------------------------------
/Chapter 10/notes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "notes",
3 | "version": "0.0.0",
4 | "private": true,
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "DEBUG=notes:*,messages:* SEQUELIZE_CONNECT=models/sequelize-mysql.yaml NOTES_MODEL=models/notes-sequelize USERS_MODEL=models/users-rest USER_SERVICE_URL=http://localhost:3333 PORT=3000 node ./app",
8 | "start-server1": "SEQUELIZE_CONNECT=models/sequelize-sqlite.yaml NOTES_MODEL=models/notes-sequelize USERS_MODEL=models/users-rest USER_SERVICE_URL=http://localhost:3333 PORT=3000 node ./app",
9 | "start-server2": "SEQUELIZE_CONNECT=models/sequelize-sqlite.yaml NOTES_MODEL=models/notes-sequelize USERS_MODEL=models/users-rest USER_SERVICE_URL=http://localhost:3333 PORT=3002 node ./app",
10 | "on-server": "SEQUELIZE_CONNECT=models/sequelize-server-mysql.yaml NOTES_MODEL=models/notes-sequelize USERS_MODEL=models/users-rest USER_SERVICE_URL=http://localhost:3333 PORT=3000 node ./app",
11 | "docker": "node ./app",
12 | "postinstall": "bower --allow-root install",
13 | "bootstrapsetup": "cd bower_components/bootstrap && npm install && npm install grunt-cli ",
14 | "buildbootstrap": "cp variables.less bower_components/bootstrap/less && cd bower_components/bootstrap && grunt"
15 | },
16 | "engines": {
17 | "node": ">=5.x"
18 | },
19 | "dependencies": {
20 | "body-parser": "~1.13.2",
21 | "cookie-parser": "~1.3.5",
22 | "debug": "~2.2.0",
23 | "ejs": "~2.3.3",
24 | "express": "~4.13.1",
25 | "express-session": "^1.13.0",
26 | "file-stream-rotator": "0.0.6",
27 | "fs-extra": "^0.26.5",
28 | "js-yaml": "^3.5.3",
29 | "leveldown": "^1.4.4",
30 | "levelup": "^1.3.1",
31 | "mongodb": "^2.1.7",
32 | "morgan": "~1.6.1",
33 | "mysql": "^2.10.2",
34 | "passport": "^0.3.2",
35 | "passport-local": "^1.0.0",
36 | "passport-twitter": "^1.0.4",
37 | "passport.socketio": "^3.6.1",
38 | "restify": "^4.0.4",
39 | "sequelize": "^3.19.2",
40 | "serve-favicon": "~2.3.0",
41 | "session-file-store": "0.0.24",
42 | "socket.io": "^1.4.5",
43 | "sqlite3": "3.x"
44 | },
45 | "devDependencies": {
46 | "bower": "^1.7.7"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.eps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.eps
--------------------------------------------------------------------------------
/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.png
--------------------------------------------------------------------------------
/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_white.eps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_white.eps
--------------------------------------------------------------------------------
/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 10/notes/public/images/twitter-brand-logos/TwitterLogo_white.png
--------------------------------------------------------------------------------
/Chapter 10/notes/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 5px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
10 | header.page-header {
11 | background: #eeeeee;
12 | padding: 5px;
13 | }
14 |
15 | header.page-header h1 {
16 | margin-top: 5px;
17 | }
18 |
19 | header.page-header .breadcrumb {
20 | margin-bottom: 5px;
21 | }
22 |
23 | header.page-header a.btn-primary {
24 | float: right;
25 | }
--------------------------------------------------------------------------------
/Chapter 10/notes/routes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var path = require('path');
5 | var express = require('express');
6 | var router = express.Router();
7 | var notes = require(process.env.NOTES_MODEL ? path.join('..', process.env.NOTES_MODEL) : '../models/notes-memory');
8 |
9 | const log = require('debug')('notes:router-home');
10 | const error = require('debug')('notes:error');
11 |
12 | /* GET home page. */
13 | router.get('/', function(req, res, next) {
14 | var notelist;
15 | getKeyTitlesList()
16 | .then(notelist => {
17 | var user = req.user ? req.user : undefined;
18 | res.render('index', {
19 | title: 'Notes',
20 | notelist: notelist,
21 | user: user,
22 | breadcrumbs: [
23 | { href: '/', text: 'Home' }
24 | ]
25 | });
26 | })
27 | .catch(err => { error('home page '+ err); next(err); });
28 | });
29 |
30 | module.exports = router;
31 |
32 | var getKeyTitlesList = function() {
33 | log('getKeyTitlesList')
34 | return notes.keylist()
35 | .then(keylist => {
36 | var keyPromises = keylist.map(key => {
37 | return notes.read(key).then(note => {
38 | return { key: note.key, title: note.title };
39 | });
40 | });
41 | return Promise.all(keyPromises);
42 | });
43 | };
44 |
45 | module.exports.socketio = function(io) {
46 | var emitNoteTitles = () => {
47 | getKeyTitlesList().then(notelist => {
48 | io.of('/home').emit('notetitles', { notelist });
49 | });
50 | };
51 | notes.events.on('notecreated', emitNoteTitles);
52 | notes.events.on('noteupdate', emitNoteTitles);
53 | notes.events.on('notedestroy', emitNoteTitles);
54 | };
55 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/error.ejs.html:
--------------------------------------------------------------------------------
1 |
<%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/headerStuff.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= title %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/index.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
19 |
20 | <% include footer %>
21 |
22 |
23 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/login.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
29 |
30 | <% include footer %>
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/not-logged-in.ejs:
--------------------------------------------------------------------------------
1 |
2 |
Not Logged In
3 |
The user is required to be logged in for this action, but is not.
4 | You should not see this message.
5 | It's a bug if this message appears.
6 |
Log in
7 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/notedestroy.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
11 | <% if (user) { %>
12 |
17 | <% } else { %>
18 | <% include not-logged-in %>
19 | <% } %>
20 |
21 |
22 | <% include footer %>
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/noteedit.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
11 | <% if (user) { %>
12 |
37 | <% } else { %>
38 | <% include not-logged-in %>
39 | <% } %>
40 |
41 |
42 | <% include footer %>
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Chapter 10/notes/views/pageHeader.ejs.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Chapter 10/users/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:5.9
2 |
3 | # ENV MYSQL_PORT=3306
4 | # ENV MYSQL_HOST=db-auth
5 | # ENV MYSQL_DATABASE=userauth
6 | # ENV MYSQL_USER=userauth
7 | # ENV MYSQL_PASSWORD=userauth
8 |
9 | ENV DEBUG="users:*"
10 | ENV PORT="3333"
11 | ENV SEQUELIZE_CONNECT="sequelize-docker-mysql.yaml"
12 | ENV REST_LISTEN="0.0.0.0"
13 |
14 | RUN mkdir -p /usr/src/app
15 |
16 | COPY . /usr/src/app/
17 | WORKDIR /usr/src/app
18 | RUN apt-get update -y \
19 | && apt-get -y install curl python build-essential git ca-certificates \
20 | && npm install --unsafe-perm
21 |
22 | EXPOSE 3333
23 |
24 | CMD npm run docker
25 |
--------------------------------------------------------------------------------
/Chapter 10/users/mysql-create-db.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE userauth;
2 | CREATE USER 'userauth'@'localhost' IDENTIFIED BY 'userauth';
3 | GRANT ALL PRIVILEGES ON userauth.* TO 'userauth'@'localhost' WITH GRANT OPTION;
--------------------------------------------------------------------------------
/Chapter 10/users/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "user-auth-server",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "user-server.js",
6 | "scripts": {
7 | "start": "DEBUG=users:* PORT=3333 SEQUELIZE_CONNECT=sequelize-mysql.yaml node user-server",
8 | "on-server": "PORT=3333 SEQUELIZE_CONNECT=sequelize-server-mysql.yaml node ./user-server",
9 | "docker": "node user-server"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "engines": {
14 | "node": ">=5.x"
15 | },
16 | "dependencies": {
17 | "debug": "^2.2.0",
18 | "js-yaml": "^3.5.3",
19 | "mysql": "^2.10.2",
20 | "restify": "^4.0.4",
21 | "sequelize": "^3.19.3",
22 | "sqlite3": "3.x"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Chapter 10/users/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: userauth
2 | username: userauth
3 | password: userauth
4 | params:
5 | host: db-auth
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/users/sequelize-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: users
2 | username: users
3 | password: users
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/users/sequelize-server-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: userauth
2 | username: userauth
3 | password: userauth
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 10/users/sequelize-sqlite.yaml:
--------------------------------------------------------------------------------
1 | dbname: users
2 | username:
3 | password:
4 | params:
5 | dialect: sqlite
6 | storage: users-sequelize.sqlite3
--------------------------------------------------------------------------------
/Chapter 10/users/users-add.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.post('/create-user', {
14 | username: "me", password: "w0rd", provider: "local",
15 | familyName: "Einarrsdottir", givenName: "Ashildr", middleName: "",
16 | emails: [], photos: []
17 | },
18 | (err, req, res, obj) => {
19 | if (err) console.error(err.stack);
20 | else console.log('Created '+ util.inspect(obj));
21 | });
22 |
--------------------------------------------------------------------------------
/Chapter 10/users/users-delete.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.del('/destroy/'+ process.argv[2],
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('Deleted - result= '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 10/users/users-find.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.get('/find/'+ process.argv[2],
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('Found '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 10/users/users-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.get('/list',
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('List '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 11/assert/deleteFile.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | exports.deleteFile = function(fname, callback) {
4 | fs.stat(fname, (err, stats) => {
5 | if (err)
6 | callback(new Error(`the file ${fname does not exist`));
7 | else {
8 | fs.unlink(fname, err => {
9 | if (err)
10 | callback(new Error(`Could not delete ${fname}`));
11 | else callback();
12 | });
13 | }
14 | });
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter 11/assert/test-deleteFile.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const assert = require('assert');
3 | const df = require('./deleteFile');
4 | df.deleteFile("no-such-file", (err) => {
5 | assert.throws(
6 | function() { if (err) throw err; },
7 | function(error) {
8 | if ((error instanceof Error)
9 | && /does not exist/.test(error)) {
10 | return true;
11 | } else return false;
12 | },
13 | "unexpected error"
14 | );
15 | });
--------------------------------------------------------------------------------
/Chapter 11/compose/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 |
4 | db-auth:
5 | build: ../db-auth
6 | container_name: db-auth
7 | networks:
8 | - authnet
9 | volumes:
10 | - db-auth-data:/var/lib/mysql
11 |
12 | userauth:
13 | build: ../users
14 | container_name: userauth
15 | environment:
16 | NODE_ENV: "production"
17 | SEQUELIZE_CONNECT: "sequelize-docker-mysql.yaml"
18 | networks:
19 | - authnet
20 | - notesauth
21 | expose:
22 | - 3333
23 | depends_on:
24 | - db-auth
25 | restart: on-failure:10
26 |
27 | db-notes:
28 | build: ../db-notes
29 | container_name: db-notes
30 | networks:
31 | - frontnet
32 | volumes:
33 | - db-notes-data:/var/lib/mysql
34 |
35 | notesapp:
36 | build: ../notes
37 | container_name: notesapp
38 | environment:
39 | NODE_ENV: "production"
40 | SEQUELIZE_CONNECT: "models/sequelize-docker-mysql.yaml"
41 | USER_SERVICE_URL: "http://userauth:3333"
42 | networks:
43 | - frontnet
44 | - notesauth
45 | expose:
46 | - 3000
47 | ports:
48 | - "3000:3000"
49 | depends_on:
50 | - db-notes
51 | - userauth
52 | restart: on-failure:10
53 |
54 | networks:
55 | authnet:
56 | driver: bridge
57 | frontnet:
58 | driver: bridge
59 | notesauth:
60 | driver: bridge
61 |
62 | volumes:
63 | db-auth-data:
64 | db-notes-data:
--------------------------------------------------------------------------------
/Chapter 11/db-auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.7
2 |
3 | ENV MYSQL_RANDOM_ROOT_PASSWORD=yes
4 | ENV MYSQL_DATABASE=userauth
5 | ENV MYSQL_USER=userauth
6 | ENV MYSQL_PASSWORD=userauth
7 |
8 | RUN sed -i "s/^#bind-address.*$/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
9 | RUN sed -i "s/^pid-file/# pid-file/" /etc/mysql/my.cnf
10 | RUN sed -i "s/^socket/# socket/" /etc/mysql/my.cnf
11 |
12 | VOLUME /var/lib/mysql
13 |
14 | EXPOSE 3306
15 | CMD ["mysqld"]
16 |
--------------------------------------------------------------------------------
/Chapter 11/db-notes/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mysql:5.7
2 |
3 | ENV MYSQL_RANDOM_ROOT_PASSWORD=yes
4 | ENV MYSQL_DATABASE=notes
5 | ENV MYSQL_USER=notes
6 | ENV MYSQL_PASSWORD=notes
7 |
8 | RUN sed -i "s/^#bind-address.*$/bind-address = 0.0.0.0/" /etc/mysql/my.cnf
9 | RUN sed -i "s/^pid-file/# pid-file/" /etc/mysql/my.cnf
10 | RUN sed -i "s/^socket/# socket/" /etc/mysql/my.cnf
11 |
12 | VOLUME /var/lib/mysql
13 |
14 | EXPOSE 3306
15 | CMD ["mysqld"]
16 |
--------------------------------------------------------------------------------
/Chapter 11/notes/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:5.9.0
2 |
3 | # ENV DEBUG="notes:*,messages:*"
4 | # ENV SEQUELIZE_CONNECT="models/sequelize-docker-mysql.yaml"
5 | ENV NOTES_MODEL="models/notes-sequelize"
6 | ENV USERS_MODEL="models/users-rest"
7 | # ENV USER_SERVICE_URL="http://userauth:3333"
8 | ENV PORT="3000"
9 | ENV NOTES_SESSIONS_DIR="/sessions"
10 | # ENV NODE_ENV="production"
11 |
12 | RUN mkdir -p /usr/src/app
13 | COPY . /usr/src/app/
14 | WORKDIR /usr/src/app
15 | RUN apt-get update -y \
16 | && apt-get -y install curl python build-essential git ca-certificates \
17 | && apt-get -y install sqlite3 \
18 | && rm -rf node_modules \
19 | && npm install --unsafe-perm
20 |
21 | VOLUME /sessions
22 |
23 | EXPOSE 3000
24 |
25 | CMD npm run docker
26 |
--------------------------------------------------------------------------------
/Chapter 11/notes/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('notes:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 | require('../messages').connect(server);
24 |
25 | /**
26 | * Listen on provided port, on all network interfaces.
27 | */
28 |
29 | server.listen(port);
30 | server.on('error', onError);
31 | server.on('listening', onListening);
32 |
33 | /**
34 | * Normalize a port into a number, string, or false.
35 | */
36 |
37 | function normalizePort(val) {
38 | var port = parseInt(val, 10);
39 |
40 | if (isNaN(port)) {
41 | // named pipe
42 | return val;
43 | }
44 |
45 | if (port >= 0) {
46 | // port number
47 | return port;
48 | }
49 |
50 | return false;
51 | }
52 |
53 | /**
54 | * Event listener for HTTP server "error" event.
55 | */
56 |
57 | function onError(error) {
58 | if (error.syscall !== 'listen') {
59 | throw error;
60 | }
61 |
62 | var bind = typeof port === 'string'
63 | ? 'Pipe ' + port
64 | : 'Port ' + port;
65 |
66 | // handle specific listen errors with friendly messages
67 | switch (error.code) {
68 | case 'EACCES':
69 | console.error(bind + ' requires elevated privileges');
70 | process.exit(1);
71 | break;
72 | case 'EADDRINUSE':
73 | console.error(bind + ' is already in use');
74 | process.exit(1);
75 | break;
76 | default:
77 | throw error;
78 | }
79 | }
80 |
81 | /**
82 | * Event listener for HTTP server "listening" event.
83 | */
84 |
85 | function onListening() {
86 | var addr = server.address();
87 | var bind = typeof addr === 'string'
88 | ? 'pipe ' + addr
89 | : 'port ' + addr.port;
90 | debug('Listening on ' + bind);
91 | }
92 |
--------------------------------------------------------------------------------
/Chapter 11/notes/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "notes",
3 | "description": "",
4 | "main": "",
5 | "license": "MIT",
6 | "moduleType": [],
7 | "homepage": "",
8 | "ignore": [
9 | "**/.*",
10 | "node_modules",
11 | "bower_components",
12 | "test",
13 | "tests"
14 | ],
15 | "dependencies": {
16 | "bootstrap": "3.3.6"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Chapter 11/notes/brand_guideline_logos_0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/brand_guideline_logos_0.zip
--------------------------------------------------------------------------------
/Chapter 11/notes/chap11.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/chap11.sqlite3
--------------------------------------------------------------------------------
/Chapter 11/notes/ecosystem.json:
--------------------------------------------------------------------------------
1 | {
2 | /**
3 | * Application configuration section
4 | * http://pm2.keymetrics.io/docs/usage/application-declaration/
5 | */
6 | apps : [
7 |
8 | // First application
9 | {
10 | name : "API",
11 | script : "app.js",
12 | env: {
13 | COMMON_VARIABLE: "true"
14 | },
15 | env_production : {
16 | NODE_ENV: "production"
17 | }
18 | },
19 |
20 | // Second application
21 | {
22 | name : "WEB",
23 | script : "web.js"
24 | }
25 | ],
26 |
27 | /**
28 | * Deployment section
29 | * http://pm2.keymetrics.io/docs/usage/deployment/
30 | */
31 | deploy : {
32 | production : {
33 | user : "node",
34 | host : "212.83.163.1",
35 | ref : "origin/master",
36 | repo : "git@github.com:repo.git",
37 | path : "/var/www/production",
38 | "post-deploy" : "npm install ; pm2 startOrRestart ecosystem.json --env production"
39 | },
40 | dev : {
41 | user : "node",
42 | host : "212.83.163.1",
43 | ref : "origin/master",
44 | repo : "git@github.com:repo.git",
45 | path : "/var/www/development",
46 | "post-deploy" : "npm install ; pm2 startOrRestart ecosystem.json --env dev",
47 | env : {
48 | NODE_ENV: "dev"
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/Note.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 |
5 | const log = require('debug')('notes:Note');
6 | const error = require('debug')('notes:error');
7 |
8 | module.exports = class Note {
9 | constructor(key, title, body) {
10 | this.key = key;
11 | this.title = title;
12 | this.body = body;
13 | }
14 |
15 | get JSON() {
16 | return JSON.stringify({
17 | key: this.key, title: this.title, body: this.body
18 | });
19 | }
20 |
21 | static fromJSON(json) {
22 | var data = JSON.parse(json);
23 | var note = new Note(data.key, data.title, data.body);
24 | log(json +' => '+ util.inspect(note));
25 | return note;
26 | }
27 | };
--------------------------------------------------------------------------------
/Chapter 11/notes/models/mysql-create-db.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE notes;
2 | CREATE USER 'notes'@'localhost' IDENTIFIED BY 'notes';
3 | GRANT ALL PRIVILEGES ON notes.* TO 'notes'@'localhost' WITH GRANT OPTION;
--------------------------------------------------------------------------------
/Chapter 11/notes/models/notes-events.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const EventEmitter = require('events');
4 | const util = require('util');
5 |
6 | const log = require('debug')('notes:router-events');
7 | const error = require('debug')('notes:error');
8 |
9 | class NotesEmitter extends EventEmitter {}
10 |
11 | module.exports = new NotesEmitter();
12 |
13 | module.exports.noteCreated = function(note) {
14 | log('noteCreated '+ util.inspect(note));
15 | module.exports.emit('notecreated', note);
16 | };
17 |
18 | module.exports.noteUpdate = function(note) {
19 | log('noteUpdate '+ util.inspect(note));
20 | module.exports.emit('noteupdate', note);
21 | };
22 |
23 | module.exports.noteDestroy = function(data) {
24 | log('noteDestroy '+ util.inspect(data));
25 | module.exports.emit('notedestroy', data);
26 | };
27 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/notes-levelup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const levelup = require('levelup');
5 |
6 | const log = require('debug')('notes:levelup-model');
7 | const error = require('debug')('notes:error');
8 |
9 | const Note = require('./Note');
10 |
11 | var db; // store the database connection here
12 |
13 | function connectDB() {
14 | return new Promise((resolve, reject) => {
15 | if (db) return resolve(db);
16 | levelup(process.env.LEVELUP_DB_LOCATION || 'notes.levelup', {
17 | createIfMissing: true,
18 | valueEncoding: "json"
19 | },
20 | (err, _db) => {
21 | if (err) return reject(err);
22 | db = _db;
23 | resolve();
24 | });
25 | });
26 | }
27 |
28 | exports.update = exports.create = function(key, title, body) {
29 | return connectDB().then(() => {
30 | var note = new Note(key, title, body);
31 | return new Promise((resolve, reject) => {
32 | db.put(key, note, err => {
33 | if (err) reject(err);
34 | else resolve(note);
35 | });
36 | });
37 | });
38 | };
39 |
40 | exports.read = function(key) {
41 | return connectDB().then(() => {
42 | return new Promise((resolve, reject) => {
43 | db.get(key, (err, note) => {
44 | if (err) reject(err);
45 | else resolve(new Note(note.key, note.title, note.body));
46 | });
47 | });
48 | });
49 | };
50 |
51 | exports.destroy = function(key) {
52 | return connectDB().then(() => {
53 | return new Promise((resolve, reject) => {
54 | db.del(key, err => {
55 | if (err) reject(err);
56 | else resolve();
57 | });
58 | });
59 | });
60 | };
61 |
62 | exports.keylist = function() {
63 | return connectDB().then(() => {
64 | var keyz = [];
65 | return new Promise((resolve, reject) => {
66 | db.createReadStream()
67 | .on('data', data => keyz.push(data.key))
68 | .on('error', err => reject(err))
69 | .on('end', () => resolve(keyz));
70 | });
71 | });
72 | };
73 |
74 | exports.count = function() {
75 | return connectDB().then(() => {
76 | var total = 0;
77 | return new Promise((resolve, reject) => {
78 | db.createReadStream()
79 | .on('data', data => total++)
80 | .on('error', err => reject(err))
81 | .on('end', () => resolve(total));
82 | });
83 | });
84 | };
85 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/notes-memory.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const Note = require('./Note');
5 |
6 | var notes = [];
7 |
8 | exports.update = exports.create = function(key, title, body) {
9 | return new Promise((resolve, reject) => {
10 | notes[key] = new Note(key, title, body);
11 | resolve(notes[key]);
12 | });
13 | };
14 |
15 | exports.read = function(key) {
16 | return new Promise((resolve, reject) => {
17 | if (notes[key]) resolve(notes[key]);
18 | else reject(`Note ${key} does not exist`);
19 | });
20 | };
21 |
22 | exports.destroy = function(key) {
23 | return new Promise((resolve, reject) => {
24 | if (notes[key]) {
25 | delete notes[key];
26 | resolve();
27 | } else reject(`Note ${key} does not exist`);
28 | });
29 | };
30 |
31 | exports.keylist = function() {
32 | return new Promise((resolve, reject) => {
33 | resolve(Object.keys(notes));
34 | });
35 | };
36 |
37 | exports.count = function() {
38 | return new Promise((resolve, reject) => {
39 | resolve(notes.length);
40 | });
41 | };
42 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/schema-sqlite3.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS notes (
2 | notekey VARCHAR(255),
3 | title VARCHAR(255),
4 | author VARCHAR(255),
5 | body TEXT
6 | );
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: db-notes
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sequelize-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sequelize-server-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sequelize-sqlite.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username:
3 | password:
4 | params:
5 | dialect: sqlite
6 | storage: notes-sequelize.sqlite3
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sqlite3-exec.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const sqlite3Utils = require('./sqlite3-utils');
5 |
6 | sqlite3Utils.connectDB()
7 | .then(db => {
8 | return new Promise((resolve, reject) => {
9 | fs.readFile(process.argv[2], 'utf8', (err, sql) => {
10 | if (err) reject(err);
11 | else resolve({ db: db, sql: sql });
12 | });
13 | });
14 | })
15 | .then(data => {
16 | return new Promise((resolve, reject) => {
17 | data.db.exec(data.sql, err => {
18 | if (err) reject(err);
19 | else resolve();
20 | });
21 | });
22 | })
23 | .catch(err => { console.error(err); });
--------------------------------------------------------------------------------
/Chapter 11/notes/models/sqlite3-utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const sqlite3 = require('sqlite3');
4 |
5 | const log = require('debug')('notes:sqlite3-utils');
6 | const error = require('debug')('notes:error');
7 |
8 | exports.db = undefined;
9 |
10 | exports.connectDB = function() {
11 | return new Promise((resolve, reject) => {
12 | if (exports.db) return resolve(exports.db);
13 | var dbfile = process.env.SQLITE_FILE || "notes.sqlite3";
14 | exports.db = new sqlite3.Database(dbfile,
15 | sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE,
16 | err => {
17 | if (err) reject(err);
18 | else {
19 | log('Opened SQLite3 database '+ dbfile);
20 | resolve(exports.db);
21 | }
22 | });
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.eps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.eps
--------------------------------------------------------------------------------
/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_#55acee.png
--------------------------------------------------------------------------------
/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_white.eps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_white.eps
--------------------------------------------------------------------------------
/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/NodeJS-Web-Development/5c11664963471b3036eb6c47583621f70239e5ea/Chapter 11/notes/public/images/twitter-brand-logos/TwitterLogo_white.png
--------------------------------------------------------------------------------
/Chapter 11/notes/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 5px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
10 | header.page-header {
11 | background: #eeeeee;
12 | padding: 5px;
13 | }
14 |
15 | header.page-header h1 {
16 | margin-top: 5px;
17 | }
18 |
19 | header.page-header .breadcrumb {
20 | margin-bottom: 5px;
21 | }
22 |
23 | header.page-header a.btn-primary {
24 | float: right;
25 | }
--------------------------------------------------------------------------------
/Chapter 11/notes/routes/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util');
4 | var path = require('path');
5 | var express = require('express');
6 | var router = express.Router();
7 | var notes = require(process.env.NOTES_MODEL ? path.join('..', process.env.NOTES_MODEL) : '../models/notes-memory');
8 |
9 | const log = require('debug')('notes:router-home');
10 | const error = require('debug')('notes:error');
11 |
12 | /* GET home page. */
13 | router.get('/', function(req, res, next) {
14 | var notelist;
15 | getKeyTitlesList()
16 | .then(notelist => {
17 | var user = req.user ? req.user : undefined;
18 | res.render('index', {
19 | title: 'Notes',
20 | notelist: notelist,
21 | user: user,
22 | breadcrumbs: [{ href: '/', text: 'Home' }]
23 | });
24 | })
25 | .catch(err => { console.error('home page '+ err); next(err); });
26 | });
27 |
28 | module.exports = router;
29 |
30 | var getKeyTitlesList = function() {
31 | log('getKeyTitlesList')
32 | return notes.keylist()
33 | .then(keylist => {
34 | var keyPromises = keylist.map(key => {
35 | return notes.read(key).then(note => {
36 | return { key: note.key, title: note.title };
37 | });
38 | });
39 | return Promise.all(keyPromises);
40 | });
41 | };
42 |
43 | module.exports.socketio = function(io) {
44 | var emitNoteTitles = () => {
45 | getKeyTitlesList().then(notelist => {
46 | io.of('/home').emit('notetitles', { notelist });
47 | });
48 | };
49 | notes.events.on('notecreated', emitNoteTitles);
50 | notes.events.on('noteupdate', emitNoteTitles);
51 | notes.events.on('notedestroy', emitNoteTitles);
52 | };
53 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/error.ejs.html:
--------------------------------------------------------------------------------
1 | <%= message %>
2 | <%= error.status %>
3 | <%= error.stack %>
4 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/headerStuff.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | <%= title %>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/index.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
19 |
20 | <% include footer %>
21 |
22 |
23 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/login.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
29 |
30 | <% include footer %>
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/not-logged-in.ejs:
--------------------------------------------------------------------------------
1 |
2 |
Not Logged In
3 |
The user is required to be logged in for this action, but is not.
4 | You should not see this message.
5 | It's a bug if this message appears.
6 |
Log in
7 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/notedestroy.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
11 | <% if (user) { %>
12 |
17 | <% } else { %>
18 | <% include not-logged-in %>
19 | <% } %>
20 |
21 |
22 | <% include footer %>
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/noteedit.ejs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <% include headerStuff %>
5 |
6 |
7 |
8 | <% include pageHeader %>
9 |
10 |
41 |
42 | <% include footer %>
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Chapter 11/notes/views/pageHeader.ejs.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 |
3 | services:
4 |
5 | db-auth-test:
6 | build: ../db-auth
7 | container_name: db-auth-test
8 | networks:
9 | - authnet-test
10 |
11 | userauth-test:
12 | build: ../users
13 | container_name: userauth-test
14 | environment:
15 | DEBUG: ""
16 | NODE_ENV: "test"
17 | SEQUELIZE_CONNECT: "userauth-test/sequelize-docker-mysql.yaml"
18 | HOST_USERS_TEST: "localhost"
19 | networks:
20 | - authnet-test
21 | - notesauth-test
22 | depends_on:
23 | - db-auth-test
24 | volumes:
25 | - ./reports-userauth:/reports
26 | - ./userauth:/usr/src/app/userauth-test
27 |
28 | db-notes-test:
29 | build: ../db-notes
30 | container_name: db-notes-test
31 | networks:
32 | - frontnet-test
33 |
34 | notesapp-test:
35 | build: ../notes
36 | container_name: notesapp-test
37 | environment:
38 | DEBUG: "notes:*,messages:*"
39 | NODE_ENV: "test"
40 | SEQUELIZE_CONNECT: "notesmodel-test/sequelize-docker-mysql.yaml"
41 | USER_SERVICE_URL: "http://userauth-test:3333"
42 | networks:
43 | - frontnet-test
44 | - notesauth-test
45 | expose:
46 | - 3000
47 | ports:
48 | - "3000:3000"
49 | depends_on:
50 | - db-notes-test
51 | - userauth-test
52 | volumes:
53 | - ./reports-notes:/reports
54 | - ./notesui:/usr/src/app/notesui-test
55 | - ./notesmodel:/usr/src/app/notesmodel-test
56 |
57 | networks:
58 | authnet-test:
59 | driver: bridge
60 | frontnet-test:
61 | driver: bridge
62 | notesauth-test:
63 | driver: bridge
64 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/notesmodel/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: db-notes-test
6 | port: 3306
7 | dialect: mysql
8 | logging: false
9 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/notesmodel/sequelize-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: notes
2 | username: notes
3 | password: notes
4 | params:
5 | host: db-notes
6 | port: 3306
7 | dialect: mysql
8 | logging: false
9 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/notesmodel/sequelize-sqlite.yaml:
--------------------------------------------------------------------------------
1 | dbname: notestest
2 | username:
3 | password:
4 | params:
5 | dialect: sqlite
6 | storage: notestest-sequelize.sqlite3
7 | logging: false
--------------------------------------------------------------------------------
/Chapter 11/test-compose/notesui/uitest.js:
--------------------------------------------------------------------------------
1 |
2 | var notes = 'http://localhost:3000';
3 |
4 | casper.test.begin('Can login to Notes application', function suite(test) {
5 | casper.start(notes, function() {
6 | test.assertTitle("Notes");
7 | test.assertExists('a#btnloginlocal', "Login button is found");
8 | this.click("a#btnloginlocal");
9 | });
10 |
11 | casper.then(function() {
12 | test.assertHttpStatus(200);
13 | test.assertUrlMatch(/users\/login/, 'should be on /users/login');
14 | this.fill('form', {
15 | username: "me",
16 | password: "w0rd"
17 | });
18 | this.click('button[type="submit"]');
19 | });
20 |
21 | casper.waitForSelector('#btnlogout', function() {
22 | // this.echo('Logged in?');
23 | test.assertHttpStatus(200);
24 | test.assertTitle("Notes");
25 | test.assertExists('a#btnlogout', "logout button is found");
26 | test.assertExists('a#btnaddnote', "Add Note button is found");
27 | this.click("#btnaddnote");
28 | });
29 |
30 | casper.waitForUrl(/notes\/add/, function() {
31 | test.assertHttpStatus(200);
32 | test.assertTitle("Add a Note");
33 | test.assertField("docreate", "create");
34 | this.fill('form', {
35 | notekey: 'testkey',
36 | title: 'Test Note Title',
37 | body: 'Test Note Body with various textual delights'
38 | });
39 | this.click('button[type="submit"]');
40 | });
41 |
42 | casper.waitForUrl(/notes\/view/, function() {
43 | test.assertHttpStatus(200);
44 | test.assertTitle("Test Note Title");
45 | test.assertSelectorHasText("p#notebody", 'Test Note Body with various textual delights');
46 | this.click('#btndestroynote');
47 | });
48 |
49 | casper.waitForUrl(/notes\/destroy/, function() {
50 | test.assertHttpStatus(200);
51 | test.assertTitle("Test Note Title");
52 | test.assertField("notekey", "testkey");
53 | this.click('input[type="submit"]');
54 | });
55 |
56 | casper.waitForUrl(notes, function() {
57 | test.assertHttpStatus(200);
58 | test.assertTitle("Notes");
59 | test.assertExists('a#btnlogout', "logout button is found");
60 | this.click("#btnlogout");
61 | });
62 |
63 | casper.waitForUrl(notes, function() {
64 | test.assertHttpStatus(200);
65 | test.assertTitle("Notes");
66 | test.assertExists('a#btnloginlocal', "Login button is found");
67 | });
68 |
69 | casper.run(function() {
70 | test.done();
71 | });
72 | });
--------------------------------------------------------------------------------
/Chapter 11/test-compose/reports-notes/notesui.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/reports-userauth/userauth.json:
--------------------------------------------------------------------------------
1 | {
2 | "stats": {
3 | "suites": 4,
4 | "tests": 4,
5 | "passes": 4,
6 | "pending": 0,
7 | "failures": 0,
8 | "start": "2016-05-01T01:01:35.021Z",
9 | "end": "2016-05-01T01:01:35.363Z",
10 | "duration": 342
11 | },
12 | "tests": [
13 | {
14 | "title": "list created users",
15 | "fullTitle": "Users Test List user list created users",
16 | "duration": 19,
17 | "currentRetry": 0,
18 | "err": {}
19 | },
20 | {
21 | "title": "find created users",
22 | "fullTitle": "Users Test find user find created users",
23 | "duration": 14,
24 | "currentRetry": 0,
25 | "err": {}
26 | },
27 | {
28 | "title": "fail to find non-existent users",
29 | "fullTitle": "Users Test find user fail to find non-existent users",
30 | "duration": 13,
31 | "currentRetry": 0,
32 | "err": {}
33 | },
34 | {
35 | "title": "delete nonexistent users",
36 | "fullTitle": "Users Test delete user delete nonexistent users",
37 | "duration": 13,
38 | "currentRetry": 0,
39 | "err": {}
40 | }
41 | ],
42 | "pending": [],
43 | "failures": [],
44 | "passes": [
45 | {
46 | "title": "list created users",
47 | "fullTitle": "Users Test List user list created users",
48 | "duration": 19,
49 | "currentRetry": 0,
50 | "err": {}
51 | },
52 | {
53 | "title": "find created users",
54 | "fullTitle": "Users Test find user find created users",
55 | "duration": 14,
56 | "currentRetry": 0,
57 | "err": {}
58 | },
59 | {
60 | "title": "fail to find non-existent users",
61 | "fullTitle": "Users Test find user fail to find non-existent users",
62 | "duration": 13,
63 | "currentRetry": 0,
64 | "err": {}
65 | },
66 | {
67 | "title": "delete nonexistent users",
68 | "fullTitle": "Users Test delete user delete nonexistent users",
69 | "duration": 13,
70 | "currentRetry": 0,
71 | "err": {}
72 | }
73 | ]
74 | }
--------------------------------------------------------------------------------
/Chapter 11/test-compose/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -x
4 |
5 | docker-compose stop
6 |
7 | docker-compose up --build --force-recreate -d
8 |
9 | docker ps
10 | docker network ls
11 |
12 | docker exec -it notesapp-test npm install -g phantomjs-prebuilt@2.1.7 casperjs@1.1.0-beta5
13 | docker exec -it notesapp-test npm install mocha@2.4.5 chai@3.5.0
14 |
15 | docker exec -it notesapp-test npm run test-docker-notes-memory
16 | docker exec -it notesapp-test npm run test-docker-notes-fs
17 | docker exec -it notesapp-test npm run test-docker-notes-levelup
18 | docker exec -it notesapp-test npm run test-docker-notes-sqlite3
19 | docker exec -it notesapp-test npm run test-docker-notes-sequelize-sqlite
20 | docker exec -it notesapp-test npm run test-docker-notes-sequelize-mysql
21 |
22 | docker exec -it userauth-test npm run setupuser
23 | docker exec -it notesapp-test npm run test-docker-ui
24 |
25 | docker exec -it userauth-test npm install mocha@2.4.5 chai@3.5.0
26 |
27 | docker exec -it userauth-test npm run test-docker
28 |
29 | docker-compose stop
30 |
--------------------------------------------------------------------------------
/Chapter 11/test-compose/userauth/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: userauth
2 | username: userauth
3 | password: userauth
4 | params:
5 | host: db-auth-test
6 | port: 3306
7 | dialect: mysql
8 | logging: false
9 |
--------------------------------------------------------------------------------
/Chapter 11/users/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:5.9
2 |
3 | # ENV DEBUG="users:*"
4 | ENV PORT="3333"
5 | # ENV SEQUELIZE_CONNECT="sequelize-docker-mysql.yaml"
6 | ENV REST_LISTEN="0.0.0.0"
7 | # ENV HOST_USERS_TEST="localhost"
8 | # ENV NODE_ENV="production"
9 |
10 | RUN mkdir -p /usr/src/app
11 |
12 | COPY . /usr/src/app/
13 | WORKDIR /usr/src/app
14 | RUN apt-get update -y \
15 | && apt-get -y install curl python build-essential git ca-certificates \
16 | && rm -rf node_modules \
17 | && npm install --unsafe-perm
18 |
19 | EXPOSE 3333
20 |
21 | CMD npm run docker
22 |
--------------------------------------------------------------------------------
/Chapter 11/users/mysql-create-db.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE userauth;
2 | CREATE USER 'userauth'@'localhost' IDENTIFIED BY 'userauth';
3 | GRANT ALL PRIVILEGES ON userauth.* TO 'userauth'@'localhost' WITH GRANT OPTION;
--------------------------------------------------------------------------------
/Chapter 11/users/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "user-auth-server",
3 | "version": "0.0.1",
4 | "description": "",
5 | "main": "user-server.js",
6 | "scripts": {
7 | "start": "DEBUG=users:* PORT=3333 SEQUELIZE_CONNECT=sequelize-mysql.yaml node user-server",
8 | "on-server": "PORT=3333 SEQUELIZE_CONNECT=sequelize-server-mysql.yaml node ./user-server",
9 | "docker": "node user-server",
10 | "setupuser": "PORT=3333 node users-add",
11 | "test": "mocha",
12 | "test-docker": "mocha -R json userauth-test/test.js >/reports/userauth.json"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "engines": {
17 | "node": ">=5.x"
18 | },
19 | "dependencies": {
20 | "debug": "^2.2.0",
21 | "js-yaml": "^3.5.3",
22 | "mysql": "^2.10.2",
23 | "restify": "^4.0.4",
24 | "sequelize": "^3.19.3",
25 | "sqlite3": "3.x"
26 | },
27 | "devDependencies": {
28 | "mocha": "2.x",
29 | "chai": "3.x"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter 11/users/sequelize-docker-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: userauth
2 | username: userauth
3 | password: userauth
4 | params:
5 | host: db-auth
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/users/sequelize-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: users
2 | username: users
3 | password: users
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/users/sequelize-server-mysql.yaml:
--------------------------------------------------------------------------------
1 | dbname: userauth
2 | username: userauth
3 | password: userauth
4 | params:
5 | host: localhost
6 | port: 3306
7 | dialect: mysql
8 |
--------------------------------------------------------------------------------
/Chapter 11/users/sequelize-sqlite.yaml:
--------------------------------------------------------------------------------
1 | dbname: users
2 | username:
3 | password:
4 | params:
5 | dialect: sqlite
6 | storage: users-sequelize.sqlite3
--------------------------------------------------------------------------------
/Chapter 11/users/users-add.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.post('/find-or-create', {
14 | username: "me", password: "w0rd", provider: "local",
15 | familyName: "Einarrsdottir", givenName: "Ashildr", middleName: "",
16 | emails: [], photos: []
17 | },
18 | (err, req, res, obj) => {
19 | if (err) console.error(err.stack);
20 | else console.log('Created '+ util.inspect(obj));
21 | });
22 |
--------------------------------------------------------------------------------
/Chapter 11/users/users-delete.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.del('/destroy/'+ process.argv[2],
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('Deleted - result= '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 11/users/users-find.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.get('/find/'+ process.argv[2],
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('Found '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 11/users/users-list.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const util = require('util');
4 | const restify = require('restify');
5 |
6 | var client = restify.createJsonClient({
7 | url: 'http://localhost:'+process.env.PORT,
8 | version: '*'
9 | });
10 |
11 | client.basicAuth('them', 'D4ED43C0-8BD6-4FE2-B358-7C0E230D11EF');
12 |
13 | client.get('/list',
14 | (err, req, res, obj) => {
15 | if (err) console.error(err.stack);
16 | else console.log('List '+ util.inspect(obj));
17 | });
18 |
--------------------------------------------------------------------------------
/Chapter 2/app.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | http.createServer(function (req, res) {
3 | res.writeHead(200, {'Content-Type': 'text/plain'});
4 | res.end('Hello, World!\n');
5 | }).listen(8124, '127.0.0.1');
6 | console.log('Server running at http://127.0.0.1:8124');
--------------------------------------------------------------------------------
/Chapter 2/ls.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var files = fs.readdirSync('.');
3 | for (fn in files) {
4 | console.log(files[fn]);
5 | }
--------------------------------------------------------------------------------
/Chapter 2/ls2.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var dir = '.';
3 | if (process.argv[2]) dir = process.argv[2];
4 | var files = fs.readdirSync(dir);
5 | for (fn in files) {
6 | console.log(files[fn]);
7 | }
--------------------------------------------------------------------------------
/Chapter 3/module1.js:
--------------------------------------------------------------------------------
1 | var A = "value A";
2 | var B = "value B";
3 | exports.values = function() {
4 | return { A: A, B: B };
5 | }
6 |
--------------------------------------------------------------------------------
/Chapter 3/module2.js:
--------------------------------------------------------------------------------
1 | var util = require('util');
2 | var A = "a different value A";
3 | var B = "a different value B";
4 | var m1 = require('./module1');
5 | util.log('A='+A+' B='+B+' values='+util.inspect(m1.values()));
6 |
--------------------------------------------------------------------------------
/Chapter 3/simple.js:
--------------------------------------------------------------------------------
1 |
2 | var count = 0;
3 | exports.next = function() { return count++; }
4 | exports.hello = function() {
5 | return "Hello, world!";
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter 4/app1/app1.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var server = http.createServer();
3 | server.on('request', (req, res) => {
4 | res.writeHead(200, {'Content-Type': 'text/plain'});
5 | res.end('Hello, World!\n');
6 | });
7 | server.listen(8124, '127.0.0.1');
8 | console.log('Server running at http://127.0.0.1:8124');
--------------------------------------------------------------------------------
/Chapter 4/events/httpsniffer.js:
--------------------------------------------------------------------------------
1 |
2 | var util = require('util');
3 | var url = require('url');
4 |
5 | exports.sniffOn = function(server) {
6 | // Emitted each time there is request.
7 | // request is an instance of http.ServerRequest
8 | // response is an instance of http.ServerResponse
9 | server.on('request', (req, res) => {
10 | util.log('request');
11 | util.log(reqToString(req));
12 | });
13 |
14 | // Called when a new TCP stream is established.
15 | // stream is an object of type net.Stream.
16 | // Usually users will not want to access this event.
17 | // The stream can also be accessed at request.connection.
18 | // var e_connection = function(stream) {
19 | // };
20 |
21 | // Emitted when the server closes.
22 | server.on('close', errno => { util.log('close errno='+ errno); });
23 |
24 | // Emitted each time a request with an http Expect: 100-continue is received.
25 | // If this event isn't listened for,
26 | // the server will automatically respond with a 100 Continue as appropriate.
27 | // Handling this event involves calling response.writeContinue
28 | // if the client should continue to send the request body,
29 | // or generating an appropriate HTTP response (e.g., 400 Bad Request)
30 | // if the client should not continue to send the request body.
31 | server.on('checkContinue', (req, res) => {
32 | util.log('checkContinue');
33 | util.log(reqToString(req));
34 | res.writeContinue();
35 | });
36 |
37 | // Emitted each time a client requests a http upgrade.
38 | // If this event isn't listened for,
39 | // then clients requesting an upgrade will have their connections closed.
40 | server.on('upgrade', (req, socket, head) => {
41 | util.log('upgrade');
42 | util.log(reqToString(req));
43 | });
44 |
45 | // If a client connection emits an 'error' event - it will forwarded here.
46 | server.on('clientError', () => { util.log('clientError'); });
47 |
48 | // server.on('connection', e_connection);
49 | };
50 |
51 | var reqToString = exports.reqToString = function(req) {
52 | var ret = `request ${req.method} ${req.httpVersion} ${req.url}` +'\n';
53 | ret += JSON.stringify(url.parse(req.url, true)) +'\n';
54 | var keys = Object.keys(req.headers);
55 | for (var i = 0, l = keys.length; i < l; i++) {
56 | var key = keys[i];
57 | ret += `${i} ${key}: ${req.headers[key]}` +'\n';
58 | }
59 | if (req.trailers)
60 | ret += req.trailers +'\n';
61 | return ret;
62 | };
63 |
64 |
--------------------------------------------------------------------------------
/Chapter 4/events/pulser.js:
--------------------------------------------------------------------------------
1 | var events = require('events');
2 | var util = require('util');
3 |
4 | // Define the Pulser object
5 | function Pulser() {
6 | events.EventEmitter.call(this);
7 | }
8 | util.inherits(Pulser, events.EventEmitter);
9 |
10 | Pulser.prototype.start = function() {
11 | var self = this;
12 | setInterval(() => {
13 | util.log('>>>> pulse');
14 | self.emit('pulse');
15 | util.log('<<<< pulse');
16 | }, 1000);
17 | };
18 |
19 | // Instantiate a Pulser object
20 | var pulser = new Pulser();
21 | // Handler function
22 | pulser.on('pulse', () => {
23 | util.log('pulse received');
24 | });
25 | // Start it pulsing
26 | pulser.start();
27 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/_gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
27 | node_modules
28 |
29 | # Debug log from npm
30 | npm-debug.log
31 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/app.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var path = require('path');
3 | var favicon = require('serve-favicon');
4 | var logger = require('morgan');
5 | var cookieParser = require('cookie-parser');
6 | var bodyParser = require('body-parser');
7 |
8 | var routes = require('./routes/index');
9 | var fibonacci = require('./routes/fibonacci');
10 |
11 | var app = express();
12 |
13 | // view engine setup
14 | app.set('views', path.join(__dirname, 'views'));
15 | app.set('view engine', 'ejs');
16 |
17 | // uncomment after placing your favicon in /public
18 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
19 | app.use(logger('dev'));
20 | app.use(bodyParser.json());
21 | app.use(bodyParser.urlencoded({ extended: false }));
22 | app.use(cookieParser());
23 | app.use(express.static(path.join(__dirname, 'public')));
24 |
25 | app.use('/', routes);
26 | app.use('/fibonacci', fibonacci);
27 |
28 | // catch 404 and forward to error handler
29 | app.use(function(req, res, next) {
30 | var err = new Error('Not Found');
31 | err.status = 404;
32 | next(err);
33 | });
34 |
35 | // error handlers
36 |
37 | // development error handler
38 | // will print stacktrace
39 | if (app.get('env') === 'development') {
40 | app.use(function(err, req, res, next) {
41 | res.status(err.status || 500);
42 | res.render('error', {
43 | message: err.message,
44 | error: err
45 | });
46 | });
47 | }
48 |
49 | // production error handler
50 | // no stacktraces leaked to user
51 | app.use(function(err, req, res, next) {
52 | res.status(err.status || 500);
53 | res.render('error', {
54 | message: err.message,
55 | error: {}
56 | });
57 | });
58 |
59 |
60 | module.exports = app;
61 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('fibonacci:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/fiboclient.js:
--------------------------------------------------------------------------------
1 | var http = require('http');
2 | var util = require('util');
3 | [
4 | "/fibonacci/30", "/fibonacci/20", "/fibonacci/10",
5 | "/fibonacci/9", "/fibonacci/8", "/fibonacci/7",
6 | "/fibonacci/6", "/fibonacci/5", "/fibonacci/4",
7 | "/fibonacci/3", "/fibonacci/2", "/fibonacci/1"
8 | ].forEach(path => {
9 | util.log('requesting ' + path);
10 | var req = http.request({
11 | host: "localhost",
12 | port: 3002,
13 | path: path,
14 | method: 'GET'
15 | }, res => {
16 | res.on('data', chunk => {
17 | util.log('BODY: ' + chunk);
18 | });
19 | });
20 | req.end();
21 | });
22 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/fiboserver.js:
--------------------------------------------------------------------------------
1 | var math = require('./math');
2 | var express = require('express');
3 | var logger = require('morgan');
4 | var app = express();
5 | app.use(logger('dev'));
6 | app.get('/fibonacci/:n', (req, res, next) => {
7 | math.fibonacciAsync(Math.floor(req.params.n), (err, val) => {
8 | if (err) next('FIBO SERVER ERROR ' + err);
9 | else {
10 | res.send({
11 | n: req.params.n,
12 | result: val
13 | });
14 | }
15 | });
16 | });
17 | app.listen(process.env.SERVERPORT);
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/fibotimes.js:
--------------------------------------------------------------------------------
1 |
2 | var math = require('./math');
3 | var util = require('util');
4 |
5 | for (var num = 1; num < 8000; num++) {
6 | // util.log('Fibonacci for '+ num +' = '+ math.fibonacci(num));
7 | util.log('Fibonacci for '+ num +' = '+ math.fibonacciLoop(num));
8 | }
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/math.js:
--------------------------------------------------------------------------------
1 |
2 | var fibonacci = exports.fibonacci = function(n) {
3 | if (n === 1)
4 | return 1;
5 | else if (n === 2)
6 | return 1;
7 | else
8 | return fibonacci(n-1) + fibonacci(n-2);
9 | };
10 |
11 | var fibonacciLoop = exports.fibonacciLoop = function(n) {
12 | var fibos = [];
13 | fibos[0] = 0;
14 | fibos[1] = 1;
15 | fibos[2] = 1;
16 | for (var i = 3; i <= n; i++) {
17 | fibos[i] = fibos[i-2] + fibos[i-1];
18 | }
19 | return fibos[n];
20 | };
21 |
22 | var fibonacciAsync = exports.fibonacciAsync = function(n, done) {
23 | if (n === 0)
24 | done(undefined, 0);
25 | else if (n === 1 || n === 2)
26 | done(undefined, 1);
27 | else {
28 | setImmediate(() => {
29 | fibonacciAsync(n-1, (err, val1) => {
30 | if (err) done(err);
31 | else setImmediate(() => {
32 | fibonacciAsync(n-2, (err, val2) => {
33 | if (err) done(err);
34 | else done(undefined, val1+val2);
35 | });
36 | });
37 | });
38 | });
39 | }
40 | };
41 |
42 | exports.fibonacciPromise = function(n) {
43 | return new Promise((resolve, reject) => {
44 | fibonacciAsync(n, (err, val) => {
45 | if (err) reject(err);
46 | else resolve(val);
47 | });
48 | });
49 | };
50 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fibonacci",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "SERVERPORT=3002 DEBUG=fibonacci:* node ./bin/www",
7 | "server": "SERVERPORT=3002 node ./fiboserver --max_semi_space_size 5000 --max_old_space_size 5000",
8 | "client": "node ./fiboclient"
9 | },
10 | "engines": {
11 | "node": ">=5.x"
12 | },
13 | "dependencies": {
14 | "body-parser": "~1.13.2",
15 | "cookie-parser": "~1.3.5",
16 | "debug": "~2.2.0",
17 | "ejs": "~2.3.3",
18 | "express": "~4.13.1",
19 | "morgan": "~1.6.1",
20 | "serve-favicon": "~2.3.0"
21 | }
22 | }
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/routes/fibonacci.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | var math = require('../math');
5 |
6 | router.get('/', function(req, res, next) {
7 | if (req.query.fibonum) {
8 | // Calculate directly in this server
9 | res.render('fibonacci', {
10 | title: "Calculate Fibonacci numbers",
11 | fibonum: req.query.fibonum,
12 | fiboval: math.fibonacci(req.query.fibonum)
13 | });
14 | // Calculate using async-aware function, in this server
15 | /* math.fibonacciAsync(req.query.fibonum, (err, fiboval) => {
16 | res.render('fibonacci', {
17 | title: "Calculate Fibonacci numbers",
18 | fibonum: req.query.fibonum,
19 | fiboval: fiboval
20 | });
21 | }); */
22 | // Pass request off to back end server
23 | /* var httpreq = require('http').request({
24 | host: "localhost",
25 | port: process.env.SERVERPORT,
26 | path: "/fibonacci/"+Math.floor(req.query.fibonum),
27 | method: 'GET'
28 | },
29 | httpresp => {
30 | httpresp.on('data', chunk => {
31 | var data = JSON.parse(chunk);
32 | res.render('fibonacci', {
33 | title: "Calculate Fibonacci numbers",
34 | fibonum: req.query.fibonum,
35 | fiboval: data.result
36 | });
37 | });
38 | httpresp.on('error', err => { next(err); });
39 | });
40 | httpreq.on('error', err => { next(err); });
41 | httpreq.end(); */
42 | } else {
43 | res.render('fibonacci', {
44 | title: "Calculate Fibonacci numbers",
45 | fiboval: undefined
46 | });
47 | }
48 | });
49 |
50 | module.exports = router;
51 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | /* GET home page. */
5 | router.get('/', function(req, res, next) {
6 | res.render('index', {
7 | title: "Math Calculator"
8 | });
9 | });
10 |
11 | module.exports = router;
12 |
--------------------------------------------------------------------------------
/Chapter 4/fibonacci/views/bottom.ejs:
--------------------------------------------------------------------------------
1 |