How to migrate SSE chat node express to node hapi - node.js

I was testing a SSE node express chat in localhost.It was working perfectly. I was including a chat_server in a demo with hapijs as modular server...and it complain about the express syntax. How can I migrate the code to the right syntax in hapijs?
I am trying to solve changing writeHead and write methods because it's complaing about and adding stream package after searching answers in internet.
/*
* Request handlers
*/
function handleGetChat(req, res) {
console.log('handleGetChat received.');
// res(chatStream).code(200).type('text/event-stream').header('Connection', 'keep-alive').header('Cache-Control','no-cache');
// chatStream.write('\n');
(function(clientId) {
clients[clientId] = res;
clientNames[clientId] = req.params.name;
console.log('name {$req.params.name}');
req.on("close", () => {
delete clients[clientId];
actUserName = "";
sendText(clientNames[clientId] + " disconnected!", false);
delete clientNames[clientId];
});
})(++clientId);
sendText(req.params.name + " connected!", false);
let allMates = "";
for (cliId in clientNames) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(`logged in [${allMates}]`, false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
allMates += `${clientNames[cliId]}`;
if (cliId < clientId) allMates += " ";
}
sendText(logged in [${allMates}], false);
}
let sendText = (text, showUserName = true) => {
for (clientId in clients) {
let data = "";
let date = new Date();
let timestamp = `[${date.getHours()}:${date.getMinutes()}]`;
if (showUserName) {
data = `data: ${timestamp} <${actUserName}> ${text}\n\n`;
} else {
data = `data: ${timestamp} ${text}\n\n`;
}
//chatStream.push('data: ' + "\n\n");
}
};
function handleWriteChat(req, res) {
actUserName = req.body.name;
sendText(req.body.text);
res.json({ success: true });
}
The commented lines in the code above are the lines with syntax error in hapi. I was already changing the originals write and writeHead with chatstream.

Related

connection.queryRaw is not a function error in NodeJs WebAPI call

I am new to Nodejs. I am developing WebAPI by using NodeJs and MSSQl as database.My api is giving proper response in case of POST endpoint If it is called while server is listening through Dev environment command [npm run start]. But, If I Deploy my API on Windows IIS , it is giving the mentioned error. My reference API endpoint code is as below :
router.post('/',async (req,res,next)=>{
// console.log('Enter products creation')
const Product = Array.from(req.body) // req.body
// console.log('New Product details passed on',Product)
const createProd = require('../CreateProduct')
const response = await createProd(Product)
res.status(404).json({
message : response.retStatus
})
})
CreateProduct function called in above code is as below :
const sql = require("mssql/msnodesqlv8");
const dataAccess = require("../DataAccess");
const fn_CreateProd = async function (product) {
let errmsg = "";
let objBlankTableStru = {};
let connPool = null;
// console.log('Going to connect with Connstr:',global.config)
await sql
.connect(global.config)
.then((pool) => {
global.connPool = pool;
productsStru = pool.request().query("DECLARE #tblProds tvp_products select * from #tblProds");
return productsStru;
})
.then(productsStru=>{
objBlankTableStru.products = productsStru
productsOhStru = global.connPool.request().query("DECLARE #tblprodsOh tvp_product_oh select * from #tblprodsOh");
return productsOhStru
})
.then((productsOhStru) => {
objBlankTableStru.products_oh = productsOhStru
let objTvpArr = [
{
uploadTableStru: objBlankTableStru,
},
{
tableName : "products",
tvpName: "tvp_products",
tvpPara: "tblProds"
},
{
tableName : "products_oh",
tvpName: "tvp_product_oh",
tvpPara: "tblProdsOh",
}
];
newResult = dataAccess.getPostResult(
objTvpArr,
"sp3s_ins_products_tvp",
product
);
console.log("New Result of Execute Final procedure", newResult);
return newResult;
})
.then((result) => {
// console.log("Result of proc", result);
if (!result.recordset[0].errmsg)
errmsg = "New Products Inserted successfully";
else errmsg = result.recordset[0].errmsg;
})
.catch((err) => {
console.log("Enter catch of Posting prod", err.message);
errmsg = err.message;
if (errmsg == "") {
errmsg = "Unknown error from Server... ";
}
})
.finally((resp) => {
sql.close();
});
return { retStatus: errmsg };
};
module.exports = fn_CreateProd;
GetPost() function is as below :
const getPostResult = (
tvpNamesArr,
procName,
sourceData,
sourceDataFormat,
singleTableData
) => {
let arrtvpNamesPara = [];
let prdTable = null;
let newSrcData = [];
// console.log("Source Data :", sourceData);
let uploadTable = tvpNamesArr[0];
for (i = 1; i <= tvpNamesArr.length - 1; i++) {
let tvpName = tvpNamesArr[i].tvpName;
let tvpNamePara = tvpNamesArr[i].tvpPara;
let TableName = tvpNamesArr[i].tableName;
let srcTable = uploadTable.uploadTableStru[TableName];
srcTable = srcTable.recordset.toTable(tvpName);
let newsrcTable = Array.from(srcTable.columns);
newsrcTable = newsrcTable.map((i) => {
i.name = i.name.toUpperCase();
return i;
});
if (!singleTableData) {
switch (sourceDataFormat) {
case 1:
newSrcData = sourceData.filter((obj) => {
return obj.tablename.toUpperCase() === TableName.toUpperCase();
});
break;
case 2:
newSrcData = getObjectDatabyKey(sourceData, TableName);
break;
default:
newSrcData = getTableDatabyKey(sourceData, TableName);
break;
}
} else {
newSrcData = sourceData;
}
// console.log(`Filtered Source data for Table:${TableName}`, newSrcData);
prdTable = generateTable(
newsrcTable,
newSrcData,
tvpName,
sourceDataFormat
);
arrtvpNamesPara.push({ name: tvpNamePara, value: prdTable });
}
const newResult = execute(procName, arrtvpNamesPara);
return newResult;
};
Finally, I have found the solution to this.. it is very strange and shocking and surprising that If I using Morgan Middleware in app.js and have used it by syntax : app.use(morgan('dev')) , then it is the culprit command..I just removed dev from this command after which problem got resolved..But I found no help regarding this issue over Google anywhere..I really fear that what type of challenges I am going to face in future development if these kind of silly error come without giving any hint..I would be highly obliged If anyone could make me understand this kind of silly errors..

Edit a JSON object

I retrieved a JSON object from a local database, I want to edit a value (invItems) and add a new value to it (filed[filed.invItems]), then upload it back to the database, but it does not seem to work (the JSON does not seem to change)
async function invPut(itemID, message) {
var filed = await frenzyDB.getKey(id + "_invcache");
console.log("Before: " + filed)
newInvItems = filed.invItems + 1;
filed.invItems = newInvItems;
filed[filed.invItems] = itemID;
console.log("After: " + filed);
await frenzyDB.addKey(id + "_invcache", filed)
}
Console Output:
Before: {"invItems":0}
After: {"invItems":0}
It shows no errors, but the JSON doesnt change. Am I doing something wrong? If so, what can I do to fix it?
Thanks for all your help!
Notes:
frenzyDB is just a javascript file that deals with a standard REPL.it Database
Code of frenzyDB:
const Database = require("#replit/database")
const db = new Database()
async function addKey(key, value) {
await db.set(key, value).then(() => {return;});
}
async function getKey(key) {
return await db.get(key).then(value => {return value;});
}
function listAllKeys() {
db.list().then(keys => {return keys;});
}
async function hasKey(key) {
var keys = await listAllKeys();
if (keys.includes(key)) {
return true;
} else {
return false;
}
}
async function removeKey(key) {
await db.delete(key).then(() => {return;});
}
module.exports = {
addKey,
getKey,
listAllKeys,
hasKey,
removeKey
};
Edit: Latest code:
async function invPut(itemID, message) {
await init(message.author.id);
var filed = await frenzyDB.getKey(message.author.id + "_invcache");
console.log(filed)
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log(result);
frenzyDB.addKey(message.author.id + "_invcache", result)
message.reply("A **"+ itemIDs[itemID].name + "** was placed in your inventory");
return true;
}
EDIT 2: Latest Console Output:
{ '4': 3, invItems: 5 }
{ '5': 3, invItems: 6 }
Any help will be appreciated!
Thanks
Try this
// Demo Data
const itemID = 10;
var filed = { "invItems" : 0 };
// Real function
console.log("Before: " + JSON.stringify(filed));
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log("After: " + JSON.stringify(result));
The result I get is
Before: {"invItems":0}
After: {"0":10,"invItems":1}
You would then of course use result to store the data away in the DB.
async function invPut(itemID, message) {
// Typo?
var filed = await frenzyDB.getKey(itemID + "_invcache");
console.log("Before: " + filed)
const result = {};
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log("After: " + result);
// Typo?
await frenzyDB.addKey(itemID + "_invcache", result)
}
Answer Edit:
const result = { ...filed };
result.invItems = (filed['invItems'] + 1) || 1;
result.hasOwnProperty(filed.invItems) ? result[filed.invItems + 1] = itemID : result[filed.invItems] = itemID;
console.log(JSON.stringify(result));
maybe this will help you
const json = fs.readFileSync(`${__dirname}/data/data.json`, "utf-8");
const inputData = JSON.parse(json);
inputData.push({input: 'front'}) // creates new element for data.json
-------------------------------------------
array.push({front: 'front', back: 'back'});

Problem with findOne() in sequelize node.js

I have a problem with node.js and sequelize findOne(). I want to find new students, that I want to add to the DB (var novi), and the ones that already exist, I just want to update their field (var stari). Everything works as expected, only when I want to return JSON with how many new students I added to the DB, and how many are updated, values of stari and novi, go back to 0, but the counting is good, I checked. I know the problem is with asynchronous call, but I don't know how to fix.
app.post('/student', function(req,res) {
var imeGodine = req.body['godina'];
//POMOĆNE SKRIPTE BitBucket.js i citanjeGodina.js
var broj = 0;
var stari = 0;
var novi = 0;
db.godina.findOne({where:{nazivGod:req.body.godina}}).then(god => {
var studenti = req.body.studenti;
db.student.count().then (ranijeStudenata => {
for(var i = 0; i<studenti.length; i++) {
var ime = studenti[i].imePrezime;
var ind = studenti[i].index;
db.student.findOne({where:{index :studenti[i].index}}).then(stud => {
if (stud == null) {
novi++;
db.student.create({imePrezime:ime, index : ind}).then(noviStudent => {
god.addStudenti(noviStudent);
});
}
else if (stud != null) {
stari++;
god.addStudenti(stud);
}
});
broj++;
}
var brojNovih = broj - ranijeStudenata; //ne koristi se, ali možda hoće
res.set("Content-Type", "application/json");
res.status(200).send(JSON.stringify({message: "Dodano je " + novi + " novih studenata i upisano " + stari + " na godinu " + imeGodine}));
});
});
});
Picture of code
You can use async/await to do counting in a synchronous way.
'use strict';
app.post('/student', async function (req, res) {
var imeGodine = req.body['godina'];
var {studenti} = req.body;
var broj = 0;
var stari = 0;
var novi = 0;
let god = await db.godina.findOne({where: {nazivGod: req.body.godina}});
let ranijeStudenata = await db.student.count(); // ranijeStudenata not used?
for (var i = 0; i < studenti.length; i++) {
var ime = studenti[i].imePrezime;
var ind = studenti[i].index;
let stud = await db.student.findOne({where: {index: studenti[i].index}});
if (stud === null) {
novi++;
let noviStudent = await db.student.create({imePrezime: ime, index: ind});
god.addStudenti(noviStudent);
} else if (stud !== null) {
stari++;
god.addStudenti(stud);
}
broj++;
}
return res.status(200).send({
message: "Dodano je " + novi + " novih studenata i upisano " + stari + " na godinu " + imeGodine
});
});

Knockout-2.2.0, subscribe get value before change AND new value

jsfiddle link: http://jsfiddle.net/T8ee7/
When I call Knockout's subscribe method is there a way I can get both the previous and new value? Right now, I can only call get these values separately.
I want to trigger some code if the old and new value are different.
I suppose I could do the following, but it can get messy...
(http://jsfiddle.net/MV3fN/)
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
this.pageNumber = ko.observable(pageNumber || 1);
this.numberOfPages = ko.observable(1);
this.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
};
var _pagedRequest = new sv.PagedRequest();
var oldValue;
_pagedRequest.pageNumber.subscribe(function (previousValue) {
console.log("old: " + previousValue);
oldValue = previousValue;
}, _pagedRequest, "beforeChange");
_pagedRequest.pageNumber.subscribe(function (newValue) {
console.log("new: " + newValue);
if (oldValue != newValue) {
console.log("value changed!");
}
});
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
​
I prefer using an observable extender.
http://jsfiddle.net/neonms92/xybGG/
Extender:
ko.extenders.withPrevious = function (target) {
// Define new properties for previous value and whether it's changed
target.previous = ko.observable();
target.changed = ko.computed(function () { return target() !== target.previous(); });
// Subscribe to observable to update previous, before change.
target.subscribe(function (v) {
target.previous(v);
}, null, 'beforeChange');
// Return modified observable
return target;
}
Example Usage:
// Define observable using 'withPrevious' extension
self.hours = ko.observable().extend({ withPrevious: 1 });
// Subscribe to observable like normal
self.hours.subscribe(function () {
if (!self.hours.changed()) return; // Cancel if value hasn't changed
print('Hours changed from ' + self.hours.previous() + ' to ' + self.hours());
});
This seems to work for me
ko.observable.fn.beforeAndAfterSubscribe = function (callback, target) {
var _oldValue;
this.subscribe(function (oldValue) {
_oldValue = oldValue;
}, null, 'beforeChange');
this.subscribe(function (newValue) {
callback.call(target, _oldValue, newValue);
});
};
See more at: http://ideone.com/NPpNcB#sthash.wJn57567.dpuf
http://jsfiddle.net/MV3fN/3/
var sv = sv || {};
sv.PagedRequest = function (pageNumber, pageSize) {
var self = this;
self.pageNumber = ko.observable(pageNumber || 1);
self.numberOfPages = ko.observable(1);
self.pageSize = ko.observable(pageSize || sv.DefaultPageSize);
self.pageNumber.subscribe(function (previousValue) {
console.log(previousValue);
console.log(self.pageNumber.arguments[0]);
if (previousValue != _pagedRequest.pageNumber.arguments[0]) {
console.log('value changed');
}
else {
//This won't get executed because KO doesn't
//call the function if the value doesn't change
console.log('not changed');
}
}, _pagedRequest, "beforeChange");
};
var _pagedRequest = new sv.PagedRequest();
_pagedRequest.pageNumber(10);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(20);
_pagedRequest.pageNumber(5);
I don't know if you're really supposed to use arguments[0], but it seems to work.
You could also set up your own method to accomplish this in a much cleaner way:
http://jsfiddle.net/PXKgr/2/
...
self.setPageNumber = function(page) {
console.log(self.pageNumber());
console.log(page);
if (self.pageNumber() != page) {
console.log('value changed');
}
else {
console.log('not changed');
}
self.pageNumber(page);
};
...
_pagedRequest.setPageNumber(10);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(20);
_pagedRequest.setPageNumber(5);

Handling byte streams in node.js

For education purposes I am creating a little chat with node.js using TCP.
I am using the windows console to connect with my node server but when I am typing all the characters are streamed one by one. They don't arive as strings. How can I manage to handle those streams so my users don't can write complete words.
My Code:
var net = require("net");
Array.prototype.remove = function(e) {
for (var i = 0; i < this.length; i++) {
if (e == this[i]) { return this.splice(i, 1); }
}
};
function Chatter(stream) {
this.name = null;
this.stream = stream;
}
var chatters = [];
var server = net.createServer(function(stream) {
var chatter = new Chatter(stream);
chatters.push(chatter);
stream.setTimeout(0);
stream.setEncoding("utf8");
stream.addListener("connect", function(){
stream.write("Hallo, wer bist du?:\n");
});
stream.addListener("data", function (data) {
if(chatter.name == null) {
chatter.name = data.match(/\S+/);
stream.write("....................\n");
chatters.forEach(function(c){
if (c != chatter) {
c.stream.write(chatter.name + " ist dem Chat beigetreten!\n");
}
});
return;
}
var command = data.match(/^\/(.*)/);
if (command) {
if (command[1] == 'users') {
chatters.forEach(function(c) {
stream.write("- " + c.name + "\n");
});
}
else if (command[1] == 'quit') {
stream.end();
}
}
chatters.forEach(function(c) {
if(c != chatter) {
c.stream.write(chatter.name + ": " + data);
}
});
});
stream.addListener("end", function(){
chatters.remove(chatter);
chatters.forEach(function(c) {
c.stream.write(chatter.name + " hat den Chat verlassen.\n");
});
stream.end();
});
});
server.listen(8000);
For the record that code is from this site
ADDITION:
setEncoding('utf8') is supposed to change the emiting of data, but it doesn't work for me :-(
The solution to your problem is to store all received characters in a buffer and when an END_OF_NICK character is encountered (say, \n), use the buffer as the name.
var buffer = ""; // stores received characters
stream.addListener("data", function (data) {
if(chatter.name == null) { // still receiving characters for the name
buffer += data; // append received characters to the buffer
if (buffer.indexOf('\n') == -1) return; // if there's no END_OF_NICK character, keep waiting for it
chatter.name = buffer.match(/\S+/); // use the name in the buffer
// ...
}

Resources