github.com/wfusion/gofusion@v1.1.14/routine/candy_utils.go (about) 1 package routine 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "reflect" 8 "runtime" 9 "strconv" 10 11 "github.com/wfusion/gofusion/common/utils" 12 ) 13 14 // NoMatchedError presents no future that returns matched result in WhenAnyTrue function. 15 type NoMatchedError struct { 16 Results []any 17 } 18 19 func (e *NoMatchedError) Error() string { 20 return "No matched future" 21 } 22 23 func (e *NoMatchedError) HasError() bool { 24 for _, ie := range e.Results { 25 if _, ok1 := ie.(error); ok1 { 26 return true 27 } 28 } 29 return false 30 } 31 32 func newNoMatchedError(results []any) *NoMatchedError { 33 return &NoMatchedError{results} 34 } 35 36 func newNoMatchedError1(e any) *NoMatchedError { 37 return &NoMatchedError{[]any{e}} 38 } 39 40 // AggregateError aggregate multi errors into an error 41 type AggregateError struct { 42 s string 43 InnerErrs []error 44 } 45 46 func (e *AggregateError) Error() string { 47 if e.InnerErrs == nil { 48 return e.s 49 } else { 50 buf := bytes.NewBufferString(e.s) 51 _, _ = buf.WriteString("\n\n") 52 for i, ie := range e.InnerErrs { 53 if ie == nil { 54 continue 55 } 56 _, _ = buf.WriteString("error appears in Future ") 57 _, _ = buf.WriteString(strconv.Itoa(i)) 58 _, _ = buf.WriteString(": ") 59 _, _ = buf.WriteString(ie.Error()) 60 _, _ = buf.WriteString("\n") 61 } 62 _, _ = buf.WriteString("\n") 63 return buf.String() 64 } 65 } 66 67 func newAggregateError1(s string, e any) *AggregateError { 68 return &AggregateError{newErrorWithStacks(s).Error(), []error{getError(e)}} 69 } 70 71 func newErrorWithStacks(i any) (e error) { 72 err := getError(i) 73 buf := bytes.NewBufferString(err.Error()) 74 _, _ = buf.WriteString("\n") 75 76 pcs := make([]uintptr, 50) 77 num := runtime.Callers(2, pcs) 78 for _, v := range pcs[0:num] { 79 fun := runtime.FuncForPC(v) 80 file, line := fun.FileLine(v) 81 name := fun.Name() 82 writeStrings(buf, []string{name, " ", file, ":", strconv.Itoa(line), "\n"}) 83 } 84 return errors.New(buf.String()) 85 } 86 87 func getAct(p *promise, act any) (f func(opt *candyOption) (r any, err error)) { 88 var ( 89 act1 func(...any) (any, error) 90 act2 func(Canceller, ...any) (any, error) 91 ) 92 canCancel := false 93 94 // convert the act to the function that has return value and error if act function haven't return value and error 95 switch v := act.(type) { 96 case func(): 97 act1 = func(...any) (any, error) { v(); return nil, nil } 98 case func() error: 99 act1 = func(...any) (any, error) { e := v(); return nil, e } 100 case func() (any, error): 101 act1 = func(a ...any) (any, error) { return v() } 102 case func(Canceller): 103 canCancel = true 104 act2 = func(canceller Canceller, a ...any) (any, error) { v(canceller); return nil, nil } 105 case func(Canceller) error: 106 canCancel = true 107 act2 = func(canceller Canceller, a ...any) (any, error) { e := v(canceller); return nil, e } 108 case func(Canceller) (any, error): 109 canCancel = true 110 act2 = func(canceller Canceller, a ...any) (any, error) { return v(canceller) } 111 default: 112 typ := reflect.TypeOf(v) 113 if typ.Kind() == reflect.Func { 114 act1 = utils.WrapFunc2[any, error](v) 115 } else { 116 if e, ok := v.(error); !ok { 117 _ = p.Resolve(v) 118 } else { 119 _ = p.Reject(e) 120 } 121 return nil 122 } 123 } 124 125 // If parameters of act function has a Canceller interface, the Future will be cancelled. 126 var canceller Canceller 127 if p != nil && canCancel { 128 canceller = p.Canceller() 129 } 130 131 // return proxy function of act function 132 f = func(opt *candyOption) (r any, err error) { 133 defer func() { 134 if e := recover(); e != nil { 135 err = newErrorWithStacks(e) 136 } 137 }() 138 139 if canCancel { 140 r, err = act2(canceller, opt.args...) 141 } else { 142 r, err = act1(opt.args...) 143 } 144 145 return 146 } 147 return 148 } 149 150 // Error handling struct and functions------------------------------ 151 type stringer interface { 152 String() string 153 } 154 155 func getError(i any) (e error) { 156 if i != nil { 157 switch v := i.(type) { 158 case error: 159 e = v 160 case string: 161 e = errors.New(v) 162 default: 163 if s, ok := i.(stringer); ok { 164 e = errors.New(s.String()) 165 } else { 166 e = fmt.Errorf("%v", i) 167 } 168 } 169 } 170 return 171 } 172 173 func writeStrings(buf *bytes.Buffer, strings []string) { 174 for _, s := range strings { 175 _, _ = buf.WriteString(s) 176 } 177 } 178 179 func startPipe(r *Result, pipeTask func(v any) *Future, pipePromise *promise) { 180 if pipeTask != nil { 181 f := pipeTask(r.Result) 182 f.OnSuccess(func(v any) { 183 _ = pipePromise.Resolve(v) 184 }).OnFailure(func(v any) { 185 _ = pipePromise.Reject(getError(v)) 186 }) 187 } 188 } 189 190 func getFutureReturnVal(r *Result) (any, error) { 191 switch r.Typ { 192 case ResultSuccess: 193 return r.Result, nil 194 case ResultFailure: 195 return nil, getError(r.Result) 196 default: 197 return nil, getError(r.Result) // &CancelledError{} 198 } 199 } 200 201 func execCallback( 202 r *Result, 203 dones []func(v any), 204 fails []func(v any), 205 always []func(v any), 206 cancels []func(), 207 ) { 208 if r.Typ == ResultCancelled { 209 for _, f := range cancels { 210 func() { 211 defer func() { 212 if e := recover(); e != nil { 213 err := newErrorWithStacks(e) 214 fmt.Println("error happens:\n ", err) 215 } 216 }() 217 f() 218 }() 219 } 220 return 221 } 222 223 var callbacks []func(v any) 224 if r.Typ == ResultSuccess { 225 callbacks = dones 226 } else { 227 callbacks = fails 228 } 229 230 forFs := func(s []func(v any)) { 231 forSlice(s, func(f func(v any)) { f(r.Result) }) 232 } 233 234 forFs(callbacks) 235 forFs(always) 236 } 237 238 func forSlice(s []func(v any), f func(func(v any))) { 239 for _, e := range s { 240 func() { 241 defer func() { 242 if e := recover(); e != nil { 243 err := newErrorWithStacks(e) 244 fmt.Println("error happens:\n ", err) 245 } 246 }() 247 f(e) 248 }() 249 } 250 }