geckosio / geckos.io

🦎 Real-time client/server communication over UDP using WebRTC and Node.js http://geckos.io
BSD 3-Clause "New" or "Revised" License
1.35k stars 86 forks source link

Geckos server fails when used with Electron #16

Closed reyalpsirc closed 4 years ago

reyalpsirc commented 4 years ago

I was changing test project that I made before with websockets and electron (used when debugging the game so that I could see what's happening on the server visually) to this but apparently, it does not work inside electron.

Whenever a client tries to connect to the server on Electron, the server gives this error:

Anotação 2020-03-25 181322

Also, it gives a bunch of warnings when it starts:

Anotação 2020-03-25 182022

I know the rest of the code is okay because when I run in headless mode it works just fine.

Any idea what's causing the issue with Electron? Is there an alternative to run the server in a visual way while debugging?

reyalpsirc commented 4 years ago

To use electron I run this command: cross-env IS_DEBUG=true electron debugger.js

My debugger.js:

const { app, BrowserWindow } = require('electron')
const path = require('path')
const url = require('url')
require('electron-reload')([
  path.join(__dirname)
], {
  electron: path.join(__dirname, 'node_modules', '.bin', 'electron')
})

let window = null

// Wait until the app is ready
app.once('ready', () => {
  // Create a new window
  window = new BrowserWindow({
    // Set the initial width to 500px
    width: 1280,
    // Set the initial height to 400px
    height: 720,
    // set the title bar style
    titleBarStyle: 'hiddenInset',
    // set the background color to black
    backgroundColor: '#FFFFFF',
    // Don't show the window until it's ready, this prevents any white flickering
    show: false,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      nodeIntegrationInWorker: true,
      preload: path.join(__dirname, 'server/inject-module.js')
    }
  })

  // window.loadURL('http://localhost:8081/')
  window.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))

  window.once('ready-to-show', () => {
    window.show()
    window.maximize()
    window.webContents.openDevTools()
  })
})

And the inject-module.js only contains a require for the file index.js

My index.js file contains this:

const express = require('express')
const path = require('path')
const Datauri = require('datauri')
const geckos = require('@geckos.io/server').default
const {iceServers} = require('@geckos.io/server')

require('dotenv').config({
  path: path.join(__dirname, '../.env')
})

const datauri = new Datauri()
const expressApp = express()
const server = require('http').Server(expressApp)

expressApp.get('/client.html', function (req, res) {
  res.sendFile(path.join(__dirname, '../client/index.html'))
})

expressApp.use('/dist', express.static(path.join(__dirname, '../dist')))

expressApp.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, '../index.html'))
})

const startAndGetGeckos = () => {
  const io = geckos({
    iceServers: process.env.NODE_ENV === 'production' ? iceServers : []
  })
  io.addServer(server)
  return io
}

if (process.env.IS_DEBUG) {
  window.gameLoaded = (callback) => {
    server.listen(process.env.PORT, function () {
      console.log(`Server listening on ${server.address().port}`)
      window.geckos = startAndGetGeckos()
      if (callback) callback()
    })
  }
} else {
  const setupAuthoritativePhaser = () => {
    const { JSDOM } = require('jsdom')

    JSDOM.fromFile(path.join(__dirname, '../index.html'), {
      // To run the scripts in the html file
      runScripts: 'dangerously',
      // Also load supported external resources
      resources: 'usable',
      // So requestAnimatinFrame events fire
      pretendToBeVisual: true
    }).then((dom) => {
      dom.window.URL.createObjectURL = (blob) => {
        if (blob) {
          return datauri.format(blob.type, blob[Object.getOwnPropertySymbols(blob)[0]]._buffer).content
        }
      }
      dom.window.URL.revokeObjectURL = (objectURL) => {}
      dom.window.gameLoaded = (callback) => {
        server.listen(process.env.PORT, function () {
          console.log(`Server listening on ${server.address().port}`)
          dom.window.geckos = startAndGetGeckos()
          if (callback) callback()
        })
      }
    }).catch((error) => {
      console.log(error.message)
    })
  }
  setupAuthoritativePhaser()
}

Hope this helps identifying the problem

yandeu commented 4 years ago

I have not used electron a lot, but I managed to make an working example on how to use it with geckos.io.

Hope it helps :)

reyalpsirc commented 4 years ago

Thanks @yandeu but in my case I want electron to run as the server and then have a client page (served through expressjs) connecting to it.

In your example, the electron is being used as a client afaik.

The idea is that I can "see" what the server is doing when using it as an authoritative server for a phaserjs game so that I can see things like client movement predictions vs real placement and such.

yandeu commented 4 years ago

I see. This is an interesting approach to debug the server-side.

I use another method to debug the physics on the server. See this video.


I have tried to do the same thing as you and got the same errors. It seems that it is an electron based issue. Unfortunately I do not have sufficient electron knowledge to solve it. Geckos needs access to the ports 9208/tcp and 0-65535/upd. Is electron blocking these? I have no idea :/

reyalpsirc commented 4 years ago

Hmm, I see. Since it worked before with websockets and also worked partially with peerjs (it works when I have the server in localhost but not with their public server), I though the problem would be something with the webrtc implementation on this.

I'm thinking about trying an alternative to electron like NWJS. Do you know any other alternative for "full" visual debug of the server @yandeu ?

yandeu commented 4 years ago

Hi @reyalpsirc, sorry you had to wait so long.

I made it work.

Try the electron-as-server branch. Navigate to packages/electron-server and run ǹpm start. The client will open on http://localhost:8080.

There is sill and error I want to fix, but at least @geckos.io/server is now running on electron. I have not tried a Phaser Game, but I probably will test it soon.

yandeu commented 4 years ago

I just added Phaser and it works! This is so great!

reyalpsirc commented 4 years ago

@yandeu When I opened the client I got this error on the electron server:

image

Anyway, once I tried to move, it worked well. So I guess the error you meant that you're trying to solve is that one? Btw, how can I test this directly on my own game?

yandeu commented 4 years ago

Yes, this is the error I want to fix. Do you know how to fix it? For me, everything looks fine :/

You will have to wait until the release of version 1.4.0. I just have to fix this error and resolve the PR #19.

Btw, I just tested it with multiple players, and I works as well. (Check latest commit).

reyalpsirc commented 4 years ago

Unfortunately I have no idea about the cause of the error :/

yandeu commented 4 years ago

Done!

Please check the example repo.

reyalpsirc commented 4 years ago

@yandeu Thanks, I just tested the example and also tested on my project and works! :D