1 | 'use strict'
|
2 |
|
3 | const ExecInfo = require('./ExecInfo')
|
4 | const Promise = require('bluebird')
|
5 | const _ = require('lodash')
|
6 | const { execHook, logError, possiblyCallback, resultsTransform } =
|
7 | require('./utils')
|
8 |
|
9 |
|
10 | class CommandBinder {
|
11 |
|
12 | constructor (server, transport, userName) {
|
13 | this.server = server
|
14 | this.transport = transport
|
15 | this.userName = userName
|
16 | }
|
17 |
|
18 | commandWatcher (id, name) {
|
19 | this.server.runningCommands++
|
20 | return Promise.resolve().disposer(() => {
|
21 | this.server.runningCommands--
|
22 | if (this.transport.closed && this.server.runningCommands <= 0) {
|
23 | this.server.emit('commandsFinished')
|
24 | }
|
25 | })
|
26 | }
|
27 |
|
28 | makeCommand (name, fn) {
|
29 | let { validator } = this.server
|
30 | let beforeHook = this.server.hooks[`${name}Before`]
|
31 | let afterHook = this.server.hooks[`${name}After`]
|
32 | return (args, info) => {
|
33 | let execInfo = new ExecInfo()
|
34 | _.assign(execInfo, { server: this.server, userName: this.userName })
|
35 | _.assign(execInfo, info)
|
36 | _.assign(execInfo, validator.splitArguments(name, args))
|
37 | return Promise.using(
|
38 | this.commandWatcher(info.id, name),
|
39 | () => validator.checkArguments(name, ...execInfo.args)
|
40 | .then(() => {
|
41 | if (beforeHook && !execInfo.bypassHooks) {
|
42 | return execHook(beforeHook, execInfo)
|
43 | } else {
|
44 | return Promise.resolve()
|
45 | } })
|
46 | .then(results => {
|
47 | if (results && results.length) { return results }
|
48 | return fn(...execInfo.args, execInfo)
|
49 | .then(result => { execInfo.results = [result] },
|
50 | error => { execInfo.error = error })
|
51 | .then(() => {
|
52 | if (afterHook && !execInfo.bypassHooks) {
|
53 | return execHook(afterHook, execInfo)
|
54 | } else {
|
55 | return Promise.resolve()
|
56 | } })
|
57 | .then(results => {
|
58 | if (results && results.length) {
|
59 | return results
|
60 | } else if (execInfo.error) {
|
61 | return Promise.reject(execInfo.error)
|
62 | } else {
|
63 | return execInfo.results
|
64 | }
|
65 | })
|
66 | }))
|
67 | .catch(error => logError(error))
|
68 | }
|
69 | }
|
70 |
|
71 | bindDisconnect (id, fn) {
|
72 | let server = this.server
|
73 | let hook = this.server.hooks.onDisconnect
|
74 | this.transport.bindHandler(id, 'disconnect', () => {
|
75 | return Promise.using(
|
76 | this.commandWatcher(id, 'disconnect'),
|
77 | () => fn(id)
|
78 | .catch(error => logError(error))
|
79 | .catchReturn()
|
80 | .then(() => execHook(hook, server, id))
|
81 | .catch(error => logError(error))
|
82 | .catchReturn())
|
83 | })
|
84 | }
|
85 |
|
86 | bindCommand (id, name, fn) {
|
87 | let cmd = this.makeCommand(name, fn)
|
88 | let useErrorObjects = this.server.useRawErrorObjects
|
89 | let info = {id}
|
90 | return this.transport.bindHandler(id, name, function () {
|
91 | let [args, cb] = possiblyCallback(arguments)
|
92 | let ack = resultsTransform(useErrorObjects, cb)
|
93 | return cmd(args, info).asCallback(ack, { spread: true })
|
94 | })
|
95 | }
|
96 |
|
97 | }
|
98 |
|
99 | module.exports = CommandBinder
|