Comparing version 0.0.9 to 0.0.10
@@ -30,4 +30,5 @@ import Message from './message'; | ||
receive(message: MessageSerialized, socket: Socket): void; | ||
handleFromPeer(socket?: Socket, message?: MessageSerialized): Peer | undefined; | ||
votePublicIp(ip: string): void; | ||
} | ||
export default Network; |
@@ -6,3 +6,2 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var peer_1 = __importDefault(require("./peer")); | ||
var message_1 = __importDefault(require("./message")); | ||
@@ -16,3 +15,3 @@ var registry_1 = __importDefault(require("./registry")); | ||
var nat_upnp_1 = __importDefault(require("nat-upnp")); | ||
var peer_2 = __importDefault(require("./peer")); | ||
var peer_1 = __importDefault(require("./peer")); | ||
var ipvotes_1 = __importDefault(require("./ipvotes")); | ||
@@ -28,3 +27,3 @@ var Network = /** @class */ (function () { | ||
this.votes = new ipvotes_1.default(); | ||
this.node = new peer_2.default(new address_1.default(host, port), 'alive', this.id.uuid); | ||
this.node = new peer_1.default(new address_1.default(host, port), 'alive', this.id.uuid); | ||
this.reg = new registry_1.default(this.events, this.node, cache); | ||
@@ -143,3 +142,3 @@ this.pool = new pool_1.default(this.events, this.id, this.reg); | ||
var _this = this; | ||
this.send(node, new message_1.default('locate', {}), function (err) { return err && _this.events.emit('error', new Error('Error during locate: ' + err)); }, true); | ||
this.send(node, new message_1.default('locate', {}), function (err) { return err && _this.events.emit('error', new Error('Error during locate: ' + err)); }); | ||
}; | ||
@@ -162,6 +161,10 @@ Network.prototype.broadcast = function (message) { | ||
var _this = this; | ||
this.events.emit('message:received', message, socket); | ||
try { | ||
// Act on incoming messages | ||
if (message.type === 'registry') { | ||
// Bail out if message.type is missing | ||
if (!message.type) { | ||
this.events.emit('error', 'Invalid message received'); | ||
return; | ||
} | ||
// Run default message handlers | ||
switch (message.type) { | ||
case 'registry': { | ||
// Handle incoming batch update | ||
@@ -171,24 +174,31 @@ if (message.payload && message.payload.registry) { | ||
} | ||
break; | ||
} | ||
else if (message.type === 'locate') { | ||
case 'locate': { | ||
this.reply(socket, new message_1.default('registry', { registry: this.reg.serialize('alive') }), function (err) { | ||
return _this.events.emit('error', 'Error during reply ' + err); | ||
}); | ||
break; | ||
} | ||
else if (message.type === 'ping') { | ||
// Handle from node | ||
case 'ping': { | ||
if (message.payload && message.payload.node) { | ||
var resolvedNode = new peer_2.default(message.payload.node.address, 'pending', message.payload.node.uuid); | ||
socket.setNode(resolvedNode); | ||
this.reg.update(resolvedNode, socket); | ||
this.reply(socket, new message_1.default('pong', { node: this.node, publicIp: socket.remoteAddress }), function (err) { return err && _this.events.emit('error', new Error('Error during reply: ')); }); | ||
// Handle from peer | ||
var resolvedPeer = this.handleFromPeer(socket, message); | ||
// Try to send a public pong, informing remote peer of it's connectivity, set noCache to true to use a new connection | ||
if (resolvedPeer) { | ||
this.send(resolvedPeer, new message_1.default('publicpong', { node: this.node, publicIp: socket.remoteAddress }), function (err) { return err && _this.events.emit('error', new Error('Error during reply: ')); }, true); | ||
} | ||
// Send a reply on active socket, so that the remote peer gets a reply even if it's not publically available | ||
this.reply(socket, new message_1.default('pong', { node: this.node }), function (err) { return err && _this.events.emit('error', new Error('Error during reply: ')); }); | ||
} | ||
break; | ||
} | ||
else if (message.type === 'pong') { | ||
case 'pong': { | ||
// Handle from node | ||
if (message.payload && message.payload.node) { | ||
var resolvedNode = new peer_1.default(message.payload.node.address, 'alive', message.payload.node.uuid); | ||
socket.setNode(resolvedNode); | ||
this.reg.update(resolvedNode, socket); | ||
} | ||
this.handleFromPeer(socket, message); | ||
break; | ||
} | ||
case 'publicpong': { | ||
// Handle from node | ||
this.handleFromPeer(socket, message); | ||
// Handle public ip votes | ||
@@ -198,6 +208,21 @@ if (message.payload && message.payload.publicIp) { | ||
} | ||
break; | ||
} | ||
default: { | ||
// Notify event system that a unhandled message arrived | ||
this.events.emit('message:unhandled', message, socket); | ||
break; | ||
} | ||
} | ||
catch (e) { | ||
this.events.emit('error', 'Failed to receive message: ' + e); | ||
// Notify event system that a message arrived | ||
this.events.emit('message:received', message, socket); | ||
}; | ||
Network.prototype.handleFromPeer = function (socket, message) { | ||
// Use ip from active socket, use port from supplied information | ||
if (socket && socket.remoteAddress && message && message.payload && message.payload.node) { | ||
var resolvedAddress = new address_1.default(socket.remoteAddress, message.payload.node.address.port); | ||
var resolvedNode = new peer_1.default(resolvedAddress, 'pending', message.payload.node.uuid); | ||
socket.setNode(resolvedNode); | ||
this.reg.update(resolvedNode, socket); | ||
return resolvedNode; | ||
} | ||
@@ -204,0 +229,0 @@ }; |
{ | ||
"name": "decene", | ||
"version": "0.0.9", | ||
"version": "0.0.10", | ||
"description": "Framework for creating decentralised distributed p2p networks.", | ||
@@ -5,0 +5,0 @@ "author": "Hexagon <github.com/hexagon>", |
125
README.md
@@ -7,2 +7,125 @@ # Work in progress | ||
See project hexagon/decene-examples | ||
## Short version | ||
See project ```hexagon/decene-examples``` | ||
## A little longer version | ||
Fairly complete and minimal example of how to use decent... Untested code! | ||
```javascript | ||
const | ||
{ network, encryption } = require("decene"), | ||
fs = require('fs'); // fs is used to read/write registry cache to disk | ||
// Settings | ||
let idLocation = '~/.decene.id'; | ||
let cacheLocation = "~/.decene.registy"; | ||
// Try to load identity from cache, or create a new identity | ||
let id = id || encryption.loadIdentity(idLocation); | ||
if (!id) { | ||
// Create | ||
id = encryption.newIdentity(idLocation); | ||
if (!id) { | ||
console.log("Could not read or create identity, bailing out."); | ||
process.exit(0); | ||
} else { | ||
console.log("New identity generated and stored at " + cacheLocation); | ||
} | ||
} | ||
// Try to load registry cache | ||
let cache; | ||
try { | ||
cache = JSON.parse(fs.readFileSync(cacheLocation, 'utf8')); | ||
} catch (err) { | ||
console.error('Warning: Could not load cache.'); | ||
} | ||
// Set up network client, listen at 0.0.0.0:47474, use my.decent.spawn.address.fake:47474 as "spawn" in case no local cache is available | ||
var d = new network(id,"0.0.0.0","47474","my.decent.spawn.address.fake:47474",cache); | ||
// Handle network events | ||
d.events.on('state:changed',(prevState,curState) => { | ||
console.log("State changed: "+prevState+" -> "+curState); | ||
}); | ||
d.events.on('server:error', (err) => console.error("Server Error:"+err)); | ||
d.events.on('socket:error', (err) => console.error("Socket Error:"+err)); | ||
d.events.on('error', (err) => console.error("Generic Error:"+err)); | ||
d.events.on('server:listening', (port) => console.log("Listening at " + port)); | ||
d.events.on('ip:changed',(ip) => console.log("Public ip verified: "+ip)); | ||
// A message is received (could be core, or application specific message) | ||
d.events.on('message:received', (message, socket) => { | ||
if (message.type) { | ||
let hasPayload = message.payload ? "yes" : "no"; | ||
console.log(message.type + ' > payload : ' + hasPayload); | ||
} | ||
}); | ||
// A unhandled message is received this is an invalid, or application specific message | ||
d.events.on('message:unhandled', (message, socket) => { | ||
if (message.type === "mycustommessage") { | ||
let hasPayload = message.payload ? "yes" : "no"; | ||
console.log("Custom message received > payload : " + hasPayload); | ||
} | ||
}); | ||
// Handle registry events | ||
d.events.on('node:discover', (node) => { console.log('Discover: ' + node.uuid ); }); | ||
// Handle registry disk cache | ||
d.events.on('registry:batch', (node) => { | ||
fs.writeFile(cacheLocation, JSON.stringify(d.reg.serialize()), err => { | ||
if (err) { | ||
gui.log.log("Registry cache flush failed: " + err); | ||
return; | ||
} else { | ||
gui.log.log("Registry cache flushed to disc"); | ||
} | ||
}) | ||
}); | ||
``` | ||
# Development of this framework | ||
1. Clone decene adjacent to your reference project, using decent-examples | ||
```bash | ||
cd my-projects-folder | ||
git clone ..../decene | ||
git clone ..../decene-examples``` | ||
2. Edit the decene imort in the reference project, example | ||
```javascript | ||
// Local decene development using adjacent dir | ||
var {network, encryption } = require("../../decene/lib"), | ||
// Normal mode, using decene from npmjs | ||
// var {network, encryption } = require("decene"), | ||
``` | ||
3. Build decene, to generate lib folder from typescript code | ||
```bash | ||
cd decene | ||
npm run-script build | ||
``` | ||
4. Run your reference project, now you are using the local version of decene | ||
5. When you are ready to commit to decene, make sure everything is formatted, linted, tested and do build | ||
```bash | ||
npm run-script format | ||
npm run-script lint | ||
npm run-script test | ||
npm run-script build | ||
git add . | ||
git commit -m "Yay, committing working and tested code." | ||
``` |
47564
1101
131