generate buffer before `unload` - buffer

I'm tracking events in a web page using RxJs and sending them through buffer.
I emit a buffer on unload event, but it's done after the event is triggered, so it's never triggered.
Is there a way to generate everything related to my buffer on unload ?
/* globals $ */
import { Observable } from 'rx-dom'
import { Load, Unload } from './events'
$(function () {
const load$ = (new Load()).observer$() // triggered on page load
const unload$ = (new Unload()).observer$() // triggered on page unload
const source$ = Observable.merge(load$, unload$)
const intervalBetween = 5000
const dummyStart$ = Observable.return({})
const bufferizeEvents$ = [submit$, unload$]
const opening$ = dummyStart$
.concat.apply(dummyStart$, bufferizeEvents$)
.flatMapLatest(x => Observable.timer(0, intervalBetween))
.skip(1)
const buffers$ = source$.buffer(opening$)
buffers$.subscribe(buffer => {
if (buffer.length) {
// some ajax call
// this is never reached on page unload
}
})
})

Related

control Electron instances

Wanted to check how many instances are running and control the number of instances running in one exe electron bundle. Let us say I wanted to allow only three instances running for the one exe bundle. I am not able to do this.
Current Behavior:
Only one and remaining can block. Or open for any number of instances. We need to control only three instances running, not more than that.
Example:
const { app } = require('electron')
let myWindow = null
const gotTheLock = app.requestSingleInstanceLock()
if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (myWindow) {
if (myWindow.isMinimized()) myWindow.restore()
myWindow.focus()
}
})
// Create myWindow, load the rest of the app, etc...
app.on('ready', () => {
})
}
You can try with the following code to know how many windows have been opened.
const count = BrowserWindow.getAllWindows().length;
To check visible windows, you can try the following code
let count = BrowserWindow.getAllWindows()
.filter(b => {
return b.isVisible()
}).length
Once you get the number of instances, based upon the condition for number of instance, ie. if it is more than 3, you can quit using app.quit().
You can make each instance write to a file (increment a counter for example) when the instance starts and when it exits. (decrement the counter). You should check that file to see if the maximum number of instances are running
import { app } from "electron";
import path from "path";
import fs from "fs";
const MAX_APP_INSTANCES = 3;
const INSTANCE_COUNT_FILE_PATH = path.join(
app.getPath("userData"),
"numOfInstances"
);
// utils to read/write number of instances to a file
const instanceCountFileExists = () => fs.existsSync(INSTANCE_COUNT_FILE_PATH);
const readInstanceCountFile = () =>
parseInt(fs.readFileSync(INSTANCE_COUNT_FILE_PATH, "utf-8"));
const writeInstanceCountFile = (value) =>
fs.writeFileSync(INSTANCE_COUNT_FILE_PATH, value);
const incInstanceCountFile = () => {
const value = readInstanceCountFile() + 1;
writeInstanceCountFile(value.toString());
};
const decInstanceCountFile = () => {
const value = readInstanceCountFile() - 1;
writeInstanceCountFile(value.toString());
};
// logic needed to only allow a certain number of instances to be active
if (instanceCountFileExists() && readInstanceCountFile() >= MAX_APP_INSTANCES) {
app.quit();
} else {
if (!instanceCountFileExists()) {
writeInstanceCountFile("1");
} else {
incInstanceCountFile();
}
app.on("quit", () => decInstanceCountFile());
}
Note: this is solution is somewhat hacky. For example, the quit event is not guaranteed to fire when the Electron app exits

Dart - Get the last or the first value of a stream

I have a stream and I need to use the last value of this stream, and if there is no value emitted by this stream I need to wait for the fist value. I only want to use this value once. What is the correct way to do it?
Sounds like you want the most recent event emitted by a stream (which is presumably a broadcast stream, because otherwise there is no events until you listen), or, if there has been no events before, you want the next event instead.
For a plain Dart Stream, that's impossible. It doesn't remember previous events. You need to have listened to that stream previously in order to know what the most recent event was (but if you do that, it doesn't have to be a broadcast stream anyway).
You can build your own memorizing stream wrapper fairly easily (but as always with asynchronous programming, you need to be careful about race conditions)
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
import "dart:async";
/// Listens to [source] to returned stream.
///
/// Each listener on the returned stream receives the most recent
/// event sent on [source] followed by all further events of [source]
/// until they stop listening.
/// If there has been no events on [source] yet, only the further events
/// are forwarded.
Stream<T> mostRecentStream<T>(Stream<T> source) {
var isDone = false;
var hasEvent = false;
T? mostRecentEvent;
List<MultiStreamController>? pendingListeners;
var listeners = <MultiStreamController>[];
void forEachListener(void Function(MultiStreamController) action) {
var active = 0;
var originalLength = listeners.length;
for (var i = 0; i < listeners.length; i++) {
var controller = listeners[i];
if (controller.hasListener) {
listeners[active++] = controller;
if (i < originalLength) action(controller);
}
}
listeners.length = active;
}
source.listen((event) {
mostRecentEvent = event;
hasEvent = true;
forEachListener((controller) {
controller.addSync(event);
});
}, onError: (e, s) {
forEachListener((controller) {
controller.addErrorSync(e, s);
});
}, onDone: () {
isDone = true;
for (var controller in listeners) {
controller.close();
}
listeners.clear();
});
return Stream<T>.multi((controller) {
if (hasEvent) controller.add(mostRecentEvent as T);
if (isDone) {
controller.close();
} else {
listeners.add(controller);
}
});
}
With that, you can simply do var recentStream = mostRecentStream(yourStream) and then later do recentStream.first to get either the most recent event or, if there is none, the next event (if there is one, you get an error if the stream is completely empty).

Aurelia, Electron: Possible EventEmitter memory leak detected

I'm building a system resource monitor as a project using electron and aurelia.
Main.js
var ramInfo = {};
var result = await si.mem()
ramInfo.total = parseInt(result.total / 1024 / 1024);
ramInfo.used = parseInt(result.used / 1024 / 1024);
ramInfo.percentUsed = parseInt((ramInfo.used / ramInfo.total) * 100);
ramInfo.percentAvailable = parseInt((ramInfo.percentUsed - 100) * -1);
event.sender.send('ram-reply', ramInfo);
})
Overview.js:
async attached () {
await this.getRamInfo();
this.startDataRefresh();
}
async getRamInfo () {
window.ipc.send('ram');
await window.ipc.on('ram-reply', (event, result) => {
this.system.ram = result;
//This line gets logged an additional time each time the setInterval function runs
console.log(this.system.ram);
this.ramData.series = [this.system.ram.percentAvailable, this.system.ram.percentUsed];
new Chartist.Pie('.ram-chart', this.ramData , this.options);
});
console.log("Break");
}
startDataRefresh() {
let scope = this;
setInterval(function() {
scope.getRamInfo();
}, 3000);
}
I am receiving the folowing error in my electron console:
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 ram-reply listeners added to [EventEmitter]. Use emitter.setMaxListeners() to increase limit
I would only think that the getRamInfo() function would run once every three seconds, however, the console.log portion of the function is getting logged an additional time each time the function runs. I'm fairly certain this is where the issue lies, I'm just not sure why it is running multiple times per interval.
EDIT:
I've reached a partial solution in moving the setInterval function into main.js:
ipcMain.on('ram', async (event) => {
setInterval(async function() {
var ramInfo = {};
var result = await si.mem()
ramInfo.total = parseInt(result.total / 1024 / 1024);
ramInfo.used = parseInt(result.used / 1024 / 1024);
ramInfo.percentUsed = parseInt((ramInfo.used / ramInfo.total) * 100);
ramInfo.percentAvailable = parseInt((ramInfo.percentUsed - 100) * -1);
event.sender.send('ram-reply', ramInfo)
}, 3000);
})
It seems like each time the original setInterval called to ipcMain this created a new listener and each time every listener returned the results. I would like it to be dependant on the view that is open so controlling this via the view would be preferable.
Try this:
async getRamInfo () {
window.ipc.send('ram');
return new Promise(resolve => window.ipc.once('ram-reply', (event, result) => resolve(result));
}
async refresh() {
const ramInfo = await this.getRamInfo();
this.ramData.series = [this.system.ram.percentAvailable, this.system.ram.percentUsed];
new Chartist.Pie('.ram-chart', this.ramData , this.options);
// ...
}
startDataRefresh() {
if(!this.interval) {
this.interval = setInterval(() => this.refresh(), 3000);
}
}
stopDataRefresh() {
if(this.interval) {
clearInterval(this.interval);
delete this.interval;
}
}
main part - window.ipc.once('ram-reply' - use once for one-time event subscription

How to use ipcRender inside executeJavascript?

I tried just simply putting the ipcRenderer message inside of executeJavascript but it returned
ipcRenderer is not defined
my ipcRender is defined using window.ipcRenderer:
const { ipcRenderer, remote } = require('electron');
window.ipcRenderer = ipcRenderer;
//and then
remote.getCurrentWebContents().executeJavaScript(`settingsDiv.addEventListener('click', function() { ipcRenderer.send('test','ayy'); } );`)
This is loaded as a preloaded script for a webpage.
There is no need to take that path on a preload.
Something like this should work instead:
const { ipcRenderer } = require('electron');
document.addEventListener('DOMContentLoaded', (event) => {
const settingsDiv = document.querySelector('<?>'); // replace <?> with your selector for that div element
settingsDiv.addEventListener('click', () => {
ipcRenderer.send('test', 'ayy');
});
}
(the preload runs first, then the page is rendered. So we have to wait until the DOM content is loaded and the div is available)

Twilio Studio Not Listing Services

I am setting up a Sync Application using Twilio's Sync Library. For some reason, none of the REST API methods seem to work. That is, I cannot get any of the sync methods to console.log() anything via the runtime functions.
I can, however, console.log() plain text.
Here is my code:
exports.handler = function(context, event, callback) {
// 0. Init
// const phoneNumber = event.phoneNumber;
const issueLimit = 3; // CHANGE IF NEEDED
const listName = 'issues';
const twilioClient = context.getTwilioClient();
// 1. List all lists
twilioClient.sync.services(context.SYNC_SERVICE_SID)
.syncLists
.list({limit: 20})
.then(syncLists => syncLists.forEach(s => console.log(s.sid)));
// 2. return true if quota reached
console.log("Got to here");
// 3. return false
callback(null, undefined);
};
The only code that appears to execute is the 'console.log("Got to here");'. I'm also not receiving any error messages.
Any guidance is sincerely appreciated.
When you see .then(), that's a promise, and you can read more about this here https://www.twilio.com/blog/2016/10/guide-to-javascript-promises.html
In other words, the JavaScript engine goes to your steps 2. and then 3. without waiting for 1. to finish. And since you're returning at step 3 with callback(null, undefined); you won't see the logs.
So, you'll have to move callback() inside the .then(), something like this:
exports.handler = function (context, event, callback) {
// 0. Init
// const phoneNumber = event.phoneNumber;
const issueLimit = 3; // CHANGE IF NEEDED
const listName = 'issues';
const twilioClient = context.getTwilioClient();
// 1. List all lists
twilioClient.sync.services(context.SYNC_SERVICE_SID)
.syncLists
.list({ limit: 20 })
.then(
function (syncLists) {
console.log("Got to here");
syncLists.forEach(s => console.log(s.sid));
callback(null, undefined);
}
);
};

Resources