How to run https server on Babylon.js Editor

Hi, @julien-moreau
Hope you’re well.
Finally I have time again. Therefore, I tried to adapt WebXR feature on Babylon.js Editor v4.

First of all, I’d like to add the following feature.
(1) Run https server when another play button is pressed.
(2) Add WebXR template on Babylon.js Editor

Now I’m trying (1) but I’m at a loss where I should pem files.
Let me current my progress.

Added a new button under “Play…” button. See the picture.

Implemented several codes. (Especially “src/main/tools/server.ts”)

    public static RunHttpsServer(root: string, port: number): void {

        root = this.url;
        if (this.Server) { this.StopServer(); }
        this.Server = createServer( {root,cache:-1});
        fs.lstatSync("./cert.pem");
        fs.lstatSync("./key.pem");
        this.Server.listen(port/*, "localhost*/);

 
        this.Path = this.url;
    
    }

“RunHttpsServer” itself seems to be called, but the error occurred.

Uncaught Exception:
Error: ENOENT: no such file or directory, lstat './cert.pem'
    at lstatSync (fs.js:906:3)
    at Object.fs.lstatSync (electron/js2c/asar.js:235:27)
    at Function.GameServer.RunHttpsServer (/Users/username/Documents/BJSEditor/Editorv4_webxr_dev_gitprivate/BJSEditorv4_WebXRdev/electron-packages/mac/BabylonJS Editor.app/Contents/Resources/app.asar/build/src/main/tools/server.js:72:22)
    at StartHttpsWebServerIPC.handler (/Users/username/Documents/BJSEditor/Editorv4_webxr_dev_gitprivate/BJSEditorv4_WebXRdev/electron-packages/mac/BabylonJS Editor.app/Contents/Resources/app.asar/build/src/main/ipc/webserver.js:40:29)
    at IpcMainImpl.emit (events.js:210:5)
    at WebContents.<anonymous> (electron/js2c/browser_init.js:3908:15)
    at WebContents.emit (events.js:210:5)

I set “cert.pem” and “key.pem” on “html” folder. It is the same location as editor.html, plugin.html, and sandbox.html.

I can share more information if you need.
Any comment is helpful for me. Thanks in advance.

Hey @Limes2018 that’s excellent!

I found the problem and it is due to the difference between HTTP(s) requests and file system operations. In fact, all HTTP(s) requests will be relative to the absolute path of the HTML file. For example, “./cert.pem” will be transformed by Electron to “absolutePathToEditorHtmlFolder/cert.pem”.

Unfortunately, using “fs” or “fs-extra” will always be relative to the working directory of the application. And this working directory can be modified by either the Editor or a plugin etc. That means you’ll have to deal with absolute paths.

For example, if you put the certificates in the “html” folder you can use “join” and some Editor tools to build the path:

// Import tools of the editor located at src/renderer/editor/tools/tools.ts
import { Tools } from "./tools/tools";

import { join } from "path";

// Build absolute path which gives "absolutePathToEditor/preview/cert.pem"
const certificatePath = join(Tools.GetAppPath(), "preview", "cert.pem");

fs.lstatSync(certificatePath);

@julien-moreau
Thanks for quick and kind reply!
I’ll try it!

1 Like

I tried a new code but another error happens.

My modified code:

import { createServer } from "http-server";
import { Server } from "http";

import { Nullable } from "../../shared/types";
import fs from 'fs';
import { Tools } from "../../renderer/editor/tools/tools";
import { join } from "path";

export class GameServer {
    /**
     * Defines the current absolute path of the web server.
     */
    public static Path: Nullable<string> = null;
    /**
     * Defines the reference to the http server.
     */
    public static Server: Nullable<Server> = null;

    private static url:string ="https://localhost"; //temporary

    /**
     * Runs the server.
     * @param root the root url where to start the server and serve files.
     * @param port defines the port to listen.
     */
    public static RunServer(root: string, port: number): void {
        if (this.Server) { this.StopServer(); }

        this.Server = createServer({ root, cache: -1 });
        this.Server.listen(port/*, "localhost*/);

        this.Path = root;
    }
    /**
     * Runs the https server.
     * @param root the root url where to start the server and serve files.
     * @param port defines the port to listen.
     */

    public static RunHttpsServer(root: string, port: number): void {

        root = this.url;
        if (this.Server) { this.StopServer(); }
        this.Server = createServer( {root,cache:-1});
        const certAbsPath = join(Tools.GetAppPath(), "preview", "cert.pem");
        const keyAbsPath = join(Tools.GetAppPath(), "preview", "key.pem");
      //  fs.lstatSync("./cert.pem");
      //  fs.lstatSync("./key.pem");
        fs.lstatSync(certAbsPath);
        fs.lstatSync(keyAbsPath);
        this.Server.listen(port/*, "localhost*/);

 
        this.Path = this.url;
    
    }

npm run build works and I could get “BabylonJS Editor.app” in electron-packages/mac folder.
Run the app is OK. Other error happens when I press “Play in Integrated https Browser” button.

“Play in Integrated https Browser” calls RunHttpsServer.

Uncaught Exception:
TypeError: Cannot read property 'app' of undefined
    at Function.Tools.GetAppPath (/Users/username/Documents/BJSEditor/Editorv4_webxr_dev_gitprivate/BJSEditorv4_WebXRdev/electron-packages/mac/BabylonJS Editor.app/Contents/Resources/app.asar/build/src/renderer/editor/tools/tools.js:58:46)
    at Function.GameServer.RunHttpsServer (/Users/username/Documents/BJSEditor/Editorv4_webxr_dev_gitprivate/BJSEditorv4_WebXRdev/electron-packages/mac/BabylonJS Editor.app/Contents/Resources/app.asar/build/src/main/tools/server.js:74:53)
    at StartHttpsWebServerIPC.handler (/Users/username/Documents/BJSEditor/Editorv4_webxr_dev_gitprivate/BJSEditorv4_WebXRdev/electron-packages/mac/BabylonJS Editor.app/Contents/Resources/app.asar/build/src/main/ipc/webserver.js:40:29)
    at IpcMainImpl.emit (events.js:210:5)
    at WebContents.<anonymous> (electron/js2c/browser_init.js:3908:15)
    at WebContents.emit (events.js:210:5)

Should I do something before using “GetAppPath()” ?

I’d appreciate your help.

Ah !

You are using a file that used by the main process of Electron. In Electron you have two processes:

  • the main process: used to control the overall lifecycle of the application. There is no notion of web here except it is using JavaScript or TypeScript and NodeJS
  • the renderer process: the process that is used to render the webpage etc like you do in a normal browser except that here you have the access to NodeJS :slight_smile:

In the documentation of electron, you can see for each method/class that you import from “electron” if it is available in the main or the renderer process, like this one that may be interesting for you: app | Electron

And the function that will be useful here (getAppPath): app | Electron

In your case, just import { app } from “electron” and use “app.getAppPath()” instead of “Tools.GetAppPath()”. In that case, the way to get the app path is not the same if you are in the main process or the renderer process

Thanks for kind explanation again!
Sorry for bothering of you because I’m a new comer of electron.

I’ll check the document try it again.

Thanks to your help, the finding path issue has been resolved by the following code.

    public static RunHttpsServer(root: string, port: number): void {

        root = this.url;
        if (this.Server) { this.StopServer(); }
       this.Server = createServer( {root,cache:-1});
  
        const certAbsPath = join(app.getAppPath(), "html", "cert.pem");
        const keyAbsPath = join(app.getAppPath(), "html", "key.pem");
        fs.lstatSync(certAbsPath);
        fs.lstatSync(keyAbsPath);
        this.Server.listen(port/*, "localhost*/);
        this.Path = root;
    
    }

A new browser window opened from BJS Editor, but no information was showed.
Original “RunServer” on server.ts successfully loads html that is the same contents as editor.workspace.
On the other hand, “RunHttpsServer” loads blank html.
I’ll check my code again.

Perfect !!
Do you have any repository I can take a look to help you? I’d like to help you seeing what is missing here :slight_smile:

I’d appreciate your help. Actually, my trial is coming a deadlock.

Here is my repository. Let me current situation.
flushpot1125/Editor at release/4.0.0 (github.com)

[What I did]
For “Run In Integrated https Browser” button

  • src/renderer/editor/components/tools-toolbar.tsx
  • src/renderer/editor/tools/types.js
  • src/renderer/editor/editor.tsx

For https-server

  • src/shared/ipc.ts
  • src/main/handlers/ipc.ts
  • src/main/ipc/webserver.ts
  • src/main/tools/server.ts
  • src/main/handlers/ipc.ts

I generated key.pem and cert.pem according to the following command.


$ openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

The two files are put on html folder of Editor repository. See the attached picture.

[Current problem]
(1) “RunHttpsServer” in “server.ts” seems to run, but URL is still “http://localhost:1338”. I confirmed pressing “Open in my browser” button.

(2) No index.html was loaded. Original “RunServer” on server.ts successfully loads html that is the same contents as editor.workspace.On the other hand, “RunHttpsServer” loads blank html.

The very simple project of BJS Editor is here.
flushpot1125/BJSEditor_WebXRprojects: Compatible with Babylon.js Editor v4.0.0-rc.3 or later (github.com)

Kindly thanks for your comment in advance.

@Limes2018 thanks for sharing! I’m having a look ASAP :slight_smile:

1 Like

Hey @Limes2018, I got it working !

When creating the server, there is an option to provide the certificate and key:

if (this.Server) { this.StopServer(); }

this.Server = createServer({
    root, cache: -1, https: {
        key: join(app.getAppPath(), "html", "key.pem"),
        cert: join(app.getAppPath(), "html", "cert.pem"),
    }
});

What I can see also is that the feature you are trying to implement requires some deep (but not breaking changes) modifications to the Editor. Once you have tested and got your feature fitting your need, would you like me to implement a way to choose using HTTP or HTTPS servers?

@julien-moreau
I deeply thanks for your implementation. I’m sorry that my trial did not reach the implementation.

My ideal specification is that:

  • developers can implement WebXR contents on the Editor
  • They can access the projects on the Editor via other devices like iPhone/Android smartphone or VR headset without publishing the projects
    (e.g. If these devices access “https://“IP address of PC running the Editor”:1338”, they can show WexXR contents)

WebXR contents need https access, I tried to add another Play button and http and https server run in parallel. (Other Editor projects except for WebXR don’t require https, I think.)

If possible, could you give me time to prepare image of the specification? I’ll prepare it 2 or 3 days later.

@julien-moreau

I made a paper prototype by AdobeXD. You can check the proto on your browser.
When you click red squares, the editor images move to next one.
(1) Click “Edit” : You can confirm about key registration process.
(2) Click “Run” : You can confirm about running https server process.

I’d like to add such features but I could not implemented https server as previous my posts.
If you try to implement https-servers, I try to make remained tasks.

This is just my idea and any comments and feedback are welcome to me.

Thanks a lot for taking your time.

Thanks a lot @Limes2018 for that specification !! I’m adding the feature ASAP :slight_smile:
What I suggest is that in preferences of the Editor (workspace section) the user can choose to use HTTP or HTTPS server (using a checkbox for example). This will allow to keep only one button to run the game, else we’ll have 2 buttons per category:

  • Run
  • Run in Editor
  • Run in browser

i’m going to start implement and share you screenshots of what I mean if I’m not clear :slight_smile:

@julien-moreau

Thanks for confirming my proposal.

What I suggest is that in preferences of the Editor (workspace section) the user can choose to use HTTP or HTTPS server (using a checkbox for example). This will allow to keep only one button to run the game, else we’ll have 2 buttons per category:

Sorry for my late understanding. I could finally understand what you suggest.

The reason is why I proposed to add a new button “Play In Integrated https browser” in “Play” that WebXR generally requires the latest version chromium or some web engine. I suppose some developers use extension when developing contents like followings:

I suppose it is not easy to contains such extension in Babylon.js Editor. Therefore I proposed that https server does not open integrated browser of BJS Editor like the attached screenshot.

Of course this is just my supposition. I hope these are useful for you.
Sorry again for my just proposal. I’ll make a template for WebXR contents.

HI @Limes2018
I have implemented most of the features and pushed to the branch “release/4.0.0”. I also added some other WIP features on this branch by everything should be fine :slight_smile:

I let you check and give me feedbacks :slight_smile:
What I am missing is the popin showing the ip address of the machine but I’m working on!

Also, my question for this popin is: is it really needed to be a closable popin? Can’t it be a log in the console showing the ip address of the server each time it is started? Thanks for your answer :slight_smile:

@julien-moreau
Thanks for your great implementation!!. I’ll pulled the latest release/4.0.0 and confirm it.
Let me reply your question soon. :slight_smile:

@julien-moreau
I have finished to confirm your new features. In a word, it’s greatest!!

  • I set my cert.pem and key.pem on new preference settings and run https server successfully.
  • My firefox in PC (BJS Editor works on the same PC), an Android smartphone, and Oculus Quest2 could access “https:// my pc ip:1338” successfully. (See the attached screenshot and
    movie)

Firefox

Oculus Quest2

  • Preference UI is so cool!

Also, my question for this popin is: is it really needed to be a closable popin? Can’t it be a log in the console showing the ip address of the server each time it is started?

Actually my prototyping image is just an example. The your work is best I think.
Only I 'd like to ask is that how do I stop https server?
When I use an original button “Run in Integrated Browser”, it seems to stop by pressing “X” button of browser window.

Great thanks again. I’ll propose WebXR template soon.

@julien-moreau

Sorry for my continuous posts.

Do you know the reason why VR controller is different between Playground and BJS editor?

The post shows WebXR controller input on PG. The Quest2 controller shows appropriately.
WebXR based VR controller input - Demos and projects - Babylon.js (babylonjs.com)

Current VR controller in my project on BJS Editor is different. Version of Babylon.js cause the difference?
Thanks for your every support.

@Limes2018 excellent !!!

For the controllers, I’m pretty sure it is the reason. You can easily test by updating the version of the “@babylonjs/” modules in the package.json of your project. The editor is using the stable 4.2.0 but as Babylon.JS is backward compatible you can use whatever version you want in your project that is > to 4.2.0

Can’t wait to see the WebXR sample and put it in the templates of the Editor!! If I have your permission :slight_smile: