is it save to just add a property with a numerical id to a new websocket object and to identify a client with this id which was added by the server ?
server.js
//...
var a_o_websocket_client = []
o_websocket_server.on("connection", async function (o_websocket_client) {
console.log(`a new o_websocket_client connected: ${o_websocket_client}`)
o_websocket_client.n_id = a_o_websocket_client.length; // assign a new id
a_o_websocket_client.push(o_websocket_client)
o_websocket_client.on(
"message",
async function(s_message){
console.log(`this is the websocket with the id ${n_id}`)
}
)
});
//...
Related
I try to make RESTFUL API with node js and oracle database for my first time
I make a table in the database named "EMPLOYEES" and I add some data there
I make my backend file and I try to get the information in the database and it's worked successfuly
but when I try to make POST to add a new employee I don't get an error and the employee is not added to the database
when I try to test it with POSTMAN I got this result a null object like this {}
I know that I'm missing something
const express = require('express')
const oracledb = require('oracledb');
const bodyPerser=require("body-parser")
const app = express();
const port = 3000;
var password = 'mypassword';
app.use(bodyPerser.json());
async function selectAllEmployees(req, res) {
try {
connection = await oracledb.getConnection({
user: "system",
password: password,
connectString: "localhost:1521/XE"
});
console.log('connected to database');
// run query to get all employees
result = await connection.execute(`SELECT * FROM EMPLOYEES`);
} catch (err) {
//send error message
return res.send(err.message);
} finally {
if (connection) {
try {
// Always close connections
await connection.close();
console.log('close connection success');
} catch (err) {
console.error(err.message);
}
}
if (result.rows.length == 0) {
//query return zero employees
return res.send('query send no rows');
} else {
//send all employees
//return res.send(result.rows);
console.log(JSON.stringify(result.rows));
console.log(result.metaData[0].name);
let list=[]
result.rows.forEach(element => {
let agent = {
"ID": element[0],
"EMPNAME": element[1],
"EMPLASTNAME": element[2],
"AGE":element[3]
}
list.push(agent)
});
return res.send(JSON.stringify(list));
}
}
}
//get /employess
app.get('/employees', function (req, res) {
selectAllEmployees(req, res);
})
//////////////////post//////////////////////
app.post("/addNewEmployee", async (req, res) => {
try {
connection = await oracledb.getConnection({
user: "system",
password: password,
connectString: "localhost:1521/XE"
});
console.log('connected to database');
// I don't know what i'm missing here
result=connection.execute(`INSERT INTO EMPLOYEES VALUES ('${req.body.ID}','${req.body.EMPNAME}','${req.body.EMPLASTNAME}','${req.body.AGE}')`);
res.send(result)
} catch (err) {
//send error message
return res.send(err.message);
}
})
app.listen(port, () => console.log("nodeOracleRestApi app listening on port %s!", port))
Review node-oracledb examples and make sure you have basic techniques covered e.g. using bind variables. (The way you build your INSERT is open to SQL injection security attacks). Look at how webapp.js uses a connection pool - which you'll need if you have more than one person accessing your service.
Make sure you commit the data after inserting.
Add an 'await' before your connection.execute() for INSERT, something like:
result = await connection.execute(`INSERT INTO EMPLOYEES VALUES (:id, :empname, :emplastname, :age)`,
[req.body.ID, req.body.EMPNAME, req.body.EMPLASTNAME, req.body.AGE],
{autoCommit: true}
);
Do some debugging and see what is not working.
Avoid using SYSTEM for testing. Create a 'normal' (non privileged) user:
https://blogs.oracle.com/sql/how-to-create-users-grant-them-privileges-and-remove-them-in-oracle-database
Finally check out this series on creating a REST service with node-oracledb:
https://blogs.oracle.com/oraclemagazine/build-rest-apis-for-nodejs-part-1
https://github.com/oracle/oracle-db-examples/tree/master/javascript/rest-api
I am using the Node.js ws library, to listen to events in user accounts on a 3rd party API. For each user, I open a websocket to listen to the events in the user's account.
Turns out, the 3rd-party API doesn't provide a userID for each event, so if I have 10 websocket connections to user-accounts, I cannot determine which account an event came from.
I have access to a unique userId prior to starting each of my connections.
Is there a way to append or wrap the websocket connection with the userId identifier, to each connection I make, such that when I receive an event, I can access the custom identifier, and subsequently know which user's account the event came from?
The code below is a mix of real code, and pseudocode (i.e customSocket)
const ws = new WebSocket('wss://thirdparty-api.com/accounts', {
port: 8080,
});
ws.send(
JSON.stringify({
action: 'authenticate',
data: {
oauth_token: access_token,
},
})
);
// wrap and attach data here (pseudocode at top-level)
customSocket.add({userId,
ws.send(
JSON.stringify({
action: 'listen',
data: {
streams: ['action_updates'],
},
})
)
})
// listen for wrapper data here, pseudocode at top level
customSocket.emit((customData) {
ws.on('message', function incoming(data) {
console.log('incoming -> data', data.toString());
})
console.log('emit -> customData', customData);
})
Looking at the socket.io library, the namespace feature may solve for this, but I can't determine if that's true or not. Below is an example in their documentation:
// your application has multiple tenants so you want to dynamically create one namespace per tenant
const workspaces = io.of(/^\/\w+$/);
workspaces.on('connection', socket => {
const workspace = socket.nsp;
workspace.emit('hello');
});
// this middleware will be assigned to each namespace
workspaces.use((socket, next) => {
// ensure the user has access to the workspace
next();
});
I found a solution to this which is fairly simple. First create a message handler function:
const eventHandler = (uid, msg) => {
console.log(`${uid} did ${msg}`);
};
Then, when you create the websocket for the given user, wrap the .on event with the handler:
const createSocketForUser = (uid, eventHandler) => {
const socket = new WebSocket(/* ... */);
socket.onmessage = (msg) => {
eventHandler(uid, msg)
};
return socket;
}
Attaching the code snippet below. UniversalBot and ChatConnector has been deprecated in botbuilder 4.1.5.
var bot;
try {
bot = new BasicBot(conversationState, userState, botConfig);
} catch (err) {
console.error(`[botInitializationError]: ${ err }`);
process.exit();
}
// Create HTTP server
// let server = restify.createServer();
let server = express();
server.listen(process.env.port || process.env.PORT || 3978, function() {
console.log(`\n${ server.name } listening to ${ server.url }`);
console.log(`\nGet Bot Framework Emulator: https://aka.ms/botframework-emulator`);
console.log(`\nTo talk to your bot, open basic-bot.bot file in the Emulator`);
});
// Listen for incoming activities and route them to your bot main dialog.
server.post('/api/messages', (req, res) => {
// Route received a request to adapter for processing
adapter.processActivity(req, res, async (turnContext) => {
// route to bot activity handler.
await bot.onTurn(turnContext);
});
});
Your question is fairly general.
The session object from 3.x has been removed. Instead acccessors are used. You will want to do following in the bot class:
public onTurn = async (turnContext: TurnContext) => {
const userProfile = await this.userProfile.get(turnContext, new UserProfile());
const conversationData = await this.dialogStateAccessor.get(turnContext, { dialogStack: undefined });
// set vars in cache
userProfile.yourUserVarProp = "userValue";
conversationData.yourConversationVarProp = "conversationValue";
// persist userVars through dialog turn
await this.userProfile.set(turnContext, userProfile);
// persist conversationVars through dialog turn
await this.dialogStateAccessor.set(turnContext, conversationData);
//
// -> your dialogs here (await dc.beginDialog("dialogname");)
//
// save uservars to db at end of a turn
await this.userState.saveChanges(turnContext);
// save conversationVars to db at end of a turn
await this.conversationState.saveChanges(turnContext);
}
But there is some additional constructor stuff
#param {ConversationState} conversationState A ConversationState object used to store the dialog state.
#param {UserState} userState A UserState object used to store values specific to the user.
... and creating the userProfile and dialogStateAccessor itself.
For the whole picture have better a look at https://github.com/Microsoft/BotBuilder-Samples/tree/master/samples/javascript_nodejs .
Or try the generator: https://learn.microsoft.com/en-us/azure/bot-service/javascript/bot-builder-javascript-quickstart?view=azure-bot-service-4.0.
I'm trying to set up a server that can dynamically create many rooms for many namespaces. I'm currently just trying to broadcast to sockets of a room, when a new socket has joined that room.
So far I have been able to broadcast to a specific namespace and my event listeners on the client receives the message. However when I try to broadcast to a room, of a specific namespace, my event listener doesn't receive that message.
I've turned on the Debugger mode and see the socket.io-client:socket emitting the event with the right payload and event type. So I am not sure what I am missing since the documentation also seems fairly straightforward. Any help would be much appreciated. Below is my code.
Server
const colorNs = io.of('/color');
colorNs.on('connection', (socket) => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
if(id) {
socket.join(id);
socket.broadcast.to(id).emit('user:connect', { id: connId });
}
socket.on('disconnect', () => {
const { id } = socket.handshake.query;
const { id:connId } = socket.conn;
socket.broadcast.to(id).emit('user:disconnect', { id: connId });
});
});
Client
const socket = io('/color?id="123"');
socket.on('user:connect', () => console.log('data', data));
Client - Debug Trace
socket.io-parser decoded 2/color,["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] as {"type":2,"nsp":"/color","data":["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}]} +1ms
browser.js:133
socket.io-client:socket emitting event ["user:connect",{"id":"IZTTPidF121JCzf9AAAO"}] +3ms
Is there any way to do this?
Client side:
function connectWebSocket() {
var socket = new SockJS('/socket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log("connected");
});
}
Server side is not important. After the code above has been executed I need to know my session id.
You can get it from url without making any changes into SockJS library.
var socket = new SockJS('/mqClient');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
console.log(socket._transport.url);
//it contains ws://localhost:8080/mqClient/039/byxby3jv/websocket
//sessionId is byxby3jv
});
The SockJS constructor has an option parameter and there you can pass a custom session id generator as a function:
let sessionId = utils.random_string(8);
let socket = new SockJS('/socket', [], {
sessionId: () => {
return sessionId
}
});
To get session id we need to make some changes into SockJS library.
The string
var connid = utils.random_string(8);
is used to get our id. So, we need only complete it like this:
var connid = utils.random_string(8);
that.sessionId = connid;
and then we can read this field from the client code:
function connectWebSocket() {
var socket = new SockJS('/socket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log("connected, session id: " + socket.sessionId);
});
}
And if we need to know session id before calling connect method we can modify SockJS' constructor and connect method to use client-passed value.