Browse Source

move cli across from server, and make some fixes

Kieran Gibb 2 years ago
parent
commit
a92f8fb69f
No known key found for this signature in database

+ 10
- 0
cobox-cli/bin/groups.js View File

@@ -0,0 +1,10 @@
1
+exports.command = 'groups'
2
+exports.desc = 'create, join, leave and mount'
3
+exports.builder = function (yargs) {
4
+  return yargs
5
+    .commandDir('groups')
6
+    .demandCommand()
7
+    .help()
8
+    .argv
9
+}
10
+exports.handler = function (argv) {}

+ 41
- 0
cobox-cli/bin/groups/create.js View File

@@ -0,0 +1,41 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onSuccess,
5
+  onError,
6
+  getInput,
7
+  printGroups,
8
+} = require('../../lib/bin/util')
9
+
10
+const request = require('../../lib/bin/request')
11
+
12
+exports.command = 'create'
13
+exports.desc = 'create a new group'
14
+exports.builder = {
15
+  name: {
16
+    description: 'the name of the group',
17
+    type: 'string',
18
+    alias: 'n',
19
+    demandOption: true
20
+  }
21
+}
22
+exports.handler = async function (argv) {
23
+  var name = argv.name,
24
+    data = { name },
25
+    response,
26
+    group
27
+
28
+  onSuccess('creating a new group...')
29
+
30
+  try {
31
+    response = await request.post(`/groups`, data)
32
+    group = response.data
33
+  } catch (error) {
34
+    response = error.response
35
+    var errors = response.data.errors
36
+    return onError(errors.map((err) => err.msg))
37
+  }
38
+
39
+  onSuccess(`successfully created ${name}`)
40
+  printGroups(group)
41
+}

+ 46
- 0
cobox-cli/bin/groups/drive.js View File

@@ -0,0 +1,46 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+
4
+const {
5
+  onSuccess,
6
+  onError,
7
+  printGroups
8
+} = require('../../util')
9
+
10
+const request = require('../../request')
11
+
12
+exports.command = 'drive'
13
+exports.desc = 'get drive history'
14
+exports.builder = {
15
+  address: {
16
+    description: 'the address of the group',
17
+    type: 'string',
18
+    alias: 'A'
19
+  },
20
+  name: {
21
+    description: 'the name of the group',
22
+    type: 'string',
23
+    alias: 'n',
24
+    demandOption: true
25
+  }
26
+}
27
+exports.handler = async function (argv) {
28
+  let address = argv.address,
29
+    name = argv.name,
30
+    id = argv.address || argv.name
31
+
32
+  var data = { name, address }
33
+
34
+  try {
35
+    var response = await request.get(`/groups/${id}/drive`, { data })
36
+    var messages = response.data
37
+    onSuccess(formatState(messages))
38
+  } catch (error) {
39
+    var errors = response.errors
40
+    return onError(response.errors.map((err) => err.msg))
41
+  }
42
+}
43
+
44
+function formatState (messages) {
45
+  return messages.map(msg => JSON.stringify(msg, null, 2))
46
+}

+ 69
- 0
cobox-cli/bin/groups/join.js View File

@@ -0,0 +1,69 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onSuccess,
5
+  onError,
6
+  getInput,
7
+  printGroups,
8
+} = require('../../lib/bin/util')
9
+
10
+const request = require('../../lib/bin/request')
11
+
12
+exports.command = 'join'
13
+exports.desc = 'join a group'
14
+exports.builder = {
15
+  address: {
16
+    description: 'the address of the group',
17
+    type: 'string',
18
+    alias: 'A',
19
+  },
20
+  name: {
21
+    description: 'the name of the group',
22
+    type: 'string',
23
+    alias: 'n',
24
+    demandOption: true
25
+  }
26
+}
27
+exports.handler = async function (argv) {
28
+  let address = argv.address,
29
+    name = argv.name,
30
+    id = argv.address || argv.name,
31
+    response,
32
+    group
33
+
34
+  var data = { name, address }
35
+
36
+  try {
37
+    response = await request.get(`/groups/${id}`, { data })
38
+    group = response.data
39
+  } catch (error) {
40
+    var errors = response.errors
41
+    onError(errors.map((err) => err.msg))
42
+  }
43
+
44
+  if (!group && !address)  return onError([`replicator does not exist, provide an address.`])
45
+
46
+  if (!group) {
47
+    onSuccess('creating a new group...')
48
+    try {
49
+      response = await request.post(`/groups`, data)
50
+      group = response.data
51
+    } catch (error) {
52
+      response = error.response
53
+      var errors = response.data.errors
54
+      return onError(errors.map((err) => err.msg))
55
+    }
56
+  }
57
+
58
+  try {
59
+    response = await request.post(`/groups/${group.address}/connections`, group)
60
+  } catch (error) {
61
+    response = error.response
62
+    var errors = response.data.errors
63
+    return onError(errors.map((err) => err.msg))
64
+  }
65
+
66
+  onSuccess(`successfully joined ${name}`)
67
+  onSuccess(`swarming on ${group.discoveryKey}`)
68
+  printGroups(group)
69
+}

+ 57
- 0
cobox-cli/bin/groups/leave.js View File

@@ -0,0 +1,57 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onError,
5
+  onSuccess,
6
+  printGroups
7
+} = require('../../lib/bin/util')
8
+
9
+const request = require('../../lib/bin/request')
10
+
11
+exports.command = 'leave'
12
+exports.desc = 'drop open connections with remote peers'
13
+exports.builder = {
14
+  address: {
15
+    description: 'the address of the group',
16
+    type: 'string',
17
+    alias: 'A',
18
+  },
19
+  name: {
20
+    description: 'the name of the group',
21
+    type: 'string',
22
+    alias: 'n',
23
+    demandOption: true
24
+  }
25
+}
26
+exports.handler = async function (argv) {
27
+  var id = argv.address || argv.name
28
+  if (!id) return onError('provide a name or address')
29
+
30
+  var response, group
31
+
32
+  var data = {
33
+    name: argv.name,
34
+    address: argv.address
35
+  }
36
+
37
+  try {
38
+    response = await request.get(`/groups/${id}`, { data })
39
+  } catch (error) {
40
+    response = error.response
41
+    var errors = response.data.errors
42
+    return onError(errors.map((err) => err.msg))
43
+  }
44
+
45
+  group = response.data
46
+
47
+  try {
48
+    response = await request.delete(`/groups/${id}/connections`, { data: group })
49
+  } catch (error) {
50
+    response = error.response
51
+    var errors = response.data.errors
52
+    return onError(errors.map((err) => err.message))
53
+  }
54
+
55
+  onSuccess(`connection for ${group.name} dropped.`)
56
+  printGroups(group)
57
+}

+ 21
- 0
cobox-cli/bin/groups/list.js View File

@@ -0,0 +1,21 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onError,
5
+  printGroups,
6
+} = require('../../lib/bin/util')
7
+
8
+const request = require('../../lib/bin/request')
9
+
10
+exports.command = 'list'
11
+exports.desc = 'list all groups'
12
+exports.builder = {}
13
+exports.handler = async function (argv) {
14
+  try {
15
+    var response = await request.get('/groups')
16
+    return printGroups(response.data)
17
+  } catch (err) {
18
+    var errors = response.errors
19
+    return onError(errors.map((err) => err.msg))
20
+  }
21
+}

+ 50
- 0
cobox-cli/bin/groups/mount.js View File

@@ -0,0 +1,50 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onSuccess,
5
+  onError,
6
+  printGroups,
7
+} = require('../../lib/bin/util')
8
+
9
+const request = require('../../lib/bin/request')
10
+
11
+exports.command = 'mount'
12
+exports.desc = "mount a group"
13
+exports.builder = {
14
+  address: {
15
+    description: 'the address for the group',
16
+    type: 'string',
17
+    alias: 'A',
18
+  },
19
+  name: {
20
+    description: 'the name of the group',
21
+    type: 'string',
22
+    alias: 'n',
23
+    demandOption: true
24
+  }
25
+}
26
+exports.handler = async function (argv) {
27
+  var id = argv.address || argv.name
28
+  if (!id) return onError('provide a name or address')
29
+
30
+  var data = { name: argv.name, address: argv.address }
31
+
32
+  try {
33
+    var response = await request.get(`/groups/${id}`, { data })
34
+  } catch (error) {
35
+    var errors = response.errors
36
+    return onError(errors.map((err) => err.msg))
37
+  }
38
+
39
+  var group = response.data
40
+
41
+  try {
42
+    var response = await request.post(`/groups/${group.address}/mounts`, group)
43
+  } catch (error) {
44
+    var errors = response.errors
45
+    return onError(errors.map((err) => err.msg))
46
+  }
47
+
48
+  onSuccess(`Mounted ${group.name} at ${response.data.location}.`)
49
+  printGroups(group)
50
+}

+ 49
- 0
cobox-cli/bin/groups/unmount.js View File

@@ -0,0 +1,49 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onError,
5
+  onSuccess,
6
+  printGroups
7
+} = require('../../lib/bin/util')
8
+
9
+const request = require('../../lib/bin/request')
10
+
11
+exports.command = 'unmount'
12
+exports.desc = "unmount a group"
13
+exports.builder = {
14
+  address: {
15
+    description: 'the address of the group',
16
+    type: 'string',
17
+    alias: 'A',
18
+  },
19
+  name: {
20
+    description: 'the name of the group',
21
+    type: 'string',
22
+    alias: 'n',
23
+    demandOption: true
24
+  }
25
+}
26
+exports.handler = async function (argv) {
27
+  var id = argv.address || argv.name
28
+  if (!id) return onError('provide a name or address')
29
+
30
+  var data = { name: argv.name, address: argv.address }
31
+
32
+  try {
33
+    var response = await request.get(`/groups/${id}`, { data })
34
+  } catch (err) {
35
+    var errors = response.errors
36
+    return onError(errors.map((err) => err.msg))
37
+  }
38
+
39
+  var group = response.data
40
+
41
+  try {
42
+    var response = await request.delete(`/groups/${id}/mounts`, { data: group })
43
+  } catch (error) {
44
+    var errors = response.errors
45
+    return onError(errors.map((err) => err.msg))
46
+  }
47
+
48
+  onSuccess(`Unmounted ${group.name || group.address}.`)
49
+}

+ 9
- 0
cobox-cli/bin/replicators.js View File

@@ -0,0 +1,9 @@
1
+exports.command = 'replicators'
2
+exports.desc = 'create, join, leave'
3
+exports.builder = function (yargs) {
4
+  return yargs.commandDir('replicators')
5
+    .demandCommand()
6
+    .help()
7
+    .argv
8
+}
9
+exports.handler = function (argv) {}

+ 70
- 0
cobox-cli/bin/replicators/join.js View File

@@ -0,0 +1,70 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onSuccess,
5
+  onError,
6
+  getInput,
7
+  printGroups,
8
+} = require('../../lib/bin/util')
9
+
10
+const request = require('../../lib/bin/request')
11
+
12
+exports.command = 'join'
13
+exports.desc = 'join on an address as a blind replicator'
14
+exports.builder = {
15
+  address: {
16
+    description: 'the address of the replicator',
17
+    type: 'string',
18
+    alias: 'A'
19
+  },
20
+  name: {
21
+    description: 'your local reference for the replicator',
22
+    type: 'string',
23
+    alias: 'n',
24
+    demandOption: true
25
+  }
26
+}
27
+exports.handler = async function (argv) {
28
+  let address = argv.address,
29
+    name = argv.name,
30
+    id = argv.address,
31
+    response,
32
+    replicator
33
+
34
+  var data = { name, address }
35
+
36
+  try {
37
+    response = await request.get(`/replicators/${id}`, { data })
38
+    replicator = response.data
39
+  } catch (error) {
40
+    response = error.response
41
+    var errors = response.data.errors
42
+    onError(errors.map((err) => err.msg))
43
+  }
44
+
45
+  if (!replicator && !address) return onError([`replicator does not exist, provide an address to replicate.`])
46
+
47
+  if (!replicator) {
48
+    onSuccess('creating a new replicator...')
49
+    try {
50
+      response = await request.post(`/replicators`, data)
51
+      replicator = response.data
52
+    } catch (error) {
53
+      response = error.response
54
+      var errors = response.data.errors
55
+      return onError(errors.map((err) => err.msg))
56
+    }
57
+  }
58
+
59
+  try {
60
+    response = await request.post(`/replicators/${replicator.address}/connections`, replicator)
61
+  } catch (error) {
62
+    response = error.response
63
+    var errors = response.data.errors
64
+    return onError(errors.map((err) => err.msg))
65
+  }
66
+
67
+  onSuccess(`successfully joined ${name}`)
68
+  onSuccess(`swarming on ${replicator.discoveryKey}`)
69
+  printGroups(replicator)
70
+}

+ 56
- 0
cobox-cli/bin/replicators/leave.js View File

@@ -0,0 +1,56 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onError,
5
+  onSuccess,
6
+  printGroups
7
+} = require('../../lib/bin/util')
8
+
9
+const request = require('../../lib/bin/request')
10
+
11
+exports.command = 'leave'
12
+exports.desc = 'drop open connections with remote peers'
13
+exports.builder = {
14
+  address: {
15
+    description: 'the address of the replicator',
16
+    type: 'string',
17
+    alias: 'A'
18
+  },
19
+  name: {
20
+    description: 'your local reference for the replicator',
21
+    type: 'string',
22
+    alias: 'n'
23
+  }
24
+}
25
+exports.handler = async function (argv) {
26
+  var id = argv.address || argv.name
27
+  if (!id) return onError('provide a name or address')
28
+
29
+  var response, replicator
30
+
31
+  var data = {
32
+    name: argv.name,
33
+    address: argv.address
34
+  }
35
+
36
+  try {
37
+    response = await request.get(`/replicators/${id}`, { data })
38
+  } catch (error) {
39
+    response = error.response
40
+    var errors = response.data.errors
41
+    return onError(errors.map((err) => err.msg))
42
+  }
43
+
44
+  replicator = response.data
45
+
46
+  try {
47
+    response = await request.delete(`/replicators/${id}/connections`, { data: replicator })
48
+  } catch (error) {
49
+    response = error.response
50
+    var errors = response.data.errors
51
+    return onError(errors.map((err) => err.message))
52
+  }
53
+
54
+  onSuccess(`connection for ${replicator.name} dropped.`)
55
+  printGroups(replicator)
56
+}

+ 21
- 0
cobox-cli/bin/replicators/list.js View File

@@ -0,0 +1,21 @@
1
+const chalk = require('chalk')
2
+const path = require('path')
3
+const {
4
+  onError,
5
+  printGroups,
6
+} = require('../../lib/bin/util')
7
+
8
+const request = require('../../lib/bin/request')
9
+
10
+exports.command = 'list'
11
+exports.desc = 'list all local blind replicators'
12
+exports.builder = {}
13
+exports.handler = async function (argv) {
14
+  try {
15
+    var response = await request.get('/replicators')
16
+    if (response.errors) return onError(errors.map((err) => err.msg))
17
+    return printGroups(response.data)
18
+  } catch (err) {
19
+    return onError(err.msg)
20
+  }
21
+}

+ 39
- 0
cobox-cli/bin/start.js View File

@@ -0,0 +1,39 @@
1
+const Config = require('cobox-config')
2
+const constants = require('cobox-constants')
3
+
4
+const App = require('cobox-server')
5
+const Server = require('cobox-server/server')
6
+
7
+exports.command = 'start'
8
+exports.desc = 'Start the server'
9
+exports.builder = {
10
+  storage: {
11
+    description: 'The storage path of your cobox configuration and cores',
12
+    type: 'string',
13
+    alias: 's',
14
+  },
15
+  mountdir: {
16
+    description: 'The root mount path for your groups',
17
+    type: 'string',
18
+    alias: 'm',
19
+  },
20
+  port: {
21
+    description: 'The server port for the application',
22
+    type: 'string',
23
+    alias: 'p',
24
+  },
25
+  host: {
26
+    description: 'The server host',
27
+    type: 'string',
28
+    alias: 'h',
29
+  }
30
+}
31
+exports.handler = function (argv) {
32
+  const storage = argv.storage || constants.storage
33
+  const config = Config(storage)
34
+  const location = argv.mountdir || config.options.get('mount') || constants.mountdir
35
+
36
+  const opts = { location, ...argv }
37
+  const app = App(config, opts)
38
+  Server(app, opts)
39
+}

+ 8
- 0
cobox-cli/cli.js View File

@@ -0,0 +1,8 @@
1
+#!/usr/bin/env node
2
+const yargs = require('yargs')
3
+const path = require('path')
4
+
5
+yargs.commandDir('bin')
6
+  .demandCommand()
7
+  .help()
8
+  .argv

+ 25
- 13
cobox-cli/package.json View File

@@ -1,20 +1,32 @@
1 1
 {
2 2
   "name": "cobox-cli",
3
+  "description": "a command line client for cobox",
3 4
   "version": "1.0.0",
4
-  "description": "a command-line application that talks to cobox-server",
5
-  "main": "index.js",
5
+  "bin": {
6
+    "cobox": "cli.js"
7
+  },
6 8
   "scripts": {
7
-    "test": "tape test/**/*.test.js"
9
+    "test": "tape test/**/*.test.js | tap-spec"
10
+  },
11
+  "author": "magma-collective",
12
+  "license": "AGPL-3.0-only",
13
+  "dependencies": {
14
+    "axios": "^0.19.0",
15
+    "chalk": "^3.0.0",
16
+    "cobox-config": "git+https://ledger-git.dyne.org/cobox/cobox-config#development",
17
+    "cobox-constants": "^1.0.0",
18
+    "cobox-server": "git+https://ledger-git.dyne.org/cobox/cobox-server#development",
19
+    "debug": "^4.1.1",
20
+    "yargs": "^14.2.0"
8 21
   },
9
-  "repository": {
10
-    "type": "git",
11
-    "url": "https://ledger-git.dyne.org/cobox/cobox-cli"
22
+  "devDependencies": {
23
+    "rimraf": "^3.0.0",
24
+    "tap-spec": "^5.0.0",
25
+    "tape": "^4.11.0",
26
+    "tape-plus": "^1.0.0",
27
+    "tmp": "^0.1.0"
12 28
   },
13
-  "keywords": [
14
-    "command-line",
15
-    "cli",
16
-    "cobox"
17
-  ],
18
-  "author": "magma collective",
19
-  "license": "AGPL-3.0-or-later"
29
+  "bugs": {
30
+    "url": "https://ledger-git.dyne.org/CoBox/cobox-cli"
31
+  }
20 32
 }

+ 7
- 0
cobox-cli/request.js View File

@@ -0,0 +1,7 @@
1
+const axios = require('axios')
2
+
3
+module.exports = axios.create({
4
+  baseURL: 'http://localhost:3000/',
5
+  timeout: 5000,
6
+  headers: { 'Content-type': 'application/json' }
7
+})

+ 54
- 0
cobox-cli/util.js View File

@@ -0,0 +1,54 @@
1
+const chalk = require('chalk')
2
+const readline = require('readline')
3
+
4
+function printGroups (groups) {
5
+  groups = Array.isArray(groups) ? groups : [groups]
6
+  console.log("-- Name --".padEnd(40), "-- Address --".padEnd(64))
7
+  for (const group of groups) {
8
+    const name = group.name || ''
9
+    console.log(
10
+      name.padEnd(40),
11
+      chalk.green(group.address),
12
+    )
13
+  }
14
+  console.log()
15
+}
16
+
17
+function getInput (message, cb) {
18
+  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
19
+  rl.question(message, (answer) => {
20
+    if (!answer) return getInput(message, cb)
21
+    cb(answer)
22
+    rl.close()
23
+  })
24
+}
25
+
26
+function onSuccess (msgs) {
27
+  msgs = Array.isArray(msgs) ? msgs : [msgs]
28
+  for (const msg of msgs) console.log(msg, '\n')
29
+}
30
+
31
+function onError (errs) {
32
+  errs = Array.isArray(errs) ? errs : [errs]
33
+  for (const err of errs) console.error(chalk.red(err), '\n')
34
+}
35
+
36
+function getName (name) {
37
+  var prompt = 'provide a name for your group...\n'
38
+  return new Promise((resolve, reject) => {
39
+    return next(null, name)
40
+
41
+    function next (err, name) {
42
+      if (err) return reject(err)
43
+      if (!name) getInput(prompt, next)
44
+      else return resolve(name)
45
+    }
46
+  })
47
+}
48
+
49
+module.exports = {
50
+  getInput,
51
+  printGroups,
52
+  onSuccess,
53
+  onError
54
+}