-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathqq.coffee
122 lines (94 loc) · 2.82 KB
/
qq.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
Q = require 'q'
# Wrapper for Q promises that preserves a context along a
# promise chain. A context could be thought of as a logical
# processing thread. E.g. the current http request being processed.
# Simple use case is to have logging report the http request
# associated with the log message, across asynchronous logic.
# TODO: make it prototypically inherit from wrapped promise,
# to inherit most of the methods, as we really only need to wrap then().
class QqPromise
constructor: (@cxt, @promise) ->
#if not @cxt
#throw new Error("No cxt provided")
if process.DEV != false
@promise.fail (e) ->
console.log '(Promise failed, ' + e.toString().substring(0, 50).replace(/\n/, '') + '...)'
throw e
then: (fulfilled, rejected, progressed) =>
if fulfilled
fulfilled = @_wrap fulfilled
if rejected
rejected = @_wrap rejected
if progressed
progressed = @_wrap progressed
new QqPromise(@cxt, @promise.then(fulfilled, rejected, progressed))
fail: (fn) => @then null, fn, null
fin: (fn) =>
@promise.fin @_wrap(fn)
done: -> @promise.done()
catch: (rejected) => @promise.catch(rejected)
_wrap: (fn) ->
(v) =>
withContext @cxt, -> fn(v)
withContext = (cxt, block) ->
orig = process._qq_cxt
try
process._qq_cxt = cxt
return block()
finally
process._qq_cxt = orig
# TODO: wrap remaining funcs.
class Qq
defer: (cxt) =>
cxt ?= process._qq_cxt
d = Q.defer()
d.promise = new QqPromise(cxt, d.promise)
d
resolve: (val, cxt) =>
cxt ?= process._qq_cxt
new QqPromise(cxt, Q.resolve(val))
reject: (reason, cxt) =>
cxt ?= process._qq_cxt
new QqPromise(cxt, Q.reject(reason))
nfcall: (fn, args...) =>
new QqPromise(process._qq_cxt, Q(fn).nfapply(args))
ninvoke: (args...) =>
new QqPromise(process._qq_cxt, Q.ninvoke.apply(Q, args))
npost: (args...) =>
new QqPromise(process._qq_cxt, Q.npost.apply(Q, args))
all: (promises, cxt) =>
cxt ?= process._qq_cxt
Q.all promises
when: (promises, cxt) =>
cxt ?= process._qq_cxt
Q.when promises
catch: (object, rejected, cxt) =>
cxt ?= process._qq_cxt
Q.catch(object, rejected)
withContext: withContext
newThread: (name, block) =>
if not @log
@log = require('lib/log')('qq')
@resolve(null, {_desc:name})
.then =>
@log.info 'begin thread', name
return block()
.fail (er) ->
@log.error er
.fin ->
@log.info 'finished thread', name
return
maybeContext: => process._qq_cxt
decorate: (obj, methods) =>
qq = @
wrapped = {}
for m in methods
wrapped[m] = (args...) ->
qq.npost obj, m, args
return wrapped
context: =>
if process._qq_cxt
return process._qq_cxt
else
throw new Error('No current qq context')
module.exports = qq = new Qq