Skip to content

Commit

Permalink
Merge 4c4e534 into 55022c0
Browse files Browse the repository at this point in the history
  • Loading branch information
yusefnapora committed Jan 13, 2017
2 parents 55022c0 + 4c4e534 commit 4033120
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 4 deletions.
21 changes: 21 additions & 0 deletions src/client/api/RestClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,27 @@ class RestClient {
.then(r => r.json())
}

getNodeManifest (): Promise<string> {
return this.getRequest('manifest/node')
.then(trimTextResponse)
}

getManifests (peerId: ?string = null): Promise<Array<Object>> {
let path = (peerId == null)
? 'manifest'
: `manifest/${peerId}`

return this.getRequest(path)
.then(r => new NDJsonResponse(r))
.then(r => r.values())
}

setManifests (...manifests: Array<Object>): Promise<boolean> {
const body = manifests.map(m => JSON.stringify(m)).join('\n')
return this.postRequest('manifest', body, false)
.then(parseBoolResponse)
}

shutdown (): Promise<boolean> {
return this.postRequest('shutdown', '', false)
.then(() => true)
Expand Down
15 changes: 15 additions & 0 deletions src/client/cli/commands/manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @flow

const path = require('path')

module.exports = {
command: 'manifest <subcommand>',
describe: 'Commands for setting and retrieving identity manifests. Use "manifest --help" to see subcommands.\n',
builder: (yargs: Function) => {
return yargs
.commandDir(path.join(__dirname, './manifest'))
.help()
.strict()
},
handler: () => {}
}
44 changes: 44 additions & 0 deletions src/client/cli/commands/manifest/add.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// @flow

const fs = require('fs')
const _ = require('lodash')
const RestClient = require('../../../api/RestClient')
const { subcommand, println } = require('../../util')
const { consumeStream } = require('../../../../common/util')

module.exports = {
command: 'add [filename]',
description: 'Add a signed manifest to the local node. ' +
'If `filename` is not given, will read from standard input.\n',
handler: subcommand((opts: {client: RestClient, filename?: string}) => {
const {client, filename} = opts
let streamName = 'standard input'
let inputStream = process.stdin
if (filename != null) {
streamName = filename
inputStream = fs.createReadStream(filename)
}

let manifest: Object

return consumeStream(inputStream)
.catch(err => {
throw new Error(`Error reading from ${streamName}: ${err.message}`)
})
.then(contents => {
manifest = JSON.parse(contents)
})
.then(() => client.getManifests())
.then(manifests => {
if (_.some(manifests, m => _.isEqual(m, manifest))) {
println('Node already contains manifest, ignoring')
return
}
manifests.push(manifest)
return client.setManifests(...manifests)
.then(() => {
println('Manifest added successfully')
})
})
})
}
14 changes: 14 additions & 0 deletions src/client/cli/commands/manifest/get.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// @flow

const RestClient = require('../../../api/RestClient')
const { subcommand, printJSON } = require('../../util')

module.exports = {
command: 'get [remotePeer]',
description: `Get the signed manifests for the local node or a remote peer.\n`,
handler: subcommand((opts: {client: RestClient, remotePeer?: string}) => {
const {client, remotePeer} = opts
return client.getManifests(remotePeer)
.then(m => printJSON(m))
})
}
44 changes: 44 additions & 0 deletions src/client/cli/commands/manifest/remove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// @flow

const fs = require('fs')
const _ = require('lodash')
const RestClient = require('../../../api/RestClient')
const { subcommand, println } = require('../../util')
const { consumeStream } = require('../../../../common/util')

module.exports = {
command: 'remove [filename]',
description: 'Remove a signed manifest from the local node. ' +
'If `filename` is not given, will read from standard input.\n',
handler: subcommand((opts: {client: RestClient, filename?: string}) => {
const {client, filename} = opts
let streamName = 'standard input'
let inputStream = process.stdin
if (filename != null) {
streamName = filename
inputStream = fs.createReadStream(filename)
}

let manifest: Object

return consumeStream(inputStream)
.catch(err => {
throw new Error(`Error reading from ${streamName}: ${err.message}`)
})
.then(contents => {
manifest = JSON.parse(contents)
})
.then(() => client.getManifests())
.then(manifests => {
const without = _.filter(manifests, m => !_.isEqual(m, manifest))
if (without.length === manifests.length) {
println('Node does not contain manifest, ignoring')
return
}
return client.setManifests(...without)
.then(() => {
println('Manifest removed successfully')
})
})
})
}
15 changes: 15 additions & 0 deletions src/client/cli/commands/manifest/self.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @flow

const RestClient = require('../../../api/RestClient')
const { subcommand, println } = require('../../util')

module.exports = {
command: 'self',
description: `Get the unsigned "node manifest" for the local node, ` +
`suitable for signing by mcid to produce a manifest.\n`,
handler: subcommand((opts: {client: RestClient}) => {
const {client} = opts
return client.getNodeManifest()
.then(m => println(m))
})
}
54 changes: 54 additions & 0 deletions src/client/cli/commands/manifest/set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// @flow

const fs = require('fs')
const RestClient = require('../../../api/RestClient')
const { subcommand, println } = require('../../util')
const { consumeStream } = require('../../../../common/util')

module.exports = {
command: 'set [filename]',
description: `Set the signed manifests for the local node, replacing any existing manifests. ` +
'If `filename is not given, will read from stdin`\n',
builder: {
ndjson: {
type: 'boolean',
description: 'If present, input should be newline-delimited json, one object per line. ' +
'Otherwise, input can be either a single json object, or an array of objects.',
default: 'false'
}
},
handler: subcommand((opts: {client: RestClient, filename?: string, ndjson: boolean}) => {
const {client, filename, ndjson} = opts
let streamName = 'standard input'
let inputStream = process.stdin
if (filename != null) {
streamName = filename
inputStream = fs.createReadStream(filename)
}

return consumeStream(inputStream)
.catch(err => {
throw new Error(`Error reading from ${streamName}: ${err.message}`)
})
.then(contents => {
let manifests = []
if (ndjson) {
manifests = contents.split('\n')
.filter(line => line && line.length > 0)
.map(line => JSON.parse(line))
} else {
const parsed = JSON.parse(contents)
if (Array.isArray(parsed)) {
manifests = parsed
} else {
manifests = [parsed]
}
}
return manifests
})
.then(manifests => client.setManifests(...manifests))
.then(() => {
println('Manifests set successfully')
})
})
}
21 changes: 19 additions & 2 deletions src/common/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

const Multihashing = require('multihashing')
import type { Writable } from 'stream'
import type { Writable, Readable } from 'stream'
import type { WriteStream } from 'tty'

/**
Expand Down Expand Up @@ -101,6 +101,22 @@ function printlnErr (output: string) {
writeln(output, process.stderr)
}
/**
* Read a stream until it ends, returning its contents as a string.
* @param stream
* @returns {Promise}
*/
function consumeStream (stream: Readable): Promise<string> {
return new Promise((resolve, reject) => {
const chunks = []
stream.on('error', err => reject(err))
stream.on('data', chunk => { chunks.push(chunk) })
stream.on('end', () => {
resolve(Buffer.concat(chunks).toString('utf-8'))
})
})
}

module.exports = {
promiseHash,
promiseTimeout,
Expand All @@ -109,5 +125,6 @@ module.exports = {
isB58Multihash,
writeln,
println,
printlnErr
printlnErr,
consumeStream
}
17 changes: 15 additions & 2 deletions src/protobuf/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ import type {
EnvelopeStatementMsg,
ArchiveStatementMsg,
StatementBodyMsg,
StatementMsg
StatementMsg,
ManifestMsg,
ManifestBodyMsg,
NodeManifestMsg
} from './types'

type AllProtos = {
Expand Down Expand Up @@ -82,6 +85,11 @@ type AllProtos = {
ArchiveStatement: ProtoCodec<ArchiveStatementMsg>,
StatementBody: ProtoCodec<StatementBodyMsg>,
Statement: ProtoCodec<StatementMsg>
},
manifest: {
Manifest: ProtoCodec<ManifestMsg>,
ManifestBody: ProtoCodec<ManifestBodyMsg>,
NodeManifest: ProtoCodec<NodeManifestMsg>
}
}

Expand All @@ -90,7 +98,7 @@ type AllProtos = {
// we're concatenating all of our protos into one big string
// Stop doing this when import works!
function loadProtos (): AllProtos {
const files = ['dir.proto', 'node.proto', 'stmt.proto']
const files = ['dir.proto', 'node.proto', 'stmt.proto', 'manifest.proto']

// parsing will fail if there's a `syntax` statement that's not the first line of the file
// so we remove them from the concatenated monster and add back as the first line
Expand Down Expand Up @@ -144,6 +152,11 @@ function loadProtos (): AllProtos {
ArchiveStatement: pb.ArchiveStatement,
StatementBody: pb.StatementBody,
Statement: pb.Statement
},
manifest: {
Manifest: pb.Manifest,
ManifestBody: pb.ManifestBody,
NodeManifest: pb.NodeManifest
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/protobuf/manifest.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
syntax = "proto3";
package proto;

message Manifest {
string entity = 1;
string keyId = 2;
ManifestBody body = 3;
int64 timestamp = 4;
bytes signature = 5;
}

message ManifestBody {
oneof body {
NodeManifest node = 1;
}
}

message NodeManifest {
string peer = 1;
string publisher = 2;
}
23 changes: 23 additions & 0 deletions src/protobuf/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,27 @@ export type StatementMsg = {
signature: Buffer,
};

// manifest.proto
// message Manifest {
// string entity = 1;
// string keyId = 2;
// ManifestBody body = 3;
// int64 timestamp = 4;
// bytes signature = 5;
// }
export type ManifestMsg = {
entity: string,
keyId: string,
body: ManifestBodyMsg,
timestamp: number,
signature: Buffer
}

export type ManifestBodyMsg = {node: NodeManifestMsg}

export type NodeManifestMsg = {
peer: string,
publisher: string
}

export type ProtoCodec<T> = { encode: (obj: T) => Buffer, decode: (buf: Buffer) => T }

0 comments on commit 4033120

Please sign in to comment.