Exit from express, nodejs programme on button click - node.js

I have created a file import functionality using nodejs,express and socket.io. Everything is working fine but now I have to implement a feature in which , user clicks on a button and on click of this button, I want to cancel/stop the execution of code (wherever the control is at that moment, should not execute further). I have tried return, res.end(), res.send(), eventEmitter, throw error etc but script processing is not getting stopped. On using process.exit, code execution stops but it shutdown for all users no matter from where they are operating(i.e if 5 users are using import feature, code executions stops for all five users). Can anybody have any other suggestions?

You can make an interval checking the if the state of the button (button click should change a flag) once you check the flag you can resolve your function ( the function should be a promise) and then it will stop the execution of the code example:
let flag = false
function test(){
return new Promise((res, rej)=>{
let interval = setInterval(()=>{
if (flag){
res();
}
},1000)
/*rest of code goes here*/
})
}

Related

How to detect that Chrome Extension with Manifest v3 was unloaded

Our Chrome extension has both content and background scripts communicating with each other. When the plugin is updated, the background script is stopped and the content scripts start getting Error: Extension context invalidated.. In V2, we used port.onDisconnect event as described here to clean things up. But in V3, this event is also sent after 5 minutes (when the background service worker is automatically terminated). So this event now means either extension unloading (and the cleanup should be done), or just SW lifecycle event (no need to cleanup, reconnecting is fine).
So the question is, how to unambiguously determine whether the cleanup is necessary.
I've tried:
chrome.management. events: onDisabled etc. But unfortunately chrome.management is undefined in my content script.
Checking for chrome.runtime.id inside port.onDisconnected callback to determine the plugin is unloaded. But the id is still present at that moment.
Again inside port.onDisconnected, trying to do chrome.runtime.connect() again and catching the exception. But there's no exception! The port is created successfully, but it receives neither messages nor its own onDisconnected events.
Trying point 3 inside setTimeout(..., 0) and setTimeout(..., 100). The former doesn't produce exceptions either. The latter does, but it introduces a delay of questionable duration (why 100? would it work the CPU is overloaded?) and potential race conditions when other plugin functionality could try to send messages with unpredictable results. So I'd appreciate a more bullet-proof solution.
Thanks to wOxxOm's suggestions, I've found a solution that seems to work for now: every once in a while (<5 seconds) to disconnect the port in the content script and then reconnect again. The code looks like this:
let portToBackground: chrome.runtime.Port | undefined = openPortToBackground();
function openPortToBackground(): chrome.runtime.Port {
const port = chrome.runtime.connect();
const timeout = setTimeout(() => {
console.log('reconnecting');
portToBackground = openPortToBackground();
port.disconnect();
}, 2 * 60 * 1000); // 2 minutes here, just to be sure
port.onDisconnect.addListener(() => {
clearTimeout(timeout);
if (port !== portToBackground) return;
// perform the cleanup
});
return port;
}
export function isExtensionContextInvalidated(): boolean {
return !portToBackground;
}

How to initialize Chrome extension context menus under Manifest V3 service workers? [duplicate]

I'm working on a simple link sharing extension (pinboard, readability, delicious, etc), and have a question about how to properly deal with a context menu item. In my non-persistent background page I call chrome.contextMenus.create and chrome.contextMenus.onClicked.addListener to setup/respond to the context menu.
The context menu entry works as expected. But the background page is showing the following error (right after it starts and before I've used the entry) :
contextMenus.create: Cannot create item with duplicate id id_share_link at chrome-extension://.../share.js:52:30 lastError:29 set
This made me realize that at no point do I remove the item or the listener. Knowing little about javascript and extensions, I'm left wondering if I'm doing everything correctly. I'm assuming this top-level code is going to re-execute every time the background page is invoked. So there are going to be redundant calls to create and addListener (and hence the error I see being logged).
I clearly can't do cleanup in response to suspend, as these calls need to be present to wake up the background script.
Should I be handling things differently?
If you want to use an event page, ie a non-persistent background page, as you call it, you should register a context menu via contextMenus.create in the event handler of runtime.onInstalled, as these context menu registrations ”persist“ anyways.
You have to add the listener-function for the contextMenus.onClicked event every time the event page gets reloaded, though, as the registration of your wish to listen on that event persists, while the handler callback itself does not. So generally don't call contextMenus.onClicked.addListener from runtime.onInstalled, but from top level or other code, that is guaranteed to be executed each time the event page loads.[1]
You can handle it one of two ways:
You can add the context menu and the listeners on install using:
chrome.runtime.onInstalled.addListener(function() {
/* Add context menu and listener */
});
You can remove the context menu and listener, and then re-add it each time the file is called.
[solution may no longer be the case, read comment]
runtime.onInstalled is not triggered if you disable/enable your extension.
My solution is to always add menu items and swallow errors:
'use strict';
{
let seqId = 0;
const createMenuLinkEntry = (title, tab2url) => {
const id = (++seqId).toString();
chrome.contextMenus.create({
id: id,
title: title,
contexts: ['browser_action'],
}, () => {
const err = chrome.runtime.lastError;
if(err) {
console.warn('Context menu error ignored:', err);
}
});
};
createMenuLinkEntry('Go to Google', (tab) => 'https://google.com');
createMenuLinkEntry('Go to GitHub', (tab) => 'https://github.com');
} // namespace

How to show a page on install but not on update [duplicate]

I have a question about chrome extension install/update event. If I add the onInstalled event listener in a top level code in the background script, is there a time frame in which my event listener will catch that event?
I'm asking this, because my demos showed that if I have some logic that executes before I hook onInstalled listener, it looks like it will never be executed, like that event happens in the meantime.
Can someone explain to me with more details how this event works, in the context of other logic in the background script, or point me to some documentation, since I haven't been able to find anything useful.
Thanks!
Update #Noam Hacker : Due to a company policy I can't post any real code here, but I have some pseudo code that illustrates my problem :
/**
* setup in which I miss onInstalled event
*/
function firstLogicThatRunsOnBackgroundLoad() {
// perform some logic
// perform some asynchronous operations via generators and promises
// which can take a while
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
// this logic never gets executed
} else if(details.reason == "update") {
// perform some logic
}
});
}
/**
* setup in which I catch onInstalled event
*/
function firstLogicThatRunsOnBackgroundLoad() {
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install") {
// this logic executes
} else if(details.reason == "update") {
// perform some logic
}
});
// perform some logic
// perform some asynchronous operations via generators and promises
// which can take a while
}
onInstalled listeners catch events in these situations:
when the extension is first installed, when the extension is updated to a new version, and when Chrome is updated to a new version.
Since this is all asynchronous it will happen in the background, and according the documentation, fires immediately at any of these situations. Review asynchronous programming for some clarity on this.
link to documentation
According to your question it seems like you want help executing code in the right order. This answer provides a helpful framework for your case (using the reason attribute).
chrome.runtime.onInstalled.addListener(function(details){
if(details.reason == "install"){
//call a function to handle a first install
}else if(details.reason == "update"){
//call a function to handle an update
}
});
I needed to figure this out too. While I didn't find anything authoritative, I did throw a couple of console.time() statements in my background script.
Code was something like this:
console.time('onInstall event');
console.time('first function');
chrome.runtime.onInstalled.addListener(details => {
console.timeEnd('onInstall event');
});
// 7 module imports
someSyncFunction() // console.timeEnd('first function') is called in the first line in this function
Then I just loaded/reloaded the extension (unpacked, in dev mode) a few times. onInstall seems to pretty reliably fire within the first 50ms, while the first function happens w/in the first ms. Here are the results:
(First function, onInstall event)
(.282ms, 47.2ms)
(.331ms, 45.3ms)
(.327ms, 49.1ms)
(.294ms, 45.9ms)
Given that the document says
“Listeners must be registered synchronously from the start of the page.”
and
“Do not register listeners asynchronously, as they will not be properly triggered.”
, it seems they guarantee every synchronously-attached listener not to miss any, no matter how long it takes to evaluate your code. And this would be done by Chrome firing events after evaluating your entire code.
My hypothesis is that onInstalled actually works like onInitialized. No test data, though.

Why won't my suitescript deploy scripts fire?

I don't know when this started, but I think it happened after I did some refactoring using the IDE with renaming.
Anyway, if I attach the script through the form, they fire. However, my user event, nor client scripts fire though there is a deployment record. That deployment record uses the same script that works IF it is attached via the form custom code area.
What happened?
EDIT:
For Instance:
Trying to add a button to opportunity:
function userEventBeforeLoad(type, form, request){
var list = form.getSubList("item");
list.addButton('custpage_customconfigurebutton', 'Configure', 'clientStartConfigurator()');
}
Upload Script
Add to "Script"
Deploy:
It never fires when I "Create Opportunity"?
NONE of my user event scripts are firing
EDIT 2 (NEW SCREENS as requested
Following lines of code working for me
function userEventBeforeLoad(type, form, request) {
//nlapiLogExecution('error', 'type', type);
var list = form.getSubList("item");
list.addButton('custpage_customconfigurebutton', 'Configure',"alert('Hello World')");
}
I suspect you might have an error in your clientStartConfigurator(). To verify, you can also use the browser console on click of your button to see whether you're successfully returning from your respective function or not.
Hope this will help you.

Node.js res.send is not working

In my index.js, I have an exports function that is supposed to send data back to the client via ajax on pressing a submit button. However, when the user presses submit, the data seems to get sent over before it the data gets modified. When pressing submit one more time, it sends the data that was previously modified as if clicking the submit button only sends the 'previously' set data. This is my code:
var tabledata = getRecordFromDatabase(key);
if(tabledata.length === 0)
tabledata = 'There is no matched record in the database';
res.contentType('text/html');
res.send({'matched':tabledata});
So to illustrate the error: I click submit after filling out a form and receive back the message "There is no matched record in the database". I hit submit a second time without changing anything in the form I just filled. This time record data is actually sent to me. Why could this be?
If whatever you're doing in getRecordFromDatabase is asynchronous and non-blocking, then node.js is behaving as it should. Node.js is non-blocking - it doesn't stop and wait for processes to complete (unless those processes are intentionally written to block, which is usually avoided in node.js). This is beneficial, because it keeps the server free to accept new requests and process many requests at once.
If your database call is asynchronous, you're not waiting for it to return before you res.send(). That's why your first submit returns back empty. Most likely, by the time you hit submit a second time, your DB call has finally returned, and that's why you get a result.
It's hard to give you a code-based answer to your problem, because you abstracted away what is happening in your DB call method. But typically, an asynchronous call would go something like:
getRecordFromDatabase(key, function(err, data){
if(data.length === 0)
data = 'There is no matched record in the database';
res.contentType('text/html');
res.send({'matched':data});
});
This way, you are passing a function to execute as a callback to your asynchronous method - when the async call completes, it executes the callback, which then executes the res.send() with the appropriate data.

Resources