All Projects → geckosio → Geckos.io

geckosio / Geckos.io

Licence: bsd-3-clause
🦎 Real-time client/server communication over UDP using WebRTC and Node.js http://geckos.io

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Geckos.io

Electron Screen Recorder
A WebRTC screen recorder electron application
Stars: ✭ 343 (-21.87%)
Mutual labels:  webrtc
Flutter Webrtc Server
A simple WebRTC signaling server for flutter-webrtc.
Stars: ✭ 384 (-12.53%)
Mutual labels:  webrtc
Go Stun
A go implementation of the STUN client (RFC 3489 and RFC 5389)
Stars: ✭ 420 (-4.33%)
Mutual labels:  webrtc
Obs Studio Webrtc
This is a fork of OBS-studio with generic support for webrtc. It leverages the same webrtc implementation most browsers use.
Stars: ✭ 343 (-21.87%)
Mutual labels:  webrtc
Filedrop Web
📲 WebRTC file transfer - React/TypeScript front end.
Stars: ✭ 375 (-14.58%)
Mutual labels:  webrtc
Awesome Webrtc
A curated list of awesome WebRTC modules and resources.
Stars: ✭ 395 (-10.02%)
Mutual labels:  webrtc
Eureca.io
eureca.io : a nodejs bidirectional RPC that can use WebSocket, WebRTC or XHR fallback as transport layers
Stars: ✭ 341 (-22.32%)
Mutual labels:  webrtc
React Native Callkeep
iOS CallKit framework and Android ConnectionService for React Native
Stars: ✭ 430 (-2.05%)
Mutual labels:  webrtc
Anyrtc Rtmp Opensource
RTMP 推流器,RTMP(HLS)秒开播放器,跨平台(Win,IOS,Android)开源代码
Stars: ✭ 3,871 (+781.78%)
Mutual labels:  webrtc
Twilio Video.js
Twilio’s Programmable Video JavaScript SDK
Stars: ✭ 408 (-7.06%)
Mutual labels:  webrtc
Gortcd
Fast TURN and STUN server: cross-platform, hot reload, flexible config
Stars: ✭ 358 (-18.45%)
Mutual labels:  webrtc
Quickblox Ios Sdk
QuickBlox iOS SDK for messaging and video calling
Stars: ✭ 373 (-15.03%)
Mutual labels:  webrtc
P
Peer-to-peer networking with browsers
Stars: ✭ 400 (-8.88%)
Mutual labels:  webrtc
Magnet Player
🎥 A place for streaming torrents directly from your browser
Stars: ✭ 346 (-21.18%)
Mutual labels:  webrtc
Webtorrent Hybrid
WebTorrent (with WebRTC support in Node.js)
Stars: ✭ 422 (-3.87%)
Mutual labels:  webrtc
Libdatachannel
C/C++ WebRTC Data Channels and Media Transport standalone library
Stars: ✭ 336 (-23.46%)
Mutual labels:  webrtc
Echoplexus
Socket.io powered chat, JavaScript REPL, whiteboard, and WebRTC calls
Stars: ✭ 392 (-10.71%)
Mutual labels:  webrtc
Go Webrtc
WebRTC for Go
Stars: ✭ 432 (-1.59%)
Mutual labels:  webrtc
Rpi Webrtc Streamer
This repo's objective is providing something like Web Cam server on the most popular Raspberry PI hardware. By integrating [WebRTC](https://webrtc.org/native-code/) and Raspberry PI, we can stream the Raspberry camera feed to browser or native client which talks WebRTC.
Stars: ✭ 428 (-2.51%)
Mutual labels:  webrtc
React Native Twilio Video Webrtc
Twilio Video (WebRTC) for React Native
Stars: ✭ 403 (-8.2%)
Mutual labels:  webrtc
logo

geckos.io

Geckos.io offers real-time client/server communication over UDP using WebRTC and Node.js

Geckos.io fits perfectly with your next HTML5 real-time multiplayer games or chat app.

NPM version Github Workflow Github Workflow Dependency Status Downloads Node version Codecov


📣 Announcement: Version 2

Version 2 will likely be available soon with a huge performance improvement. The API stays exactly as it is now. The only thing that changes is the WebRTC implementation. I switched from wrtc to node-datachannel. node-datachannel is much lighter and faster compared to wrtc.

You can test it today:

 npm i @geckos.io/[email protected] @geckos.io/[email protected]

Want to know more? Join the discussions!

What is it made for?

It's designed specifically for your HTML5 real-time multiplayer games by lowering the average latency and preventing huge latency spikes. It allows you to communicate with your node.js server via UDP, which is much faster than TCP (used by WebSocket). Take a look at the comparison video between UDP and TCP. https://youtu.be/ZEEBsq3eQmg

Getting Started

First things first, install it via npm:

npm install @geckos.io/client @geckos.io/server

New in version 1.7.1

You can now pass a more complex url to the client when you set port to null. This is useful if, for example, you use the geckos.io server behind a proxy.

// client.js

// default is
const channel = geckos({
  url: `${location.protocol}//${location.hostname}`,
  port: 9208
})

// connect to http://1.2.3.4:3000
const channel = geckos({
  url: 'http://1.2.3.4',
  port: 3000
})

// connect to https://geckos.example.com:9208
const channel = geckos({
  url: 'https://geckos.example.com',
  port: 9208 // not required, since 9208 is the default
})

// connect to https://api.example.com:3000/geckos
const channel = geckos({
  url: 'https://api.example.com:3000/geckos',
  port: null
})

// connect to https://api.example.com/geckos
const channel = geckos({
  url: 'https://api.example.com/geckos',
  port: null
})

New in version 1.7.0

Custom Port Range

Allows you to set a custom port range for the WebRTC connection.

// server.js
const io = geckos({
  portRange: {
    min: 10000,
    max: 20000
  }
})

New in version 1.6.0

Connections Manager

You now have access to the connections manager.

// get any channel by its ID via the connectionsManager
const connection = io.connectionsManager.getConnection(channel.id)
if (connection) {
  // here, you could emit a message ...
  connection.channel.emit('chat message', 'You have been kicked for cheating!')
  // ... or close the channel
  connection.channel.close()
}

Raw messages from the io scope

Finally you can send rawMessages from the io scope.

server

// emit a raw message to all channels
io.raw.emit(rawMessage)

// emit a raw message to a specific room
io.raw.room('roomId').emit(rawMessage)

Authorization and Authentication

The client is now able to send a authorization header with the connection request. If the authorization fails, the server will respond with 401 (unauthorized).

Whatever you add to the option authorization (must be a string) will be sent as a Authorization request header. You could, for example, send Basic base64-encoded credentials, Bearer tokens or a simple string, as in the example below.

Read more about HTTP authentication here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization.

client

const username = 'Yannick'
const password = '12E45'
const auth = `${username} ${password}` // 'Yannick 12E45'
const channel = geckos({ authorization: auth })

channel.onConnect(error => {
  console.log(channel.userData) // { username: 'Yannick', level: 13, points: 8987 }
})

server

const io: GeckosServer = geckos({
  /**
   * A async function to authenticate and authorize a user.
   * @param auth The authentication token
   * @param request The incoming http request
   * @param response The outgoing http response
   */
  authorization: async (auth: string | undefined, request: http.IncomingMessage, response: http.OutgoingMessage)) => {
    const token = auth.split(' ') // ['Yannick', '12E45']
    const username = token[0] // 'Yannick'
    const password = token[1] // '12E45'

    // Use "request.connection.remoteAddress" to get the users ip.
    // ("request.headers['x-forwarded-for']" if your server is behind a proxy)

    // add a custom response header if you want
    response.setHeader('www-authenticate', 'Bearer realm="example", error="invalid_token", error_description="The access token expired"')

    // reach out to a database if needed (this code is completely fictitious)
    const user = await database.getByName(username)

    // whatever you return here, will later be accessible via channel.userData to authenticate the user
    if (user.username === username && user.password === password)
      return { username: user.username, level: user.level, points: user.points }

    // if you return true, you will authorize the connection, without adding any data to channel.userData
    return true

    // if you return false, the server will respond with 401 (unauthorized)
    return false

    // if you return a number between 100 and 599, the server will respond with the respective HTTP status code
    return 400 // will return 400 (Bad Request)
    return 404 // will return 404 (Not Found)
    return 500 // will return 500 (Internal Server Error)
    // and so on ...
  },
  cors: { allowAuthorization: true } // required if the client and server are on separate domains
})

io.onConnection((channel: ServerChannel) => {
  console.log(channel.userData) // { username: 'Yannick', level: 13, points: 8987 }
})

New in version 1.5.0

New autoManageBuffering option

By default the RTCDataChannel queues data if it can't be send directly. This is very bad for multiplayer games, since we do not want to render old state. In version 1.5.0, the option autoManageBuffering was added. It is set to true by default. If autoManageBuffering is on, Geckos.io will prefer to drop messages instead of adding them to the send queue. (Messages with the option { reliable: true }, will still be added to the queue)

The problem with the queue while gaming?

If you send 30Kbytes @60fps and the client only has a 10Mbit connection, he can never receive all messages. So it is necessary to drop some of them, which will be done automatically with autoManageBuffering.
Another good solution to this problem would be to decrease the send rate for that specific client. Use the new channel.onDrop(drop => {}) method to track dropped messages. If, for example, you notice that 20% of the messages for a specific client are dropped, decrease the send rate.


Usage

client.js

import geckos from '@geckos.io/client'

// or add a minified version to your index.html file
// https://github.com/geckosio/geckos.io/tree/master/bundles

const channel = geckos({ port: 3000 }) // default port is 9208

channel.onConnect(error => {
  if (error) {
    console.error(error.message)
    return
  }

  channel.on('chat message', data => {
    console.log(`You got the message ${data}`)
  })

  channel.emit('chat message', 'a short message sent to the server')
})

server.js

const geckos = require('@geckos.io/server').default
// or with es6
import geckos from '@geckos.io/server'

const io = geckos()

io.listen(3000) // default port is 9208

io.onConnection(channel => {
  channel.onDisconnect(() => {
    console.log(`${channel.id} got disconnected`)
  })

  channel.on('chat message', data => {
    console.log(`got ${data} from "chat message"`)
    // emit the "chat message" data to all channels in the same room
    io.room(channel.roomId).emit('chat message', data)
  })
})

Troubleshooting

Geckos does not run on http://localhost:PORT/? Try http://127.0.0.1:PORT/ instead.

Cheatsheet

Here a list of available methods.

Client

// import geckos.io client
import geckos from '@geckos.io/client'

/**
 * start geckos client with these options
 * @param options.url default is `${location.protocol}//${location.hostname}`
 * @param options.port default is 9208
 * @param options.label Default: 'geckos.io'
 * @param options.iceServers Default: []
 * @param options.iceTransportPolicy Default: 'all'
 */
const channel = geckos(options)

// the channel's id and maxMessageSize (in bytes)
const { id, maxMessageSize } = channel

// once the channel is connected to the server
channel.onConnect(error => {
  if (error) console.error(error.message)

  // listens for a disconnection
  channel.onDisconnect(() => {})

  // listens for a custom event from the server
  channel.on('chat message', data => {})

  // emits a message to the server
  channel.emit('chat message', 'Hi!')

  // closes the WebRTC connection
  channel.close()
})

Server

// import geckos.io server
import geckos from '@geckos.io/server'

/**
 * start geckos server with these options
 * @param options.iceServers Default: []
 * @param options.iceTransportPolicy Default: 'all'
 * @param options.label Default: 'geckos.io'
 * @param options.ordered Default: false
 * @param options.maxPacketLifeTime Default: null
 * @param options.maxRetransmits Default: 0
 * @param options.cors
 * @param options.cors.origin String | (req) => string. Default '*'
 * @param options.cors.allowAuthorization Default: false
 * @param options.autoManageBuffering By default, geckos.io manages RTCDataChannel buffering for you. Default 'true'
 * @param options.portRange Custom port range for the WebRTC connection (available in >= v1.7.0)
 * @param options.portRange.min Default: 0
 * @param options.portRange.max Default: 65535
 * @param options.authorization The async authorization callback
 */
io = geckos(options)

/**
 * make the server listen on a port
 * @param {number} port default port is 9208
 */
io.listen()

// whenever a new channel is connected
io.onConnection(channel => {
  // the channel's id and maxMessageSize (in bytes)
  const { id, maxMessageSize } = channel

  // whenever the channel got disconnected
  // the reason will be 'disconnected', 'failed' or 'closed'
  channel.onDisconnect(reason => {})

  // listen for a custom event
  channel.on('chat message', data => {})

  // channel joins a room
  channel.join('someRoomId')

  // channel leaves a room
  channel.leave()

  // channel closes the webRTC connection
  channel.close()

  // get notified when a message got dropped
  channel.onDrop(drop => {})

  // will trigger a specific event on all channels in a
  // specific room and add the senderId as a second parameter
  channel.forward(channel.roomId).emit('chat message', 'Hello!')

  // listen for a forwarded message
  channel.on('chat message', (data, senderId) => {
    // we know that the message was forwarded if senderId is defined
    if (senderId) {
      // ...
    } else {
      // ...
    }
  })

  // emits a message to the channel
  channel.emit('chat message', 'Hello to myself!')

  // emits a message to all channels, in the same room
  channel.room.emit('chat message', 'Hello everyone!')

  // emits a message to all channels, in the same room, except sender
  channel.broadcast.emit('chat message', 'Hello friends!')

  // emits a message to all channels
  io.emit('chat message', 'Hello everyone!')

  // emits a message to all channels in a specific room
  // (if you do not pass a roomId, the message will be sent to everyone who is not in a room yet)
  io.room(roomId).emit('chat message', 'Hello everyone!')
})

Note: The following event names are reserved:

  • sendOverDataChannel
  • receiveFromDataChannel
  • disconnected
  • disconnect
  • connection
  • connect
  • error
  • dataChannelIsOpen
  • sendToRoom
  • sendToAll
  • forwardMessage
  • broadcastMessage
  • rawMessage
  • dropped

Raw Messages

You can send and receive USVString, ArrayBuffer and ArrayBufferView using rawMessages.

client

// emit a raw message to the server
channel.raw.emit(rawMessage)

server

// emit a raw message to all channels
io.raw.emit(rawMessage)

// emit a raw message to a specific room
io.raw.room('roomId').emit(rawMessage)

// emit a raw message to the channel
channel.raw.emit(rawMessage)

// emit a raw message to all users in the same room
channel.raw.room.emit(rawMessage)

// broadcast a raw message
channel.raw.broadcast.emit(rawMessage)

// listen for a raw message
channel.onRaw(rawMessage => {})

Reliable Messages

All emit function can send reliable message if needed. This is NOT meant to be used as the default. Just use it to send important messages back and forth.

It works by simply transferring multiple messages after each other. The receiver will simply reject a message if it has already been processed.

channel.emit(
  'end of game',
  {
    points: 147,
    time: 650,
    achievements: ['crucial_hit', 'golden_trophy']
  },
  {
    // Set the reliable option
    // Default: false
    reliable: true,
    // The interval between each message in ms (optional)
    // Default: 150
    interval: 150,
    // How many times the message should be sent (optional)
    // Default: 10
    runs: 10
  }
)

Servers

Standalone

import geckos from '@geckos.io/server'
const io = geckos()

io.onConnection( channel => { ... })
io.listen(3000) // default port is 9208

Node.js HTTP Server

const geckos = require('@geckos.io/server').default
const http = require('http')
const server = http.createServer()
const io = geckos()

io.addServer(server)
io.onConnection( channel => { ... })
// make sure the client uses the same port
// @geckos.io/client uses the port 9208 by default
server.listen(3000)

Express

const geckos = require('@geckos.io/server').default
const http = require('http')
const express = require('express')
const app = express()
const server = http.createServer(app)
const io = geckos()

io.addServer(server)
io.onConnection( channel => { ... })
// make sure the client uses the same port
// @geckos.io/client uses the port 9208 by default
server.listen(3000)

Deployment

You have to make sure you deploy it to a server which forwards all traffic on ports 9208/tcp (or another port you define) and 0-65535/upd to your application.

Port 9208/tcp (or another port you define) is used for the peer signaling. The peer connection itself will be on a random port between 0-65535/upd.

ICE Servers

Geckos.io provides a default list of ICE servers for testing. In production, you should probably use your own STUN and TURN servers.

const geckos = require('@geckos.io/server').default
const { iceServers } = require('@geckos.io/server')
// or
import geckos, { iceServers } from '@geckos.io/server'

// use an empty array if you are developing locally
// use the default iceServers if you are testing it on your server
const io = geckos({ iceServers: null, TESTING_LOCALLY ? [] : iceServers })

Watch a useful video about ICE Servers on YouTube.

TypeScript

Geckos.io is written in TypeScript. If you import geckos.io with the import statement, the types will be imported as well.

// client.js
import geckos, { Data } from '@geckos.io/client'

const channel = geckos({ url: 'YOUR_SERVER_URL' })

channel.onConnect(() => {
  channel.on('chat message', (data: Data) => {
    // ...
  })
})

// server.js
import geckos, { Data } from '@geckos.io/server'

const io = geckos()

io.onConnection(channel => {
  channel.on('chat message', (data: Data) => {
    // ...
  })
})

Examples

socket.io vs geckos.io vs peerjs

TODO: Note some differences here.

When to use socket.io, geckos.io or peerjs?

socket.io geckos.io peerjs
Real-Time Multiplayer Game
(with authoritative server)
Real-Time Multiplayer Game
(without authoritative server)
Turn based Multiplayer Game
(with authoritative server)
Turn based Multiplayer Game
(without authoritative server)
Chat App
Any other App with Real-Time communication

New Technologies

For now WebRTC in the best way to send fast (unordered and unreliable) messages between browser and server. But once a better technology will be widely available (for example quic), we will implement it as well.

Who is using geckos.io

  • DatTank.io - is a free multiplayer browser online tank game.

Other cool Packages

Take a look at these other packages you might be interested in.

enable3d

Easily build 3D Game for Web, Mobile and PC (https://enable3d.io).

enable3d logo

Phaser on Node.js

Run Phaser 3 Games on Node.js (@geckos.io/phaser-on-nodejs)

Snapshot Interpolation

Snapshot Interpolation for Multiplayer Games (@geckos.io/snapshot-interpolation)

Development

To help developing geckos.io, install this repository via npm install. Test it with npm test. Then start the development server with npm run dev.

License

The BSD 3-Clause License (BSD-3-Clause) 2019 - Yannick Deubel. Please have a look at the LICENSE for more details.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].