├── .gitignore ├── README.md ├── .gitinore ├── package.json ├── server.js └── tcp ├── client.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | /node_modules 3 | .vscode/ 4 | .idea 5 | 6 | # misc 7 | .DS_Store 8 | .env.local 9 | .env.development.local 10 | .env.test.local 11 | .env.production.local 12 | 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | yarn.lock 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodejs-event-driven-programming 2 | Learn event driven programming using Nodejs Net, Events modules. 3 | This repo is Code for my [Medium Article](https://blog.cloudboost.io/event-driven-programming-with-nodejs-net-and-events-9e4e14f561f3) on how to write Nodejs for event driven programs. 4 | Feel free to clone this repo, fork or download and do whatever with, as long as u learn. 5 | -------------------------------------------------------------------------------- /.gitinore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | #/backend/node_modules 5 | /node_modules 6 | .vscode/ 7 | .idea 8 | 9 | # misc 10 | .DS_Store 11 | .env.local 12 | .env.development.local 13 | .env.test.local 14 | .env.production.local 15 | 16 | npm-debug.log* 17 | yarn-debug.log* 18 | yarn-error.log* 19 | yarn.lock 20 | 21 | **/*/paymentService.test.js 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs-event-driven-programming", 3 | "version": "1.0.0", 4 | "description": "Learn how to write event driven programs in JavaScript using Nodejs runtime environment.", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+ssh://git@github.com/zemuldo/nodejs-event-driven-programming.git" 12 | }, 13 | "keywords": [ 14 | "nodejs", 15 | "event-driven", 16 | "events", 17 | "tcp", 18 | "streams" 19 | ], 20 | "author": "Danstan Otieno ONyango ~ Zemuldo", 21 | "license": "ISC", 22 | "bugs": { 23 | "url": "https://github.com/zemuldo/nodejs-event-driven-programming/issues" 24 | }, 25 | "homepage": "https://github.com/zemuldo/nodejs-event-driven-programming#readme", 26 | "dependencies": { 27 | "express": "^4.16.3" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const client = require('./tcp/client'); 3 | const EventEmitter = require('events'); 4 | 5 | class OnDataEmitter extends EventEmitter { } 6 | const OnData = new OnDataEmitter(); 7 | 8 | const app = express() 9 | 10 | // TCP Client data event listener that handles data event by the client. 11 | client.on('data', (data) => { 12 | const code = data.toString().slice(0,3) 13 | OnData.emit(code, data.toString()) 14 | }); 15 | 16 | 17 | app.get(('/'), async (req, res) => { 18 | const code = req.query.statusCode; 19 | let status = false 20 | OnData.on(code, (data)=>{ 21 | status = true 22 | res.send({data}) 23 | OnData.removeAllListeners(code); 24 | }) 25 | 26 | // set a timeout to remove listener and send timeout response if the TCP server fails to reply 27 | setTimeout(()=>{ 28 | if(status) return true; 29 | // Clear the enevnt listener to void memory leaks 30 | OnData.removeAllListeners(code); 31 | res.send({error: 'timedout'}) 32 | }, 2000) 33 | client.write(code) 34 | }); 35 | 36 | app.listen(8090,()=>console.log('Server listening on http://localhost:8090')) -------------------------------------------------------------------------------- /tcp/client.js: -------------------------------------------------------------------------------- 1 | const net = require('net'); 2 | const client = new net.Socket(); 3 | const config = { 4 | host: '0.0.0.0', 5 | port: 9670, 6 | exclusive: true, 7 | } 8 | const timeout = 3000; 9 | let retrying = false; 10 | // Functions to handle client events 11 | // connector 12 | function makeConnection() { 13 | client.connect(config.port, config.host); 14 | } 15 | function connectEventHandler() { 16 | console.log('***** connected ******'); 17 | console.log({ 18 | port: client.remotePort, 19 | host: client.remoteAddress, 20 | }, 'connected to server'); 21 | retrying = false; 22 | } 23 | 24 | function errorEventHandler(e) { 25 | console.log(`Connection error ${e.code}`); 26 | if (!retrying) { 27 | retrying = true; 28 | } 29 | setTimeout(makeConnection, timeout); 30 | } 31 | function closeEventHandler() { 32 | if (retrying) return false; 33 | console.log('Server closed'); 34 | console.log(`Reconnecting... in ${timeout / 1000} Seconds`); 35 | if (!retrying) { 36 | retrying = true; 37 | } 38 | return setTimeout(makeConnection, timeout); 39 | } 40 | // Start Eevent Listeners 41 | client.on('connect', connectEventHandler); 42 | client.on('error', errorEventHandler); 43 | client.on('close', closeEventHandler); 44 | 45 | // Connect to remote server 46 | console.log('***** connecting ******'); 47 | makeConnection(); 48 | 49 | module.exports = client; -------------------------------------------------------------------------------- /tcp/server.js: -------------------------------------------------------------------------------- 1 | const net = require('net'); 2 | const server = net.createServer(); 3 | const config = { 4 | host: '0.0.0.0', 5 | port: 9670, 6 | exclusive: true, 7 | } 8 | 9 | server.on('connection', (socket) => { 10 | console.log('New client connected') 11 | socket.on('data', (data) => { 12 | const code = data.toString().slice(0,3); 13 | switch (code) { 14 | case '404': 15 | return socket.write(`${code}: Not found, used when user request for a resource or page that does not exist.\n`); 16 | case '500': 17 | return socket.write(`${code}: Internal Server, used when web server has an unxpected error.\n`); 18 | default: 19 | return socket.write(`I dont know about code "${code}" mate, or I am yet to learn about it \n`); 20 | } 21 | }); 22 | 23 | socket.on('error', (err) => { 24 | console.log({ error: `error in connection ${err}` }); 25 | socket.destroy(JSON.stringify({ 26 | error: 'connection error', 27 | code: 500, 28 | })); 29 | socket.end(); 30 | }); 31 | }); 32 | 33 | // Start server 34 | server.listen(config); 35 | 36 | // server running 37 | server.on('listening', () => { 38 | console.log('server is listening on %j', config.port); 39 | }); 40 | 41 | // Restart server if port or address is under use 42 | server.on('error', (err) => { 43 | if (err.code === 'EADDRINUSE') { 44 | console.log('Address or Port in use, retrying...'); 45 | setTimeout(() => { 46 | server.close(); 47 | server.listen(config); 48 | }, 5000); 49 | } else { 50 | console.log({ err: `Server error ${err}` }); 51 | } 52 | }); 53 | 54 | module.exports = server; --------------------------------------------------------------------------------