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  }