@sinclair/smoke
v0.8.8
Published
Run Web Servers in Web Browsers over WebRTC
Downloads
22
Readme
Example
Smoke enables Browsers run micro Web Servers over WebRTC
import { Network } from '@sinclair/smoke'
// ------------------------------------------------------------------
//
// Create a Virtual Network
//
// ------------------------------------------------------------------
const { Http } = new Network()
// ------------------------------------------------------------------
//
// Create a Http Listener on a Virtual Port
//
// ------------------------------------------------------------------
Http.listen({ port: 5000 }, request => new Response('hello webrtc'))
// ------------------------------------------------------------------
//
// Fetch data over WebRTC
//
// ------------------------------------------------------------------
const text = Http.fetch('http://localhost:5000').then(r => r.text())
Install
$ npm install @sinclair/smoke
Overview
Smoke is an experimental browser networking and storage framework that provides Http, Tcp and WebSocket emulation over WebRTC and large file storage via IndexedDB. It is built as a foundation for developing peer to peer web services in the browser with each browser accessible via an application controlled virtual network.
Smoke reshapes WebRTC into WinterCG compatible interfaces enabling traditional web server applications to be made portable between server and browser environments. It is developed in support of alternative software architectures where user centric services can be moved away from the cloud and run peer to peer in the browser.
Licence MIT
Contents
Network
Smoke networking API's are provided by way of Network objects. A Network object represents an active connection to a shared signalling Hub and exposes the Http, Net and Media functionality used to communicate with other Network objects connected to the same Hub.
import { Network, Hubs } from '@sinclair/smoke'
const { Http, Net, Media, Hub } = new Network({ hub: new Hubs.Private() })
const address = await Hub.address() // The address of this Network object.
Private
A Private hub is an in-memory relay that forwards WebRTC ICE messages by way of the browser's BroadcastChannel API. A private hub can only relay messages to the page and other tabs running within the same browser process. Because private hubs cannot facilitate connections made outside the current page, it is considered private. This Hub is the default.
import { Network, Hubs } from '@sinclair/smoke'
const { Http } = new Network({ hub: new Hubs.Private() })
Public
The implementation of this hub is currently pending.
import { Network, Hubs } from '@sinclair/smoke'
const { Http } = new Network({ hub: new Hubs.Public('ws://server/hub') })
Http
The Http API supports Http listen and fetch over WebRTC. It also provides WebSocket emulation.
const { Http } = new Network()
Listen
Use the listen function to receive Http requests from remote peers.
Http.listen({ port: 5000 }, request => new Response('hello'))
Fetch
Use the fetch function to make a Http request to remote peers.
const response = await Http.fetch('http://localhost:5000')
const message = await response.text()
Upgrade
Use the upgrade function to convert a Http request into a WebSocket
Http.listen({ port: 5000 }, request => Http.upgrade(request, (socket) => socket.send('hello')))
Connect
Use the connect function to connect to a remote WebSocket server.
const socket = await Http.connect('ws://localhost:5000')
socket.on('message', (event) => console.log(event.data))
socket.on('error', (event) => console.log(event))
socket.on('close', (event) => console.log(event))
Net
The Net API provides Tcp emulation over RTCDataChannel
const { Net } = new Network()
Listen
Use the listen function to accept an incoming socket.
Net.listen({ port: 5000 }, async socket => {
const data = await socket.read()
await socket.write(data)
await socket.close()
})
Connect
Use the connect function to establish a Net connection to a remote listener.
const socket = await Net.connect({ hostname: 'localhost', port: 5000 })
await socket.write(new Uint8Array(1000))
const data = await socket.read() // Uint8Array()
const end = await socket.read() // null
Media
The Media API provides functionality to send and receive MediaStream objects over WebRTC.
const { Media } = new Network()
Listen
Use the listen function to listen for incoming MediaStream objects
Media.listen({ port: 6000 }, (receiver) => {
const video = document.createElement('video')
video.srcObject = receiver.mediastream
video.play()
document.body.appendChild(video)
receiver.on('close', () => document.removeChild(video))
})
Send
Use the send function to send a MediaStream to a listener
const sender = await Media.send({ hostname: 'localhost', port: 6000 }, new MediaStream([...]))
sender.close() // stop sending live media
Audio
Use the audio function to create a streamable AudioSource.
const audio = Media.audio({ src: './audio.mp3' })
const sender = Media.send({ hostname: 'localhost', port: 6000 }, audio.mediastream)
Video
Use the video function to create a streamable VideoSource.
const video = Media.video({ src: './video.mp4' })
const sender = Media.send({ hostname: 'localhost', port: 6000 }, video.mediastream)
Pattern
Use the pattern function to generate a MediaStream test pattern. This function can be useful for testing live media streaming without web cameras or other media sources.
const pattern = Media.pattern()
const sender = Media.send({ port: 5000 }, pattern.mediastream)
FileSystem
Smoke provides a hierarchical file system able to store large files within the browser. The file system is backed by IndexedDB and has support for streaming read and write, directory enumeration, copy, move, rename as well as file and directory watch events. It is designed to act as a static file store for network services but can be used as a general purpose file system for applications needing to store large files in the browser.
Open
Use the open function to open a file system with the given database name. If the database does not exist it is created.
import { FileSystem } from '@sinclair/smoke'
const Fs = await FileSystem.open('<database-name>')
Stat
Use the stat function to return information about a file or directory.
const stat = await Fs.write('/path/file.txt')
Exists
Use the exists function to check a path exists.
const exists = await Fs.exists('/path/file.txt')
Mkdir
Use the mkdir function to create a directory.
await Fs.mkdir('/media/videos')
Readdir
Use the readdir function to return stat objects for the given directory path.
const stats = await Fs.readdir('/media/videos')
Blob
Use the blob function to return a Blob object to a file path.
const blob = await Fs.readdir('/video.mp4')
const url = URL.createObjectUrl(blob)
Write
Use the write and writeText functions to write file content.
await Fs.write('/path/file.dat', new Uint8Array([1, 2, 3, 4]))
await Fs.writeText('/path/file.txt', 'hello world')
Read
Use the read and readText functions will read content from a file.
const buffer = await fs.read('/path/file.dat')
const content = await Fs.readText('/path/file.txt')
Delete
Use the delete function to delete a file or directory.
await Fs.delete('/path/file.txt')
Rename
Use the rename function to rename a file or directory.
await Fs.writeText('/path/fileA.txt', '...')
await Fs.rename('/path/fileA.txt', 'fileB.txt')
Copy
Use the copy function to copy a file or directory into a target directory.
await Fs.writeText('/path/fileA.txt', '...')
await Fs.copy('/path/fileA.txt', '/backup')
Move
Use the move function to move a file or directory into a target directory.
await Fs.writeText('/path/fileA.txt', '...')
await Fs.move('/path/fileA.txt', '/backup')
Watch
Use the watch function to watch for file and directory events.
Fs.watch('/dir', event => console.log(event))
Contribute
Smoke is open to community contribution. Please ensure you submit an open issue before submitting your pull request. The Smoke project prefers open community discussion before accepting new features.