Integrating with web services in Electron - angularjs

I'm brand new to Electron and I'm about to start development of a desktop application using Electron/AngularJS. The desktop application is just going to be GUI that interacts with a backend server via a RESTful web service and web sockets.
Now my question: what is the best way in Electron to issue HTTP requests to the web service and update the UI? In normal web apps I'd just interact with the web service directly using something like Angular's $http service. However, I'm unable to do this in Electron because the same-origin policy will block the request (from what I understand the renderer runs in the file:// origin so I cannot communicate with mysite.com).
I've come up with a couple of potential solutions, but they don't seem ideal:
Disable the same-origin policy issue by setting the BrowserWindow preference 'web-security' to false. This does not seem like a good idea because if I have any sort of cross-site scripting in my UI code, then the attacker can accessing any files on my box.
Proxy all my HTTP requests through the IPC interface. The main process can then make the HTTP requests without the restrictions of the same-origin policy. This just seems like overkill, though.
Am I missing a simpler solution?

The view html file is loaded in electron via file protocol and ajax does not work in file protocol. In my case I setup an IPC event emitter in the html and an IPC event handler in the main process. Once I needed to make any http call I used the event emitter and then made the http request from the main process. After the request completed I made another IPC event from the main process and handled it in the html. I don't know if its the most elegant way but it worked in my case.
// sample code in the html
<script>
const ipc = require("electron").ipcRenderer;
function sendAjaxCall(params){
// handle the params
// and make a ipc event to the main process
ipc.send("call-AJAX", params)
}
// call the sendAjaxCall function somewhere with proper params
ipc.on("complete-AJAX", function(evt, arg){
// process your args and handle the return data
})
</script>
// sample code in the main js file
const ipc = require("electron").ipcMain;
const request = require("request"); // request is not required, but I found it quite fascinating...
ipc.on("call-AJAX", function(evt, arg){
// process the args and make the ajax call
request("http://some-url.com/some/endpoint/", function(e, resp, body){
// handle the response
// send ipc event to renderer process
ipc.send("complete-AJAX", resp)
})
})
Warning This code above is just some boilerplate code to get you the basic idea. I found a great article on medium Electron’s IPC Modules and How to Use Them where you can get some basic understanding of IPC.
Further Resources-
ipcMain on Electronjs.org
ipcRenderer on Electronjs.org
Request on npmjs.com

from what I understand the renderer runs in the file:// origin so I cannot communicate with mysite.com
I'm pretty sure this is not the case, file:// can communicate with any origin

As an alternative option consider enabling CORS on the server and make CORS requiests from the client.

Related

Sveltekit: Sharing service objects (e.g. configured http client) across pages

I am moving my app from Svelte SPA (original) to Sveltekit multi page app (new).
In the original app, I configure a http client up top and put it context using:
setContext(HTTP_CLIENT, httpClient)
Now the entire app can get that http client using
const httpClient = getContext(HTTP_CLIENT)
I do this because my app can be started with debug parameters than turn on http request logging.
I'm not clear how to do similar in Sveltekit, because it seems that pages do not share a context.
I tried sticking the http client in the session like this:
import { session } from "$app/stores";
$session.httpClient = httpClient
and I got:
Error: Failed to serialize session data: Cannot stringify arbitrary non-POJOs
So $session is meant to be serialized, ok. Does that mean that I need to put whatever debug parameters a user supplied in $session, and each page needs to freshly instantiate its own http client? Or is there some other idiomatic sveltekit way of doing this?
PS I know sveltekit has its own fetch so you might want to say "don't use your own http client", but my app uses many different service objects (graphql client for example) that can be configured in debug (and other) modes, so please don't zero in on the fact that my example is a http client.
One way around this could be to send down the configuration in the top __layout file, create the http client there and store in a store. Since stores are shared across all pages the client can then freely use this store.

Blocking / Initialization service with angular.js

My apps are using many web services on the intranet, and url-s for those depend on the server environment.
My apps are hosted on IIS, which adds an HTTP response header like this: Environment: DEV, so every web app knows in which server environment it is running, and thus which intranet servers it must use to call all the services.
Each of my angular apps uses a service that issues a simple GET against the app's own root just to get any response with the environment name in it, and set configuration accordingly.
Question:
How should an angular app implement such a service that would execute as the very first thing in the application, and make sure that while it is getting that first response, nothing in the app tries to execute an HTTP request against other services, or even try to use any configuration provided by my environment service?
Is there a way to implement such a service in angular that could block every other service / factory in the application till it is done initializing itself?
I have many other services in the app, and none of them really know what to do till my environment service has finished its initialization.
UPDATE
Looking at it from another angle.... is it possible to implement such an interceptor in angular that could do the following?:
execute an HTTP request and block the app's execution till it gets a response
make information from the response available throughout the app as a service/factory/config.
Angular lifecycle could be one solution. Using the angular.config() phase you could peek at the headers of the HTTP service.
Create a factory called 'httpInterceptor'
function httpInterceptors(siteConfig, $q, $injector) {
return {
response: function(data, status, headers) {
siteConfig.setEnvironment(headers['Environment']);
return data;
}
};
)
Then in angular.config()
$httpProvider.interceptors.push('httpInterceptor');
If you truly want to block the other option is to use UI router resolve property to block routes loading until the request has been made https://github.com/angular-ui/ui-router/wiki you can add the resolve method to the root state.
Resolve
You can use resolve to provide your controller with content or data that > is custom to the state. resolve is an optional map of dependencies which > should be injected into the controller.
If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.

Real time with AngularJs & Yii2

I'm developing a Yii2 REST API, with AngularJS for the frontend to consume.
I need a way to implement real time approach, e.g. for a chat, or to make some real time notifications.
Is this possible, how to achieve? I been reading about Ratchet, Socket.io and some other things, but I couldn't figure out how to make them fit together for REST or if this is the way to go.
Any advice would be appreciate.
You have a few options here.
Short / Long Polling (use setTimeout)
app.controller("MyController", function($scope, $timeout, $http) {
$scope.messages = [];
$timeout(callAtTimeout, 3000);
function callAtTimeout() {
console.log("Timeout occurred");
$http.get('PATH TO RESOURCE TO GET NEW MESSAGES').then(
function(res) { // update $scope.messages etc... },
function(err) { // handle error }
);
}
});
For both short and long polling on client side, you send request, wait to get a response back, then wait 3 seconds and fire again.
Short/Long polling works differently on the server side. Short polling will just return a response immediately - whether something has changed or not. Long polling, you hold the connection open and when there is a change, then you return the data. Beware of keeping too many connections open.
Socket.io (websockets)
I would recommend that you implement websockets using either something like node.js on your own web server or a hosted solution like Firebase.
The thing with Firebase is that from PHP, you can send a post request to a REST endpoint on the firebase server. Your javascript can connect to that endpoint and listen for changes and update the dom accordingly. It is possibly the simplest of all to implement.
I personally wouldnt use PHP for socket programming but it can be done.
To have real-time updates on your website, you can implement one of the following approaches depending on your requirement and how fast you need to update your frontend component.
Using a websocket
You can use a library like https://github.com/consik/yii2-websocket to implement it with Yii2. But this will act as a separate service from your REST API. Therefore you have to make sure that proper security practices are applied.
Running an Angular function with a timeout
You can continuously poll an endpoint of the REST API with a timeout of few milliseconds to receive updated values.
The second approach will create many requests to the API which will increase the server load. Therefore my preferred approach is using a websocket.

Can Firebase used callback on embedded system

Now I just get and post Firebase request through sending https request using C language.
Is there any way to use callback for this?
Because I want to get the latest data, now I just polling the https get requests. The SSL handshake may cause delay, so I want to add callback for this.

Backbonejs - CORS error

I have a REST service sitting at http://restservice.net. I am implementing a client for this service in backbone. The client is simply an html file (for bootstrapping the application) and bunch of js files holding my backbonejs code. I am hosting these files on another site http://client.net.
My backbonejs code is calling into http://restservice.net but now allowed due to same origin policy. I have already looked at other SO questions that talk about how I can only talk to http://client.net.
Do I have to redirect every request through http://client.net. I see that as inefficient. What's the point in using a client side MVC framework then? Am I missing something here?
You have two options: JSONP and CORS both of these demand that your http://restservice.net server is setup to suppor the protocols. Forcing backbone to use JSONP simply requires you passing an option to Backbone.sync. One way to do this is like this:
sync: function(method, model, options){
options.dataType = "jsonp";
return Backbone.sync(method, model, options);
}
The problem with JSONP is that you can only make GET requests, so your REST api is effectively read only. To get CORS working you simply need to configure your api server to send back the proper headers . This would pretty liberal:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, DELETE OPTIONS
here is a pretty good run down on CORS. If you set that up, then things will pretty much work as usual.
If you don't have the ability to make changes to the server at http://restservice.net then you have no choice but to proxy all the requests to that service. This is definately inefficient but implementing is probably simpler than you would expect. One thing to consider is a reverse proxy

Resources