RemoteLib
Convert your JavaScript library to a remote service 💫.
RemoteLib is a library that can be shared remotely with other peers without worrying for API interfaces or RPC integration. Using only a Duplex stream, such as TCP socket, WebSocket or even WebRTC DataChannel, your users will be able to use your code remotely exactly as if it's local library. This, including calling functions with callbacks, Promises, class inheritance, getters and setters support and more. See usage for some examples.
Is it kind of RPC?
No. RemoteLib is based on remote-context and won't just proxying your functions. Instead, you have an entirely shared context between two remote peers. See Features for more details:
Features
- Use RemoteLib on node.js & on the browser (just use browserify or webpack to create a bundle).
- Pure Javascript (Using ES6 Proxy).
- Seamless interface (your library will be proxies AS IS to the users remotely!).
- Proxy anything - from functions and object, to classes and Promises and even Symbols!
- Builtin support for Promises - Resolve any path on the remote object via the
RemoteProxy
interface. - Builtin support for class inheritance - Your user can use
instanceof
with the proxyied objects. - Use any communication method - connect using simple
Stream
interface (WebSocket or WebRTC implementation available). - Serve multiple peers in parallel.
- Use RemoteLib for P2P projects (via the
remote-context
library).
Install
npm install remote-lib
Ways to help
- Join us in Gitter to help with development or to hang out with some mad science hackers :)
- Create a new issue to report bugs
- Fix an issue. RemoteLib is an OPEN Open Source Project!
Getting Started
Simple "Hello World" library
Create a context and a server:
const net = require('net');
const { Library } = require('remote-lib');
// Create the library context
const library = new Library({
hello: 'World!',
});
// Create a server and serve each client the context remotely
const server = net.createServer(socket => {
library.serve(socket);
});
// Bind on port 3000
server.listen(3000);
On the client side, we just need to connect to the server an create our remote library. Notice that the server and the client sharing only a single socket without any knowledge of the server library format. You can easily replace the socket it with WebSocket or even WebRTC DataChannel.
const net = require('net');
const { RemoteLibrary } = require('remote-lib');
// Connect to the server and get a stream
const socket = net.createConnection(3000);
// Create the remote library
const remoteLibrary = new RemoteLibrary(socket);
// Get the remote "hello" value
remoteLibrary.hello.then(value => {
// value === 'World!'
});
Calling remote functions
RemoteLib supporting calling remote functions as well:
// On the server:
const library = new Library({
// Simple functions
foo() {
return 'bar';
},
// Async functions
getData: () =>
new Promise(resolve =>
setTimeout(() => resolve({ data: 'Tada!' }), 100),
),
// Functions with callbacks
loadInfo: callback => {
setTimeout(callback(123), 200); // call callback after 200ms
},
// Functions of functions
sum: x => y => x + y,
});
// On the client:
remoteLibrary.foo().then(value => {
// value === 'bar'
});
// Promises already handled for you
remoteLibrary.getData().then(value => {
// value == { data: 'Tada!' }
});
// Send callback as first parameter
remoteLibrary.loadInfo(value => {
// value === 123
}).catch(err => {
// catch any errors while calling loadInfo()
});
remoteLibrary.sum(5).then(async sum2 => {
await sum2(2); // 7
});
// You can even speed things up by using the virtual-path promise:
remoteLibrary.sum(3)(2).then(value => {
// value === 5
});
Using remote classes
Use can use build-in classes or create one by your own:
// On the server
class MyClass {
constructor(i) {
this.i = i;
}
inc() {
this.i += 1;
return this.i;
}
}
const library = new Library({
myClass: new MyClass(5),
// native ES6 Set class instance
myThings: new Set(['car', 'keys', 'pizza']),
});
// On the client:
remoteLibrary.myClass.then(async myClass => {
// myClass.i === 5
// Call methods with async promises
await myClass.inc(); // 6
// myClass.i === 6
});
remoteLibrary.myThings.then(async myThings => {
myThings instanceof Set; // true
// Access cached getters instantly
myThings.size; // 3
await myThings.has('keys'); // true
await myThings.has('cat'); // false
await myThings.add('dog');
await myThings.has('dog'); // true
});
Handling errors
RemoteLib catch all the errors for you and deliver them back to the user as-if they happens on the client:
// On the server:
const library = new Library({
doNotCallMe() {
throw ReferenceError('I told you! :)');
},
});
// On the client:
remoteLibrary.doNotCallMe().catch(err => {
err instanceof ReferenceError; // true
err.message; // "I told you! :)"
});
remoteLibrary.notExistsFunction().catch(err => {
err instanceof TypeError; // true
err.message; // "notExistsFunction is not a function"
});
API Reference
Remote-lib is build with many small sub-packages, each package implement a small part of this library. You can read here the full API Reference.
module | version | description |
---|---|---|
remote-lib | A high level API for creating remote libraries. | |
remote-context | The core of remote-lib , creating and serving remote context. |
|
remote-environment | A shared environment context between remote peers. | |
remote-instance | A stream transformer that can parse and construct instances remotely. |
|
remote-protocol | The core of remote-context protocol. |
|
reference-context | Virtual context implementation on vanilla Javascript. |
License
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Remote-lib
Convert your JavaScript library to a remote service 💫.
Using only a Duplex stream such as TCP soocket, WebSocket or even WebRTC DataChannel with this library you can just share your code with other peers without worrying for API interfaces or RPC integration. Your users will be able to use your code remotely exactly as you write it. Including calling functions with callbacks, Promises, class inheritance and more.
This library is based on the remote-context module.
Install
npm install remote-lib
Usage
On the server
const net = require('net');
const { Library } = require('remote-lib');
// You can put any object, class or instance under the context and it will be proxied to the
// remote peer automatically
const library = new Library({
// Static vars
foo: 'bar',
// Dynamic functions
getRandom: () => Math.random(),
// Async functions
getData: () =>
new Promise(resolve =>
setTimeout(() => resolve({ data: 'Tada!' }), 100),
),
// Classes and objects
myThings: new Set(['car', 'keys', 'pizza']),
// Functions that return functions
multiFunc: () => () => 'Yes!',
});
// Create a server and serve each client the context remotely
const server = net.createServer(socket => {
library.serve(socket);
});
// Bind on port 3000
server.listen(3000);
On the client
const net = require('net');
const { RemoteLibrary } = require('remote-lib');
// Connect to the server and get a stream
const socket = net.createConnection(3000);
// Create the remote library
const remoteLibrary = new RemoteLibrary(socket);
// Get the remote "foo"
remoteLibrary.foo.then(value => {
// value === 'bar'
});
// Run the remote function "getRandom"
remoteLibrary.getRandom().then(value => {
// `value` is random number
});
// Run the remote async function "getData"
remoteLibrary.getData().then(value => {
// value === { data: 'Tada!' }
});
// Get remote instance set "myThings"
remoteLibrary.myThings.then(async set => {
set instanceof Set; // true
// Access getters and data properties instantly
set.size; // 3
// Call methods with async promises
await set.has('keys'); // true
await set.has('cat'); // false
// Change the remote instance
await set.add('dog');
await set.has('dog'); // true
});
// Use RemotePromise virtual path:
remoteLibrary.multiFunc()().then(value => {
// value === 'Yes!'
});
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Remote-context
Create a virtual context and share it remotely with other peers via ANY stream object 💫.
Using only a Duplex stream such as TCP soocket, WebSocket or even WebRTC DataChannel with this library you can just share your code with other peers without worrying for API interfaces or RPC integration. Your users will be able to use your code remotely exactly as you write it. Including calling functions with callbacks, Promises, class inheritance and more.
This library is the core of remote-lib module.
Install
npm install remote-context
Usage
On the server
const net = require('net');
// Get the context and the environment
const { Context } = require('remote-context');
const envContext = require('remote-context/envs/es6-unstable');
// Create a new context under ES6 environment.
// You can put any object, class or instance under the context and it will be proxied to the
// remote peer automatically
const context = new Context(envContext, {
// Static vars
foo: 'bar',
// Dynamic functions
getRandom: () => Math.random(),
// Async functions
getData: () =>
new Promise(resolve =>
setTimeout(() => resolve({ data: 'Tada!' }), 100),
),
// Classes and objects
myThings: new Set(['car', 'keys', 'pizza']),
});
// Create a server and serve each client the context remotely
const server = net.createServer(socket => {
context.remote(socket);
});
// Bind on port 3000
server.listen(3000);
On the client
const net = require('net');
// Get the context and the environment
const { Context } = require('remote-context');
const envContext = require('remote-context/envs/es6-unstable');
// Connect to the server and get a stream
const socket = net.createConnection(3000);
// Create the remote context
const clientContext = new Context(envContext);
const remoteContext = clientContext.remote(socket);
// Get the remote "foo"
remoteContext.fetch('foo').then(value => {
// value === 'bar'
});
// Run the remote function "getRandom"
remoteContext.fetch('getRandom')().then(value => {
// `value` is random number
});
// Run the remote async function "getData"
remoteContext.fetch('getData')().then(value => {
// value === { data: 'Tada!' }
});
// Get remote instance set "myThings"
remoteContext.fetch('myThings').then(async set => {
set instanceof Set; // true
// Access getters and data properties instantly
set.size; // 3
// Call methods with async promises
await set.has('keys'); // true
await set.has('cat'); // false
// Change the remote instance
await set.add('dog');
await set.has('dog'); // true
});
Supported Environments
Remote-context is currently supporting only limited number of environment contexts. To use an environment you should require it explicitly:
const envContext = require('remote-context/envs/ENV_NAME');
When ENV_NAME
is the required environment name.
Name | Status | Description |
---|---|---|
es6-unstable |
AVAILABLE | A development version of ES6 context. This environment consider unstable and may change over the versions. |
node6-unstable |
IN_DEVELOPMENT | This environment will include all Node.js version 6 context. This environment consider unstable and may change over the versions. |
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Remote-environment
The complete context dictionary for given environment 💫.
This library contain a key-value map of the requested context, accessing the objects with their
real paths such as "Object.getPrototypeOf"
. All the contexts include only a variables that are
unique for this environment and can't recreate again manually. For Example, the PI number
3.141592653589793
is not a unique variable but the function Math.sin
is unique and therefore
will be available under the path "Math.sin"
.
Install
npm install remote-environment
Usage
// Load the requested environment
const context = require('remote-environment/es6');
// Access the environment objects
context['Object']; // equals to `Object`
context['Math.sin']; // equals to `Math.sin`
context['Promise.resolve']; // equals to `Promise.resolve`
context['Function.prototype']; // equals to `Function.prototype`
Supported Environments
Remote-environment is currently supporting only limited number of environment contexts. To use an environment you should require it explicitly:
const context = require('remote-environment/ENV_NAME');
When ENV_NAME
is the required environment name.
Name | Status | Description |
---|---|---|
es6 |
UNSTABLE | An ES6 context. This environment consider unstable and may change over the versions. |
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Remote-instance
With this library you can encode and transfer instances remotely 💫.
Remote instances will be just like if they created locally. To create a remote instance all you need to do is:
- Optional - Implement a static method
fromArgumentsList()
on the constructor of the instance. This method will receive an array of arguments as first argument and should return a new instance accordingly. If this method those not exists, the arguments will apply on the instance constrictor (see example bellow). - Implement a method
toArgumentsList()
on the instance which return array of arguments of any kind (including other instances!) to recreate this instance remotely via thefromArgumentsList()
method. - Register the instance constructor on the parser with a unique single byte-code that is well known to each peer (see example bellow).
That's it!
You can use the parser method parser.transform(stream)
to convert a duplex buffer stream to an
object
mode stream transformed by the parser (see API Reference for more details).
Install
npm install remote-instance
Usage
const Parser = require('remote-instance');
// Create test class
class Foo {
constructor(bar) {
this.bar = bar;
}
// Tel the parser how to rebuild this class remotely
toArgumentsList() {
return [this.bar];
}
}
// Create a parser instance and register our class
const parser = new Parser();
parser.register(0x01, Foo);
// create an instance and encode it
const foo = new Foo({ test: 'myThing' });
const buffer = parser.encode(foo);
// decode and recreate the instance
const decodedFoo = parser.decode(buffer);
// `decodedFoo` is not foo but an exact copy of Foo
decodedFoo !== foo; // true
decodedFoo instanceof Foo; // true
decodedFoo.bar; // { test: 'myThing' }
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Remote-protocol
Enable peer to create session with other peer and executing actions remotely 💫.
To create a session you should supply an duplex stream with objectMode
turn on. See the
remote-instance
module for a possible
implementation.
All the communication between the peers handled by actions. An Action
is simple class with a
fetch
and / or exec
methods that the peers can use. The protocol has build-in support for
requests and responses in order to fetch actions remotely.
Install
npm install remote-protocol
Usage
const { Session, Action } = require('remote-protocol');
class FooAction extends Action {
fetch() {
return Math.random();
}
}
// create an object mode stream that's bind to itself as-if other peer send the object
const objectStream = new PassThrough({ objectMode: true });
// create a session
const session = new Session(objectStream);
session.request(
new FooAction(),
result => {
// `result` is random number
},
error => {
// handle request error
},
);
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.
Reference-context
Creates a virtual context that can hold values with given references 💫.
Reference-context allows you to lookup values on the context, get the number of references or values currently on the context and even assign a new unique reference to a given value.
This library is the core context of the libraries remote-lib and remote-context.
Install
npm install reference-context
Usage
const ReferenceContext = require('reference-context');
class Foo {}
const foo = new Foo();
const parent = new ReferenceContext({ Object });
const referenceContext = new ReferenceContext({ foo }, parent);
parent.count; // 1
referenceContext.count; // 2
referenceContext.ownCount; // 1
referenceContext.has('Object'); // true
referenceContext.hasOwnReference('Object'); // false
referenceContext.hasOwnReference('foo'); // true
referenceContext.exists(Object); // true
referenceContext.own(Object); // false
referenceContext.get('Object'); // Object
referenceContext.get('foo'); // foo
referenceContext.lookup(Object); // "Object"
referenceContext.lookup(foo); // "foo"
API Reference
This module is a part of the remote-lib
library.
Here is the relevant documentation for this module:
© 2017 Moshe Simantov
Licensed under the Apache License, Version 2.0.