How to send a result to sender via contextBridge / IPCRenderer? - electron

I have a electron that looks like this
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
electronStore: {
get(val) {
ipcRenderer.send('electron-store-get', val);
},
set(property, val) {
ipcRenderer.send('electron-store-set', property, val);
},
// Other method you want to add like has(), reset(), etc.
},
});
and ipcMain that looks like this
ipcMain.on('electron-store-get', async (event, val) => {
store.get(val);
// console.log(reply);
// return reply;
// event.reply('electron-store-get', reply);
});
ipcMain.on('electron-store-set', async (event, property, val) => {
// console.log(val);
store.set(property, val);
});
When I was trying to call the function via electron.electronStore.get(), it returns undefined
let a = window.electron.electronStore.get('test');
console.log(a);
However, I've tested that on the line of ipcRenderer.send(""), I was able to receive data by setting as below
let result = ipcRenderer.send('electron-store-get',val);
console.log(result);
Which mean, ipcRenderer is not undefined and set has been successfuly, get as-well, just it went missing when i invoke the ipcMain Get functions

Your current preload API isn't actually returning anything:
get(val) {
ipcRenderer.send('electron-store-get', val);
}
You'll want to either use the synchronous API: return ipcRenderer.sendSync('electron-store-get', val) and then have your handler in main do:
ipcMain.on('electron-store-get', (event, val) => {
event.returnValue = store.get(val);
});
Or make the preload API async:
get(val) {
return ipcRenderer.invoke('electron-store-get', val);
}
ipcMain.handle('electron-store-get', (event, val) => {
return store.get(val);
});
And then:
let a = await window.electron.electronStore.get('test');

Related

How to respond with a stream in a Sveltekit server load function

Below I try to respond with a stream when I receive ticker updates.
+page.server.js:
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(ticker.price);
});
}
});
export async function load() {
return response????
};
Note: The YahooFinanceTicker can't run in the browser.
How to handle / set the response in the Sveltekit load function.
To my knowledge, the load functions cannot be used for this as their responses are JS/JSON serialized. You can use an endpoint in +server to return a Response object which can be constructed from a ReadableStream.
Solution: H.B. comment showed me the right direction to push unsollicited price ticker updates the client.
api route: yahoo-finance-ticker +server.js
import YahooFinanceTicker from "yahoo-finance-ticker";
const ticker = new YahooFinanceTicker();
const tickerListener = await ticker.subscribe(["BTC-USD"])
/** #type {import('./$types').RequestHandler} */
export function GET({ request }) {
const ac = new AbortController();
console.log("GET api: yahoo-finance-ticker")
const stream = new ReadableStream({
start(controller) {
tickerListener.on("ticker", (ticker) => {
console.log(ticker.price);
controller.enqueue(String(ticker.price));
}, { signal: ac.signal });
},
cancel() {
console.log("cancel and abort");
ac.abort();
},
})
return new Response(stream, {
headers: {
'content-type': 'text/event-stream',
}
});
}
page route: +page.svelte
<script>
let result = "";
async function getStream() {
const response = await fetch("/api/yahoo-finance-ticker");
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const { value, done } = await reader.read();
console.log("resp", done, value);
if (done) break;
result += `${value}<br>`;
}
}
getStream();
</script>
<section>
<p>{#html result}</p>
</section>

Is there a way to have my service worker intercept fetch requests coming from a client-side SvelteKit load function? (+page.ts)

I'm trying to have a service worker intercept fetch requests coming from a client-side SvelteKit load function. The network requests are being made, but the fetch event is not being triggered.
The fetch request from the load function is going to /api/allTeams, which is cached as reported by chrome devtools, but like I said, it's not getting intercepted. All the function does it fetch the data, and return it in a prop.
Also, every couple minutes I run invalidateAll(), to reload the data, and even those requests aren't being picked up by the SW.
Thanks!
--reese
src/service-worker.js:
import { build, version } from '$service-worker';
self.addEventListener('fetch', function (event) {
console.log("fetch")
event.respondWith(
fetch(event.request).catch(function () {
return caches.match(event.request);
}),
);
});
self.addEventListener('install', async function (event) {
event.waitUntil(
caches.open("ccs-" + version).then(function (cache) {
cache.add("/api/allTeams")
cache.addAll(build)
return;
}),
);
});
src/app.html:
<script>
const registerServiceWorker = async () => {
if ("serviceWorker" in navigator) {
try {
const registration = await navigator.serviceWorker.register("/service-worker.js", {
scope: "*",
});
if (registration.installing) {
console.log("Service worker installing");
} else if (registration.waiting) {
console.log("Service worker installed");
} else if (registration.active) {
console.log("Service worker active");
}
} catch (error) {
console.error(`Registration failed with ${error}`);
}
}
};
registerServiceWorker()
</script>
src/+page.ts:
export async function load(request: Request) {
const searchQuery = new URL(request.url).searchParams.get("q")
const apiUrl = new URL(request.url)
apiUrl.pathname = "/api/allTeams"
const req = await fetch(apiUrl)
const data = await req.json()
return {data, searchQuery};
}

OData V2 SetProperty in onInit

I need to set the property to DataSet during onInit, to change the visiblity of some controls in my View. I could solve this problem with setting the visibility dynamically in controller. But I want to use the expression binding and the visible property in the View to set visibilites.
I'm getting an error in the function OnStartSetVisibilites. self.getView().getBindingContext() returns UNDEFINED. Without the sPath, I can't use setProperty. And without setProperty, my View-Controls don't know the visible-value.
How to fix this?
View:
<uxap:ObjectPageSubSection visible="{= ${Responsible} === '1'}" id="leader">
</uxap:ObjectPageSubSection>
OnInit in View-Controller:
onInit: function () {
var startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
var sWorkitem = startupParameters.TASK[0];
this.setModel(this.getOwnerComponent().getModel());
this.getModel().metadataLoaded().then(function () {
var sObjectPath = this.getModel().createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: "/" + sObjectPath
});
}.bind(this));
var self = this;
var model = this.getOwnerComponent().getModel();
this.getModel().read("/CharSet", {
success: function (response) {
$.sap.Chars = response.results;
self.onStartSetVisibilities(model, self);
}
});
// self.getView().attachAfterRendering(function () {
// self.onStartSetVisibilities(model, self);
// });
}
OnStartSetVisibilities:
onStartSetVisibilities: function (model, self) {
var char = model.getProperty(ā€˛GeneralData/Char");
if (char !== "" || char !== null) {
model.setProperty(self.getView().getBindingContext().sPath + "/Responsible",
this.getResponsibleForChar(char));
}
}
I put together some code which might solve your issue (it's untested so it may contain syntax errors!).
I introduced the concept of Promises which simplifies the asynchronous behavior of JS. I also replaced some of the inner functions with Arrow functions so you don't have to deal with that or self. Arrow functions basically use the this of the scope they are defined within.
Your app should now have a proper flow.
First you bind the view.
After the view is bound you read the CharSet.
After the data is read you set the visibility stuff
onInit: function () {
const startupParameters = this.getOwnerComponent().getComponentData().startupParameters;
const sWorkitem = startupParameters.TASK[0];
this._bindView(sWorkitem)
.then(() => this._readCharSet())
.then(() => this._setVisibilities())
},
_bindView: function (sWorkitem) {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.metadataLoaded().then(() => {
const sPath = "/" + oModel.createKey("DataSet", {
Workitem: sWorkitem
});
this.getView().bindElement({
path: sPath,
events: {
change: resolve,
dataReceived: resolve
}
});
});
});
},
_readCharSet: function () {
return new Promise((resolve) => {
const oModel = this.getOwnerComponent().getModel();
oModel.read("/CharSet", {
success: resolve
});
});
},
_setVisibilities: function () {
const oModel = this.getOwnerComponent().getModel();
const sChar = oModel.getProperty("GeneralData/Char");
if (sChar) {
// ...
}
}

Unable to access Work Item Tracking services Azure DevOps Extensions

I am rendering extension on the Work item page using
<WebpageControlOptions AllowScript="true" ReloadOnParamChange="true">
<Link UrlRoot="http://.../extension/Validate-extension/1.0.69/assetbyname/workItemNotifications.html"/>
</WebpageControlOptions>
Following is the html/js code:
var workItemID = 0;
VSS.init({
explicitNotifyLoaded: true,
usePlatformScripts: true
});
VSS.ready(function () {
var currentContext = VSS.getWebContext();
VSS.register(VSS.getContribution().id, function (context) {
return {
// event handlers, called when the active work item is loaded/unloaded/modified/saved
onFieldChanged: function (args) {
if (!changedFields[args.id]) {
changedFields[args.id] = [];
changedFieldCount[args.id] = 0;
}
$.each(args.changedFields, function (key, value) {
if (!changedFields[args.id][key]) {
changedFields[args.id][key] = value;
changedFieldCount[args.id]++;
}
});
},
onLoaded: function (args) {
console.log("OnloadNotification");
VSS.require(["TFS/WorkItemTracking/Services"], function (workItemServices) {
workItemServices.WorkItemFormService.getService().then(function (workItemFormSvc) {
if (workItemFormSvc.hasActiveWorkItem()) {
console.log("Active work item is available.");
workItemFormSvc.getFieldValues(["System.Id"]).then(
function (value) {
var val = JSON.stringify(value);
$.each(value, function (key, values) {
if(key == "System.Id"){
workItemID = values;
}
});
});
}
else {
console.log("Active work item is NOT available.");
}
});
});
},
onUnloaded: function (args) {
},
onSaved: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onReset: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
},
onRefreshed: function (args) {
changedFieldCount[args.id] = 0;
changedFields[args.id] = [];
}
};
});
VSS.notifyLoadSucceeded();
});
$(document).ready(function () {
$("#btnValidate").click(function () {
var getResponse = ValidateUser();
VSS.require(["TFS/WorkItemTracking/Services"], function (_WorkItemServices) {
var wiServiceNew = _WorkItemServices.WorkItemFormService.getService();
wiServiceNew.setFieldValue("System.Title", "Title set from your group extension!");
});
});
});
2 things which I am trying to achieve
After button click event to validate user, I have to access the Work Item fields after successful validation. Unable to access _WorkItemServices.
Not able to to get the Work Item fields.
When I set workItemID variable OnLoad event, it resets to 0 when a tab is clicked, value is not getting retained which is set OnLoad.
You may try to interact with the IWorkItemFormService service. For example:
import {
IWorkItemChangedArgs,
IWorkItemFieldChangedArgs,
IWorkItemFormService,
IWorkItemLoadedArgs,
WorkItemTrackingServiceIds
} from "azure-devops-extension-api/WorkItemTracking";
Check the sample here:
https://github.com/microsoft/azure-devops-extension-sample/blob/master/src/Samples/WorkItemFormGroup/WorkItemFormGroup.tsx

feathersjs sequelize call stored procedure by hook doesn't resolve

I have a problem creating a hook calling a stored procedure.
My custom service hooks (customservice.hooks.js) are :
const callstored = require('../../hooks/callstored')
module.exports = {
before: {
all: [],
find: [callstored()],
get: [],
create: [],
update: [],
patch: [],
remove: []
},
...
My service class (customservice.class.js):
const mysql = require('mysql')
class Service {
constructor (options) {
this.options = options || {};
}
find (params) {
return Promise.resolve( [] );
}
get (id, params) {
return Promise.resolve({
id, text: `A new message with ID: ${id}!`
});
}
create (data, params) {
if (Array.isArray(data)) {
return Promise.all(data.map(current => this.create(current)));
}
return Promise.resolve(data);
}
update (id, data, params) {
return Promise.resolve(data);
}
patch (id, data, params) {
return Promise.resolve(data);
}
remove (id, params) {
return Promise.resolve({ id });
}
}
module.exports = function (options) {
return new Service(options);
};
module.exports.Service = Service;
And my service (customservice.service.js) :
const createService = require('./rankingvotes.class.js');
const hooks = require('./rankingvotes.hooks');
module.exports = function (app) {
const paginate = app.get('paginate');
const options = {
name: 'rankingvotes',
paginate
};
// Initialize our service with any options it requires
app.use('/rankingvotes', createService(options));
// Get our initialized service so that we can register hooks and filters
const service = app.service('rankingvotes');
service.hooks(hooks);
app.publish(() => {
});
};
And finally my hook is (callstored.js)
const Sequelize = require('sequelize');
module.exports = function () {
return function (hook) {
sequelize = hook.app.get('sequelizeClient');
let result=[];
return sequelize.query('CALL RANKING();',{
nest: true,
raw: true }).then(function(response){
console.log(response[0]) //data are correct
hook.data=response[0];
return hook;
}).error(function(err){
console.log(err);
return hook;
});
}
}
If I check the console I got data correctly, but nothing calling from a REST client like Postman.
Any idea? Thank you.
If you want to change the response you have to set hook.result.
const Sequelize = require('sequelize');
module.exports = function () {
return async hook => {
try {
const sequelize = hook.app.get('sequelizeClient');
const response = await sequelize.query('CALL RANKING();',{
nest: true,
raw: true
});
console.log(response[0]) //data are correct
context.result = response[0];
} catch(error) {
console.error(error);
}
return hook;
}
}
hook.data is the request data and is only available for create, update and patch.
Keep in mind that setting hook.result will skip your custom service find if it is set in a before hook.

Resources