Node.js: Detecting a file, opened with fs.createWriteStream(), becoming deleted - javascript

Say I have the following Node program, a machine that goes "Ping!":
var machine = require('fs').createWriteStream('machine.log', {
flags : 'a',
encoding : 'utf8',
mode : 0644
});
setInterval(function () {
var message = 'Ping!';
console.log(message);
machine.write(message + '\n');
}, 1000);
Every second, it will print a message to the console and also append it to a log file (which it will create at startup if needed). It all works great.
But now, if I delete the machine.log file while the process is running, it will continue humming along happily, but the writes will no longer succeed because the file is gone. But it looks like the writes fail silently, meaning that I would need to explicitly check for this condition. I've searched the Stream docs but can't seem to find an obvious event that is emitted when this type of thing occurs. The return value of write() is also not useful.
How can I detect when a file I'm writing to is deleted, so I can try to reopen or recreate the file? This is a CentOS box, if that's relevant.

The writes actually do not fail.
When you delete a file that is open in another program you are deleting a named link to that file's inode. The program that has it open still points to that inode. It will happily keep writing to it, actually writing to disk. Only now you don't have a way to look it at, because you deleted the named reference to it. (If there were other references, e.g. hard links, you would still be able to!).
That's why programs that expect their log files to "disappear" (b/c of logrotate, say) usually support a signal (usually SIGHUP and sometimes SIGUSR1) that tells them to close their file (at which point it is really gone, because now there are no links to it anywhere) and re-create it.
You should consider something like that as well.

Related

How to inspect which js is consuming/decrypting websocket messages?

I've been trying to understand how the websocket messages are decrypted by js.
https://1win.com.ci/casino/play/aviator
The websocket messages really seem to be encrypted. For example:
gABuEgADAAFwEgACAAFwEgADAA1jdXJyZW50UGF5b3V0B0AUAAAAAAAAAARjb2RlBAAAAMgAD2N1cnJlbnRHYW1lVGltZQUAAAAAAABLyAABYwgAEWN1cnJlbnRNdWx0aXBsaWVyAAFhAwANAAFjAgE==
Decoding it to utf-8 does not return the needed info, so I'm trying to reverse engineer it to find out which js script is consuming the websocket messages and maybe find a way to decrypt it.
So far i've tried using Chrome Dev Tools by adding a breakpoint on the element that is modified (the big multiplier in the middle of the screen), but I couldn't find what part of the code consumes and maybe decrypts the message.
Any tips?
You will need to run some code before the page code runs, which can be done with either Chrome Local Overrides or a userscript.
It depends on how the page listens to messages. If it assigns to the onmessage property of the socket instance, you can overwrite the setter with your own setter that traces the caller - you could use console.trace, or throw new Error.
Object.defineProperty(WebSocket.prototype, 'onmessage', {
set(newVal) {
throw new Error();
}
});
Then just open the console, look at the stack trace of the thrown error, and you'll be in the general location of where the message gets parsed - perhaps the decryption is done there, or perhaps the payload gets passed to another function that does the decryption. If the page's script is large, it'll help to use a good IDE that allows you to jump to function definitions by their references. (eg, in VSCode - right click an identifier, then select Go to definition).
If the message listener gets attached with addEventListener instead, you can monkeypatch WebSocket.prototype.addEventListener and use the same technique.
WebSocket.prototype.addEventListener = function(eventName, callback) {
if (eventName === 'message') {
throw new Error();
}
};
One of the above approaches will show you where the message enters the page's script. Since you already know how to get to where the message exits the page script (and gets put into the DOM), you now have a starting point and an ending point, and can work backwards and forwards until they meet.
That's for the general approach. For this particular situation, it looks like it's encoded with some variation on Base64, because I can see that the payload in your question contains the words currentPayout, code, currentGameTime, and currentMultiplier.

Event like "DOMLastNodeRemoved" to prevent multiple executions of code

First of all: I know that there are some questions similar to this, but I could not found any alternative to it, but to ask.
Hello!
Is there any event like "DOMLastNodeRemoved" (or FirstNode, since u can't know for sure when it will be the last node removed) to prevent multiple executions of code?
Here's the deal, I'm using Genexus. The only way to make an event work in this weird SPA concept is using DOMNodeRemoved event.
But whenever you click a button, it will insert a lot of nodes, making the function execute like 25 times instead of just one.
Let's go to an example:
I'm currently with this code:
$(document).on("DOMNodeRemoved", function() {
$(".Button").click(function() {
setTimeout(
function() {
toastrgx();
$('.gx-warning-message').css('display', 'none');
}, 800);
});
function toastrgx() {
var meuLoader = new Loader($);
meuLoader.Insert();
setTimeout(function() {
meuLoader.Remove();
var text = $('.gx-warning-message').text();
toastr.error(text, '');
}, 500);
};
});
I need to use timeout because the DOM is still loading up the message.
Anyways, with this code I'll get this result presented in the image:
If i use something like preventPropagation (at least the way I used) it will run my code only once, but returns a lot of errors in the console (one for each execution) and also breaks my loader.
BTW, I have power only over one custom script, everything else is generated by Genexus.
So, if I use any other normal event like document.ready, it will fire the first time I load a page within my MasterPage, but, if I click in any other page, it will not fire the event again.
So, my question is:
There is any way to execute a code only once in my case?
Is it something that I'm not seeing clearly like another event or another way to make the code work?
If the question sounds silly, sorry, i'm a newbie in JS.
The way to go in this case is creating a User Control and using its show function, that is executed by the generated application every time the control should update (for example, when the page is loaded or when a property of the control is modified).
Why a User Control?
User Controls offer a standard interface to interoperate with GeneXus generated applications. This interface is well documented and abstracts you from the inner workings of the generated applications.
If you try to extend GeneXus by including scripts, you will be exposed to unexpected behavior and changes without previous notice.
How to create a User Control
To create a User Control I recommend using the GeneXus User Control Generator, for Atom. Using this Atom package you can easily create a GeneXus User Control.
Follow the steps to create a User Control and choose Web when prompted for the supported platforms by the package.
How to have code execute only once, when the page is loaded
After creating the User Control, open the src/<YourUserControlName>Render.js file and edit the show function this way:
this.show = function() {
if (!this.IsPostBack) {
// This code will be executed only, when the page is loaded.
}
}
Inside the if you can code whatever you need to execute only once per page.
How to deploy a User Control
To build and deploy the User Control to your GeneXus installation directory, follow the build process steps described in the package documentation.
Once you have deployed your User Control, you should include it in the master page object, to start using it, instead of the script you are using now.

writing console log to file up to a certain size

I currently have some code that's outputing A LOT of console.log lines. as of now I've been running it like this: node index.js > output.txt however, this isn't enough anymore since after a few hours the file becomes WAY too big to open in most editors.
Whats a better way to handle constant log creation in node? Is there a way to create a new log (with like output<TIMESTAMP>.txt) that would be created once the previous file reaches X size?
Pass your logs to a script rather than a file and handle the stream within your script for log rotation.
A good starting point is https://unix.stackexchange.com/questions/231486/how-to-implement-logrotate-in-shell-script

selenium + chrome.fileSystem.chooseEntry = invalid calling page error

I am writing a Selenium script to test a Chrome app that uses the Chrome.fileSystem.chooseEntry API to select a directory. When I do this manually, it works fine. But when I do this in a Selenium script, I get back this error:
Unchecked runtime.lastError while running fileSystem.chooseEntry: Invalid calling page. This function can't be called from a background page.
Any ideas on how to make Selenium and chooseEntry play nicely together?
I updated to the latest Chromedriver, but still no luck. I also looked at ChromeOptions, but didn't see anything that looked like it would be helpful. The interwebs doesn't seem to have much to say about Selenium and chooseEntry. I'm on version 51 of Chrome.
I'm down to thinking I'll need a special javascript entry point to set the path values for testing instead of using chooseEntry. But I would strongly prefer to not have a separate code execution path for my tests. Anybody have a cleaner solution?
EDIT: per commenter's request, here's the offending code:
chrome.fileSystem.chooseEntry({type:'openDirectory'},function(entry) {
chrome.fileSystem.getWritableEntry(entry,function(writeable_entry) {
console.log("got writeable entry");
});
}, function(e) { errorHandler(e); });
EDIT #2: I've gone with the special javascript entry point hack. In manual mode -- i.e., not running under Selenium -- I run code that executes chooseEntry, and then use the retainEntry API to get the entry id. I added an entry point in my javascript to take an entry id and call the restoreEntry API to turn it back into an entry. I also modified my code so if this entry object is set, then use that as the file instead of calling chooseEntry. Lastly, I modified my Selenium script to call the restoreEntry entry point before running the rest of the script.
This is not ideal, since now my test code execution path is somewhat different from my actual live-human-being-at-the-controls code execution path. But at least it lets me use Selenium scripts now. Of course, if anyone can think of a non-horrible way to solve this solution, I'd love to hear about it.
EDIT #3: Per #Xan's comment, corrected my terminology from "extension" to "Chrome App."
I can only offer this horrible hack. For Chrome Apps under OSX I created folder favorites and use Robot keyPress to navigate and select the 'favorite' folders needed for the App. The only possible redeeming factor is that it does mirror a valid/possible actual human interaction with the file interface.
private void selectOSXFolderFavorite(int favorite) {
// With an OSX file folder dialog open, Shift-Tab to favorites list
robot.keyPress(KeyEvent.VK_SHIFT);
robot.keyPress(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_TAB);
robot.keyRelease(KeyEvent.VK_SHIFT);
// move to the top of favorites list
int i = 40;
while (i-- > 0) {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
while (favorite-- > 0) {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
// Send an enter key to Select the selected folder
robot.keyPress(KeyEvent.VK_ENTER);
robot.keyRelease(KeyEvent.VK_ENTER);
}

Writing to File Sometimes Failing in Windows 10 Universal Javascript App

I've developed a Universal App for Windows. It is deployed in my business, not through the App Store. It's perfectly functional 99.9% of the time.
But there's this one problem that's happened a couple of times.
I store persistent data in JSON format in my application local data folder.
To store my data, I use:
var storeData = function () {
return WinJS.Application.local.writeText('data', JSON.stringify(dataObject));
}
And to load my data, I use:
var loadData = function () {
return WinJS.Application.local.readText('data').then(function (text) {
dataObject = text ? JSON.parse(text) : {};
})
}
There's been a couple of cases where, during the loadData method, my app crashes. When I researched why it crashed, it turns out that there's an extra file in my local appdata folder. Obviously the file that's supposed to be there is called 'data' -- this extra file is called something like 'data-84DB.TMP' or something like that -- obviously a temporary file created as part of the file io API. In these cases where my app is crashing, this file has the information in it that you'd normally expect to see in the 'data' file, and the 'data' file is no longer in text format and when I open it in SublimeText it says '0000'.
So when my loadData function runs, it crashes.
Now, this is not a situation in which I want it to fail silently. I'd rather it crash than, say, just do a try-catch in loadData and make my dataObject empty or something in the cases where the data didn't save right. I'd rather it crash, so that then at least I can go and find the .TMP file and restore the information that didn't properly save.
Is this problem normal? Am I not following best practices for reading and writing persistent data? How can I fix this issue? Do you guys know what causes it? Might it be that the app unexpectedly shuts down in the middle of a file-writing operation?
I think the best practice should be to do reads and saves asynchronously. I guess WinJS.Application.local is a wrapper for WinRT API, but it works synchronously. I would suggest to use Windows.Storage.FileIO.writeTextAsync and Windows.Storage.FileIO.readTextAsync.
Also I found out that JSON.parse crashes (throws an error) when the string to parse is empty (""). In your case I see that it can be a problem as well since you're testing only if it's null or undefined, not if it's empty.

Categories