Unable to connect to oracle cloud autonomous database from linux environment - node.js

I am using a Node JS application that has Oracle Autonomous Database as a backend.
It works perfectly on my local machine and I am able to connect it well without any issue.
I tried deploying Node JS project to Azure WebAppService on Linux server.
Initially after deployment I my project was not able to find the Oracle client and so after searching a lot I was able to fix that problem by below
steps
with this I was able to solve client issue.
I have wallet files which I received from oracle which I have placed in admin folder
but now the problem is when I make any request I am getting this error
data:{"message":"db.doConnect is not a function","stack":"TypeError:
db.doConnect is not a `function\n`
createPool() callback: ORA-28759: failure to open file
my code:
// Include all external dependencies
const oracledb = require('oracledb');
// Intialize variables
const numRows = 100;
let respArr = [];
let connectionObject;
async function initialize(envName) {
await oracledb.createPool({
user: process.env.DATABASEUSERNAME,
password: process.env.DATABASEPASSWORD,
connectString: process.env.DATABASECONNECTIONSTRING,
});
}
async function close(poolAlias) {
await oracledb.getPool(poolAlias).close();
}
// Function to iterate through all the rows fetched in the result set and resturn the same
async function fetchRowsFromRS(connection, resultSet, numRows) {
// Get the rows
try {
const rows = await resultSet.getRows(numRows);
// no rows, or no more rows, then close the result set
if (rows.length === 0) {
console.log('No rows returned');
// doClose(connection, resultSet);
} else if (rows.length > 0) {
console.log(`Got ${rows.length} rows`);
respArr = respArr.concat(rows);
// Call the function recursively to get more rows
await fetchRowsFromRS(connection, resultSet, numRows);
}
// Return the rows
return respArr;
} catch (err) {
console.log(err);
}
}
async function simpleExecute(statement, binds = [], numberOutCur, poolAlias, opts = {}) {
try {
await initialize();
opts.outFormat = oracledb.OBJECT;
opts.autoCommit = true;
connectionObject = await oracledb.getConnection(poolAlias);
const finalResult = {};
const result = await connectionObject.execute(statement, binds, opts);
let promises = [];
for (let idx = 0; idx < numberOutCur; idx++) {
const refCurName = `ref_cur_${idx}`;
promises.push(fetchRowsFromRS(connectionObject, result.outBinds[refCurName], numRows));
const resultRows = await Promise.all(promises);
respArr = [];
finalResult[refCurName] = resultRows;
promises = [];
}
return finalResult;
// const values = await Promise.all(promises);
// return values;
} catch (error) {
return error;
} finally {
if (connectionObject) {
try {
await connectionObject.close();
} catch (err) {
console.log(err);
}
}
}
}
// Function to release the connection
function doRelease(connection) {
connection.close(
(err) => {
if (err) {
console.log(err.message);
}
},
);
}
// Function to close the result set connection
function doClose(connection, resultSet) {
resultSet.close(
(err) => {
if (err) { console.log(err.message); }
doRelease(connection);
},
);
}
// Export functions
module.exports.simpleExecute = simpleExecute;
module.exports.initialize = initialize;
module.exports.close = close;
I call my procs using this
const allProducts = await dbSvc.simpleExecute(query, cart_data_binds, 1,
'default');
what I understood with this message is I am not able to connect to my cloud database and I am not sure how to solve this can anyone help me with it its been 2 weeks now with this problem.
In Node JS project I am using simpleoracle library to connect my oracle cloud anonymous database

Thank you, Christopher Jones and saiharika213. Posting your suggestions as an answer to help other community members.
This ORA-28759: failure to open file error seems you need to update the WALLET_LOCATION directory in sqlnet.ora. You can refer to Connecting to Oracle Cloud Autonomous Databases
You can resolve this error by changing the connection string to point to the wallet location.
Move the wallets to respective project folder and modify the connection string as below in dbConfig.js.
Provide the wallet path from root till wallet folder.
For example:
module.exports = {
user: username,
password:password,
connectString:"(DESCRIPTION = (ADDRESS = (PROTOCOL = TCPS)(HOST = Hostname )(PORT = XXXX))(CONNECT_DATA = (SERVER = DEDICATED)(SERVICE_NAME = Servicename))(SECURITY=(MY_WALLET_DIRECTORY=/Users/yharika/Node_Projects/invoice_app/config/wallet)))"
}
You can refer to Unable to connect to oracle database from node js using sqlnet.ora with oracle wallet and Connecting with TCPS - ora-28759: failure to open file

Related

Create and handle multiple session for multiple users while making web socket connection in Microsoft Bot Builder

I am new to Microsoft Bot Framework .I have created a bot using Microsoft Bot Framework. How do I create a session for individual user. Currently the problem I am facing is whenever multiple users are creating connection, the values in the variables are getting over written thus giving wrong values to the users.
Here is the code
if (turnContext.activity.text === 'CCP') {
const url = await this.connectToAgent(members);
const initialMessage = {
topic: "aws/subscribe",
content: {
topics: ["aws/chat"]
}
};
ws = new WebSocket(url[1]);
ws.addEventListener("open", () => {
ws.send(JSON.stringify(initialMessage));
});
await turnContext.sendActivity("Please wait while we connect you to an agent.");
conversationReferences[currentUser] = TurnContext.getConversationReference(turnContext.activity);
adapter = turnContext.adapter;
ws.addEventListener('message', async function (event) {
const msg = JSON.parse(event.data);
});
let sendChatHistory = (function() {
let executed = false;
return function() {
if (!executed) {
executed = true;
const param = {
ConnectionToken: connectionToken, /* required */
Content: sendHistory, /* required */
ContentType: 'text/plain', /* required */
};
connectparticipant.sendMessage(param,async function (err, data) {
chatHistory = '';
sendHistory = '';
if (err) {
errorMsg = "Error while sending a message";
}
});
}
};
})();
sendChatHistory();
}
According to the official documentation we have the procedure of StateClient where we can give separate activity holder for individual users. This works when we are creating multiple users with multiple connections.
StateClient sc = activity.GetStateClient();
userData.SetProperty<string>("MyDetails", < some value >);
// How to save the BotUserData
await sc.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
// Getting User data from bot
BotData userData = await sc.BotState.GetUserDataAsync(activity.ChannelId, activity.From.Id);
As this is a parallel operation, the method Async is required to get the data of user simultaneously.

NodeJS GC function cannot be initialized

Trying out my first NodeJS cloud function so far unsuccessfully despite working fine VS code. Getting following error
Function cannot be initialized. Error: function terminated.
Looking through the logs I see some potential issues
Detailed stack trace: ReferenceError: supabase_public_url is not defined
Provided module can't be loaded (doesn't specify)
Thoughts: Am I doing it wrong with the secret manager and using the pub/sub incorrect?
My Code index.js
import { createClient } from '#supabase/supabase-js'
import sgMail from "#sendgrid/mail"
import { SecretManagerServiceClient } from '#google-cloud/secret-manager'
//activate cloud secret manager
const client = new SecretManagerServiceClient()
const supabaseUrl = client.accessSecretVersion(supabase_public_url)
const supabaseKey = client.accessSecretVersion(supabase_service_key)
const sendgridKey = client.accessSecretVersion(sendgrid_service_key)
sgMail.setApiKey(sendgridKey)
const supabase = createClient(supabaseUrl, supabaseKey)
// get data for supabase where notifications coins are true
const supabaseNotifications = async() => {
let { data, error } = await supabase
.from('xxx')
.select('*, xxx!inner(coin, xx, combo_change, combo_signal, combo_prev_signal), xxx!inner(email)')
.eq('crypto_signals.combo_change', true)
if(error) {
console.error(error)
return
}
return data
}
//create an array of user emails from supabase data
const userEmail = (data) => {
try {
const emailList = []
for (let i of data) {
if (emailList.includes(i.profiles.email) != true) {
emailList.push(i.profiles.email)
} else {}
}
return emailList
}
catch(e) {
console.log(e)
}
}
// function to take email list and supabase data to generate emails to users
const sendEmail = (e, data ) => {
try {
for (let i of e) {
const signalList = []
for (let x of data) {
if(i == x.profiles.email) {
signalList.push(x)
} else {}
}
// create msg and send from my email to the user
const msg = {
to: i,
from:"xxxx",
subject: "Coin notification alert from CryptoOwl",
text: "One or more of you coins have a new signal",
html: signalList.toString()
}
sgMail.send(msg)
console.log(i)
}
}
catch(e) {
console.log(e)
}
}
// main function combines all 3 functions (supabase is await)
async function main(){
let supabaseData = await supabaseNotifications();
let supabaseEmails = userEmail(supabaseData);
let sendgridEmails = sendEmail(supabaseEmails, supabaseData);
}
exports.sendgridNotifications = (event, context) => {
main()
};
my package.json with type module to use import above
{
"type":"module",
"dependencies":{
"#sendgrid/mail":"^7.6.1",
"#supabase/supabase-js":"1.30.0",
"#google-cloud/secret-manager": "^3.11.0"
}
}
I'm not at all versed in Google Secret Manager but a rapid look at the Node.js library documentation shows (if I'm not mistaking) that accessSecretVersion() is an asynchronous method.
As a matter of facts, we find in the doc examples like the following one:
async function accessSecretVersion() {
const [version] = await client.accessSecretVersion({
name: name,
});
// Extract the payload as a string.
const payload = version.payload.data.toString();
// WARNING: Do not print the secret in a production environment - this
// snippet is showing how to access the secret material.
console.info(`Payload: ${payload}`);
}
See https://cloud.google.com/secret-manager/docs/samples/secretmanager-access-secret-version#secretmanager_access_secret_version-nodejs

Code that worked on Replit doesn’t work in VSC

Basically, my code worked completely fine in replit, but now it doesnt work in a vsc folder. my replit version also suddenly can’t send any messages anymore. it sends all the console.logs but the client.say stuff it just skips without an error.
const tmi = require('tmi.js');
// Define configuration options
const opts = {
identity: {
username: 'BormBot',
password: 'cut out for a reason'
},
channels: [
'Epicurious__'
]
};
// Create a client with our options
const client = new tmi.client(opts);
const jsonFile = require('./link.json');
const fs = require('fs');
const mongoose = require('mongoose');
// Register our event handlers (defined below)
client.on('connected', onConnectedHandler);
// Connect to Twitch:
client.connect();
client.on('message', (channel, tags, msg, self, target) => {
if (self) return;
//start of geoguessr commands
const link = {
"link": ""
};
if (msg.startsWith('!geolink')) {
if (tags.badges.broadcaster == 1) {
const arguments = msg.split(/[ ]+/)
if (arguments[1]) {
let link = arguments[1];
const data = JSON.stringify(link);
fs.writeFile('./link.json', data, (err) => {
if (err) {
throw err;
}
console.log("JSON data is saved.");
});
client.say(channel, link);
} else {
console.log("no args");
}
}
}
if (msg.startsWith('!game')) {
// read JSON object from file
fs.readFile('./link.json', 'utf-8', (err, data) => {
if (err) {
throw err;
}
// parse JSON object
const linkDone = JSON.parse(data.toString());
// print JSON object
client.say(channel, `The link for the current geoguessr game is: ${linkDone}`);
console.log(`${linkDone}`);
});
}
//end of geoguessr commands
});
// Called every time the bot connects to Twitch chat
function onConnectedHandler(addr, port) {
console.log(`* Connected to ${addr}:${port}`);
}
console
Also on twitch developer forum: 2
On twitch developer forum there hasn't been an answer yet, hence why I'm also putting it on here. Hopefully I can find an answer, also, maybe add a tag for tmi.js

Do node js worker never times out?

I have an iteration that can take up to hours to complete.
Example:
do{
//this is an api action
let response = await fetch_some_data;
// other database action
await perform_operation();
next = response.next;
}while(next);
I am assuming that the operation doesn't times out. But I don't know it exactly.
Any kind of explanation of nodejs satisfying this condition is highly appreciated. Thanks.
Update:
The actual development code is as under:
const Shopify = require('shopify-api-node');
const shopServices = require('../../../../services/shop_services/shop');
const { create } = require('../../../../controllers/products/Products');
exports.initiate = async (redis_client) => {
redis_client.lpop(['sync'], async function (err, reply) {
if (reply === null) {
console.log("Queue Empty");
return true;
}
let data = JSON.parse(reply),
shopservices = new shopServices(data),
shop_data = await shopservices.get()
.catch(error => {
console.log(error);
});
const shopify = new Shopify({
shopName: shop_data.name,
accessToken: shop_data.access_token,
apiVersion: '2020-04',
autoLimit: false,
timeout: 60 * 1000
});
let params = { limit: 250 };
do {
try {
let response = await shopify.product.list(params);
if (await create(response, shop_data)) {
console.log(`${data.current}`);
};
data.current += data.offset;
params = response.nextPageParameters;
} catch (error) {
console.log("here");
console.log(error);
params = false;
};
} while (params);
});
}
Everything is working fine till now. I am just making sure that the execution will ever happen in node or not. This function is call by a cron every minute, and data for processing is provided by queue data.

How to use MongoDB locally and directline-js for state management in Bot Framework using NodeJs and Mongoose?

I am maintaining the bot state in a local MongoDB storage. When I am trying to hand-off the conversation to an agent using directline-js, it shows an error of BotFrameworkAdapter.sendActivity(): Missing Conversation ID. The conversation ID is being saved in MongoDB
The issue is arising when I change the middle layer from Array to MongoDB. I have already successfully implemented the same bot-human hand-off using directline-js with an Array and the default Memory Storage.
MemoryStorage in BotFramework
const { BotFrameworkAdapter, MemoryStorage, ConversationState, UserState } = require('botbuilder')
const memoryStorage = new MemoryStorage();
conversationState = new ConversationState(memoryStorage);
userState = new UserState(memoryStorage);
Middle Layer for Hand-Off to Agent
case '#connect':
const user = await this.provider.connectToAgent(conversationReference);
if (user) {
await turnContext.sendActivity(`You are connected to
${ user.userReference.user.name }\n ${ JSON.stringify(user.messages) }`);
await this.adapter.continueConversation(user.userReference, async
(userContext) => {
await userContext.sendActivity('You are now connected to an agent!');
});
}
else {
await turnContext.sendActivity('There are no users in the Queue right now.');
}
The this.adapter.continueConversation throws the error when using MongoDB.
While using Array it works fine. The MongoDB and Array object are both similar in structure.
Since this works with MemoryStorage and not your MongoDB implementation, I'm guessing that there's something wrong with your MongoDB implementation. This answer will focus on that. If this isn't the case, please provide your MongoDb implementation and/or a link to your repo and I can work off that.
Mongoose is only necessary if you want to use custom models/types/interfaces. For storage that implements BotState, you just need to write a custom Storage adapter.
The basics of this are documented here. Although written for C#, you can still apply the concepts to Node.
1. Install mongodb
npm i -S mongodb
2. Create a MongoDbStorage class file
MongoDbStorage.js
var MongoClient = require('mongodb').MongoClient;
module.exports = class MongoDbStorage {
constructor(connectionUrl, db, collection) {
this.url = connectionUrl;
this.db = db;
this.collection = collection;
this.mongoOptions = {
useNewUrlParser: true,
useUnifiedTopology: true
};
}
async read(keys) {
const client = await this.getClient();
try {
var col = await this.getCollection(client);
const data = {};
await Promise.all(keys.map(async (key) => {
const doc = await col.findOne({ _id: key });
data[key] = doc ? doc.document : null;
}));
return data;
} finally {
client.close();
}
}
async write(changes) {
const client = await this.getClient();
try {
var col = await this.getCollection(client);
await Promise.all(Object.keys(changes).map((key) => {
const changesCopy = { ...changes[key] };
const documentChange = {
_id: key,
document: changesCopy
};
const eTag = changes[key].eTag;
if (!eTag || eTag === '*') {
col.updateOne({ _id: key }, { $set: { ...documentChange } }, { upsert: true });
} else if (eTag.length > 0) {
col.replaceOne({ _id: eTag }, documentChange);
} else {
throw new Error('eTag empty');
}
}));
} finally {
client.close();
}
}
async delete(keys) {
const client = await this.getClient();
try {
var col = await this.getCollection(client);
await Promise.all(Object.keys(keys).map((key) => {
col.deleteOne({ _id: key });
}));
} finally {
client.close();
}
}
async getClient() {
const client = await MongoClient.connect(this.url, this.mongoOptions)
.catch(err => { throw err; });
if (!client) throw new Error('Unable to create MongoDB client');
return client;
}
async getCollection(client) {
return client.db(this.db).collection(this.collection);
}
};
Note: I've only done a little testing on this--enough to get it to work great with the Multi-Turn-Prompt Sample. Use at your own risk and modify as necessary.
I based this off of a combination of these three storage implementations:
memoryStorage
blobStorage
cosmosDbStorage
3. Use it in your bot
index.js
const MongoDbStorage = require('./MongoDbStorage');
const mongoDbStorage = new MongoDbStorage('mongodb://localhost:27017/', 'testDatabase', 'testCollection');
const conversationState = new ConversationState(mongoDbStorage);
const userState = new UserState(mongoDbStorage);

Resources