This repository has been archived by the owner on Nov 16, 2019. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 74ff507
Showing
18 changed files
with
741 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# `stellard` Module | ||
|
||
The `stellard` module provides the lower level mechanisms to communicate with the stellar network. | ||
|
||
This module is intended to be a cover over `stellar-lib`, integrating well with an modular client environment. | ||
|
||
This is meant primarily for backend code; `services` and `lib` scripts. | ||
|
||
## Notable Services | ||
|
||
The two major services provided by this module are [stellard.Network](services/network.service.es6) and [stellard.Sessions](services/sessions.service.ed6). | ||
|
||
### stellard.Network | ||
|
||
The Network service manages low level connections (i.e. stellar-lib Remote objects) and wraps them in a Promise-based interface. Additionally, this service will broadcast events on the root scope that other components can use to get notifications regarding network state. | ||
|
||
|
||
#### Example Usage | ||
|
||
```javascript | ||
|
||
//Load someone's balance | ||
|
||
let network = $get('stellard.Network'); | ||
// connect to the live stellar network | ||
network.get("live") | ||
// wait until we are connected | ||
.ensureConnected() | ||
// issue a request | ||
.then(nc => nc.sendRequest("account_info", {account: "gM4Fpv2QuHY4knJsQyYGKEHFGw3eMBwc1U"})) | ||
// process results | ||
.then(result => { | ||
console.log(result.account_data.Balance); | ||
}); | ||
|
||
``` | ||
|
||
### stellard.Sessions | ||
|
||
The Network service has no concept of a user. NetworkConnection objects do not have an associated address or secret. The Sessions service is where we introduce addresses and secrets. | ||
|
||
A session object (obtained through either `Sessions.get` or `Sessions.default`) present a similar interface to a `NetworkConnection` object. The difference is that for helper methods, it will inject the sessions address/secret automatically on the higher level operations. | ||
|
||
In addition, a session object has a `withSecret` method that allows you to upgrade to a new session that can, for example, sign requests as needed. | ||
|
||
#### Example Usage | ||
|
||
```javascript | ||
|
||
// watch an account on both live and testnet | ||
let sessions = $get('stellard.Sessions'); | ||
let live = sessions.create("account_live", { address: "gM4Fpv2QuHY4knJsQyYGKEHFGw3eMBwc1U", connection: 'live' }); | ||
let test = sessions.create("account_test", { address: "gM4Fpv2QuHY4knJsQyYGKEHFGw3eMBwc1U", connection: 'test' }); | ||
|
||
live.listenForPayments(); | ||
test.listenForPayments(); | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
|
||
|
||
export class MismatchedAddressError extends Error { } | ||
export class SessionAlreadyDefinedError extends Error { } | ||
export class SessionNotFoundError extends Error { } | ||
export class ConnectionNotFoundError extends Error { } | ||
|
||
export class TransactionFailedError extends Error { | ||
constructor(result) { | ||
super(`Transaction Failed: ${result.engine_result}`); | ||
this.result = result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Module, mod as mcsCore } from "mcs-core"; | ||
|
||
export const mod = new Module('mcs-stellard'); | ||
|
||
mod.use(mcsCore.name); | ||
|
||
mod.services = require.context("./services", true); | ||
mod.setupBlocks = require.context("./setup-blocks", true); | ||
|
||
mod.define(); | ||
|
||
export * from "./errors"; | ||
export { AddressSecretPair } from "./lib/address-secret-pair"; | ||
|
||
export let lib = require("stellar-lib"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
let stellarLib = require('stellar-lib'); | ||
|
||
export class AddressSecretPair { | ||
constructor(seed) { | ||
/*jshint camelcase: false */ | ||
|
||
this.stellarSeed = new stellar.Seed(); | ||
|
||
if (seed) { | ||
this.stellarSeed.parse_json(seed); | ||
} else { | ||
this.stellarSeed.random(); | ||
} | ||
} | ||
|
||
get secret() { | ||
return this.stellarSeed.to_json(); | ||
} | ||
|
||
get address() { | ||
return this.stellarSeed | ||
.get_key() | ||
.get_address() | ||
.to_json() | ||
; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
let _ = require("lodash"); | ||
let stellarLib = require('stellar-lib'); | ||
|
||
window.stellar = stellarLib; | ||
|
||
export class NetworkConnection { | ||
constructor($q, network, name, connectionSpec) { | ||
this.$q = $q; | ||
this.network = network; | ||
this.name = name; | ||
this.connectionSpec = connectionSpec; | ||
this.connected = false; | ||
this._remote = new stellarLib.Remote(connectionSpec, true); | ||
|
||
this._remote.on('connected', () => { | ||
/*jshint camelcase: false */ | ||
// TODO: need to figure out why this isn't being set when we connect to the stellard | ||
this._remote._reserve_base=50*1000000; | ||
this._remote._reserve_inc=10*1000000; | ||
this.connected = true; | ||
this.network.onConnected(this); | ||
|
||
if(this.waitingForConnection) { | ||
this.waitingForConnection.resolve(this); | ||
} | ||
}); | ||
|
||
this._remote.on('connecting', () => this.network.onConnecting(this)); | ||
this._remote.on('disconnected', () => this.network.onDisconnected(this)); | ||
this._remote.on('reconnecting', (t) => this.network.onReconnecting(this, t)); | ||
this._remote.on('transaction', (tx) => this.network.onTransaction(this, tx)); | ||
} | ||
|
||
disconnect() { | ||
this._remote.disconnect(); | ||
this.connected = false; | ||
|
||
this._remote.removeAllListeners('connected'); | ||
this._remote.removeAllListeners('disconnected'); | ||
this._remote.removeAllListeners('reconnecting'); | ||
this._remote.removeAllListeners('connecting'); | ||
this._remote.removeAllListeners('transaction'); | ||
|
||
} | ||
|
||
forceReconnect() { | ||
/* jshint camelcase:false */ | ||
this._remote.force_reconnect(); | ||
} | ||
|
||
ensureConnected() { | ||
if (this.connected) { | ||
return this.$q.when(this); | ||
} else if (this.waitingForConnection) { | ||
return this.waitingForConnection.promise; | ||
} else { | ||
this.waitingForConnection = this.$q.defer(); | ||
this._remote.connect(); | ||
return this.waitingForConnection.promise; | ||
} | ||
} | ||
|
||
sendRequest(method, params) { | ||
let req = new stellarLib.Request(this._remote, method); | ||
|
||
// fold the params into the message object | ||
_.extend(req.message, params); | ||
|
||
var deferred = this.$q.defer(); | ||
|
||
req.on('success', deferred.resolve); | ||
req.on('error', deferred.reject); | ||
req.request(); | ||
|
||
return deferred.promise; | ||
} | ||
|
||
sendTransaction(tx) { | ||
let deferred = this.$q.defer(); | ||
|
||
tx.on('success', deferred.resolve); | ||
tx.on('error', deferred.reject); | ||
tx.submit(); | ||
|
||
return deferred.promise; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
let { AddressSecretPair } = require("../lib/address-secret-pair"); | ||
let { MismatchedSecretError } = require("../errors"); | ||
|
||
export class Session { | ||
constructor(address, secret, connection) { | ||
this.address = address; | ||
this.secret = secret; | ||
this.connection = connection; | ||
} | ||
|
||
withSecret(secret) { | ||
let source = new AddressSecretPair(secret); | ||
|
||
if (source.address !== this.address) { | ||
throw new MismatchedSecretError(); | ||
} | ||
|
||
return new Session(source.address, source.secret, this.connection); | ||
} | ||
|
||
sendRequest(...args) { | ||
return this.connection.sendRequest(...args); | ||
} | ||
|
||
sendTransaction(...args) { | ||
return this.connection.sendTransaction(...args); | ||
} | ||
|
||
ensureConnected() { | ||
return this.connection.ensureConnected().then(() => this); | ||
} | ||
|
||
destroy() { | ||
//TODO: any cleanup needed | ||
} | ||
|
||
//TODO: add helper methods here. getBalance, etc. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"name": "mcs-stellard", | ||
"version": "0.0.1", | ||
"description": "The mcs-stellard modules provides the communication layer with stellard and session containers.", | ||
"keywords": ["stellar", "mcs"], | ||
"scripts": { | ||
"test": "gulp test" | ||
}, | ||
"author": "Stellar Development Foundation <stellar@stellar.org>", | ||
"license": "ISC", | ||
"repository": { | ||
"type": "git", | ||
"url": "http://github.com/stellar/mcs-stellard.git" | ||
}, | ||
"dependencies": { | ||
"mcs-core": "git+https://github.com/stellar/mcs-core.git#master", | ||
"stellar-lib": "git+https://github.com/stellar/stellar-lib.git#master" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
let _ = require('lodash'); | ||
let { NetworkConnection } = require("../lib/network-connection"); | ||
|
||
/** | ||
The Network service is used to communicate with the Stellar network. | ||
@namespace stellard.Network | ||
*/ | ||
import { ConnectionNotFoundError } from "../errors"; | ||
|
||
class Network { | ||
constructor($rootScope, $timeout, $q, config) { | ||
this.$rootScope = $rootScope; | ||
this.$timeout = $timeout; | ||
this.$q = $q; | ||
this.config = config; | ||
this.connections = {}; | ||
} | ||
|
||
shutdown() { | ||
this.connections.forEach(r => r.disconnect()); | ||
this.connections.clear(); | ||
} | ||
|
||
ensureConnected(name) { | ||
try { | ||
return this._getConnection(name).ensureConnected(); | ||
} catch(e) { | ||
return this.$q.reject(e); | ||
} | ||
} | ||
|
||
get(name) { | ||
return this._getConnection(name); | ||
} | ||
|
||
forceReconnect(name) { | ||
let connection = this.connections[name]; | ||
connection.forceReconnect(); | ||
} | ||
|
||
// NetworkConnection callbacks | ||
|
||
onConnecting(connection) { | ||
this._safeBroadcast('stellar-network:connecting', connection.name); | ||
} | ||
|
||
onConnected(connection) { | ||
this._safeBroadcast('stellar-network:connected', connection.name); | ||
} | ||
|
||
onDisconnected(connection) { | ||
this._safeBroadcast('stellar-network:disconnected', connection.name); | ||
} | ||
|
||
onReconnecting(connection, timeout) { | ||
this._safeBroadcast('stellar-network:reconnecting', connection.name, timeout); | ||
} | ||
|
||
onTransaction(connection, tx) { | ||
this._safeBroadcast('stellar-network:transaction', connection.name, tx); | ||
} | ||
|
||
_getConnection(name) { | ||
if(!this.connections[name]) { | ||
let config = this._getConnectionSpec(name); | ||
this.connections[name] = new NetworkConnection(this.$q, this, name, config); | ||
} | ||
|
||
return this.connections[name]; | ||
} | ||
|
||
_getConnectionSpec(name) { | ||
let configKey = `stellard/connections/${name}`; | ||
let connectionSpec = this.config.get(configKey); | ||
|
||
if (!connectionSpec) { | ||
throw new ConnectionNotFoundError(`No connection config found at key: ${configKey}`); | ||
} | ||
|
||
return connectionSpec; | ||
} | ||
|
||
_safeBroadcast(event, ...args) { | ||
this.$timeout(() => { | ||
this.$rootScope.$broadcast(event, ...args); | ||
}); | ||
} | ||
} | ||
|
||
Network.$inject = ["$rootScope", "$timeout", "$q", 'mcs-core.Config']; | ||
|
||
module.exports = function(mod) { | ||
mod.service("Network", Network); | ||
}; |
Oops, something went wrong.