@@ -3,148 +3,11 @@ package graphql
33import (
44 "context"
55 "fmt"
6- "sync"
76
87 "github.com/graphql-go/graphql/gqlerrors"
98 "github.com/graphql-go/graphql/language/ast"
109)
1110
12- // Subscriber subscriber
13- type Subscriber struct {
14- message chan interface {}
15- done chan interface {}
16- }
17-
18- // Message returns the subscriber message channel
19- func (c * Subscriber ) Message () chan interface {} {
20- return c .message
21- }
22-
23- // Done returns the subscriber done channel
24- func (c * Subscriber ) Done () chan interface {} {
25- return c .done
26- }
27-
28- // NewSubscriber creates a new subscriber
29- func NewSubscriber (message , done chan interface {}) * Subscriber {
30- return & Subscriber {
31- message : message ,
32- done : done ,
33- }
34- }
35-
36- // ResultIteratorParams parameters passed to the result iterator handler
37- type ResultIteratorParams struct {
38- ResultCount int64 // number of results this iterator has processed
39- Result * Result // the current result
40- Done func () // Removes the current handler
41- Cancel func () // Cancels the iterator, same as iterator.Cancel()
42- }
43-
44- // ResultIteratorFn a result iterator handler
45- type ResultIteratorFn func (p ResultIteratorParams )
46-
47- // holds subscription handler data
48- type subscriptionHanlderConfig struct {
49- handler ResultIteratorFn
50- doneFunc func ()
51- }
52-
53- // ResultIterator handles processing results from a chan *Result
54- type ResultIterator struct {
55- currentHandlerID int64
56- count int64
57- mx sync.Mutex
58- ch chan * Result
59- iterDone chan interface {}
60- subDone chan interface {}
61- cancelled bool
62- handlers map [int64 ]* subscriptionHanlderConfig
63- }
64-
65- func (c * ResultIterator ) incrimentCount () int64 {
66- c .mx .Lock ()
67- defer c .mx .Unlock ()
68- c .count ++
69- return c .count
70- }
71-
72- // NewResultIterator creates a new iterator and starts handling message on the result channel
73- func NewResultIterator (subDone chan interface {}, ch chan * Result ) * ResultIterator {
74- iterator := & ResultIterator {
75- currentHandlerID : 0 ,
76- count : 0 ,
77- iterDone : make (chan interface {}),
78- subDone : subDone ,
79- ch : ch ,
80- cancelled : false ,
81- handlers : map [int64 ]* subscriptionHanlderConfig {},
82- }
83-
84- go func () {
85- for {
86- select {
87- case <- iterator .iterDone :
88- subDone <- true
89- return
90- case res := <- iterator .ch :
91- if iterator .cancelled {
92- return
93- }
94-
95- count := iterator .incrimentCount ()
96- for _ , h := range iterator .handlers {
97- h .handler (ResultIteratorParams {
98- ResultCount : int64 (count ),
99- Result : res ,
100- Done : h .doneFunc ,
101- Cancel : iterator .Cancel ,
102- })
103- }
104- }
105- }
106- }()
107-
108- return iterator
109- }
110-
111- // adds a new handler
112- func (c * ResultIterator ) addHandler (handler ResultIteratorFn ) {
113- c .mx .Lock ()
114- defer c .mx .Unlock ()
115-
116- handlerID := c .currentHandlerID + 1
117- c .currentHandlerID = handlerID
118- c .handlers [handlerID ] = & subscriptionHanlderConfig {
119- handler : handler ,
120- doneFunc : func () {
121- c .removeHandler (handlerID )
122- },
123- }
124- }
125-
126- // removes a handler and cancels if no more handlers exist
127- func (c * ResultIterator ) removeHandler (handlerID int64 ) {
128- c .mx .Lock ()
129- defer c .mx .Unlock ()
130-
131- delete (c .handlers , handlerID )
132- if len (c .handlers ) == 0 {
133- c .Cancel ()
134- }
135- }
136-
137- // ForEach adds a handler and handles each message as they come
138- func (c * ResultIterator ) ForEach (handler ResultIteratorFn ) {
139- c .addHandler (handler )
140- }
141-
142- // Cancel cancels the iterator
143- func (c * ResultIterator ) Cancel () {
144- c .cancelled = true
145- c .iterDone <- true
146- }
147-
14811// SubscribeParams parameters for subscribing
14912type SubscribeParams struct {
15013 Schema Schema
@@ -158,14 +21,8 @@ type SubscribeParams struct {
15821}
15922
16023// Subscribe performs a subscribe operation
161- func Subscribe (p SubscribeParams ) * ResultIterator {
24+ func Subscribe (ctx context. Context , p SubscribeParams ) chan * Result {
16225 resultChannel := make (chan * Result )
163- doneChannel := make (chan interface {})
164- // Use background context if no context was provided
165- ctx := p .ContextValue
166- if ctx == nil {
167- ctx = context .Background ()
168- }
16926
17027 var mapSourceToResponse = func (payload interface {}) * Result {
17128 return Execute (ExecuteParams {
@@ -174,18 +31,18 @@ func Subscribe(p SubscribeParams) *ResultIterator {
17431 AST : p .Document ,
17532 OperationName : p .OperationName ,
17633 Args : p .VariableValues ,
177- Context : ctx ,
34+ Context : p . ContextValue ,
17835 })
17936 }
18037
18138 go func () {
18239 result := & Result {}
18340 defer func () {
18441 if err := recover (); err != nil {
185- fmt .Println ("SUBSCRIPTION RECOVERER" , err )
18642 result .Errors = append (result .Errors , gqlerrors .FormatError (err .(error )))
43+ resultChannel <- result
18744 }
188- resultChannel <- result
45+ close ( resultChannel )
18946 }()
19047
19148 exeContext , err := buildExecutionContext (buildExecutionCtxParams {
@@ -195,7 +52,7 @@ func Subscribe(p SubscribeParams) *ResultIterator {
19552 OperationName : p .OperationName ,
19653 Args : p .VariableValues ,
19754 Result : result ,
198- Context : ctx ,
55+ Context : p . ContextValue ,
19956 })
20057
20158 if err != nil {
@@ -263,7 +120,7 @@ func Subscribe(p SubscribeParams) *ResultIterator {
263120 Source : p .RootValue ,
264121 Args : args ,
265122 Info : info ,
266- Context : ctx ,
123+ Context : p . ContextValue ,
267124 })
268125 if err != nil {
269126 result .Errors = append (result .Errors , gqlerrors .FormatError (err .(error )))
@@ -279,14 +136,14 @@ func Subscribe(p SubscribeParams) *ResultIterator {
279136 }
280137
281138 switch fieldResult .(type ) {
282- case * Subscriber :
283- sub := fieldResult .(* Subscriber )
139+ case chan interface {} :
140+ sub := fieldResult .(chan interface {} )
284141 for {
285142 select {
286- case <- doneChannel :
287- sub .done <- true
143+ case <- ctx .Done ():
288144 return
289- case res := <- sub .message :
145+
146+ case res := <- sub :
290147 resultChannel <- mapSourceToResponse (res )
291148 }
292149 }
@@ -296,6 +153,6 @@ func Subscribe(p SubscribeParams) *ResultIterator {
296153 }
297154 }()
298155
299- // return a result iterator
300- return NewResultIterator ( doneChannel , resultChannel )
156+ // return a result channel
157+ return resultChannel
301158}
0 commit comments