package state import ( "errors" "fmt" "log" "reflect" ) type S map[string]any type SetState struct { States S Setters []Setter Broadcast bool // 广播或者指定 includes ExcludeReceivers []string IncludeReceivers []string } // State 增量状态同步 type State struct { options Options v any rv reflect.Value c chan SetState statesTmp S settersTmp []Setter done chan bool } // InitState 初始化状态 todo serializable distribute transfer func (s *State) InitState(ptrV any, opts ...Option) { t := reflect.TypeOf(ptrV) if t.Kind() != reflect.Ptr { panic("参数必须是ptr类型") } s.options = defaultOptions for _, opt := range opts { opt(&s.options) } s.v = ptrV s.rv = reflect.ValueOf(s.v) s.c = make(chan SetState, 16) s.statesTmp = S{} s.done = make(chan bool) } func (s *State) Chan() (c <-chan SetState, done <-chan bool) { return s.c, s.done } // State2Broadcast 聚合消息发送到管道进行广播 // excludeReceivers 忽略 receiver 列表 func (s *State) State2Broadcast(excludeReceivers ...string) { s.state2Pipe(true, nil, excludeReceivers) } // State2Assign 聚合消息发送到管道指定receiver发送 // includes 指定 receiver 列表 func (s *State) State2Assign(includesReceivers ...string) { s.state2Pipe(false, includesReceivers, nil) } func (s *State) state2Pipe(broadcast bool, includes []string, excludes []string) { if len(s.statesTmp) == 0 && len(s.settersTmp) == 0 { return } state := SetState{ States: s.statesTmp, Setters: s.settersTmp, Broadcast: broadcast, IncludeReceivers: includes, ExcludeReceivers: excludes, } s.statesTmp = S{} s.settersTmp = []Setter{} s.options.Mapping(state.States, &state.Setters) s.c <- state } func (s *State) StateIdleClean() { s.statesTmp = S{} s.settersTmp = []Setter{} } // SetState panic error func (s *State) SetState(state S) { err := s.setState0(state) if err != nil { panic(err) } } // SetStateEx return error func (s *State) SetStateEx(state S) (err error) { return s.setState0(state) } func (s *State) setState0(state S) (err error) { defer func() { if e := recover(); e != nil { if e2, ok := e.(string); ok { err = errors.New(e2) return } if e1, ok := e.(error); ok { err = e1 return } err = errors.New("recover setState") log.Printf("error recover setState: %v \n", e) } }() for k, v := range state { field := s.rv.Elem().FieldByName(k) if !field.CanSet() { return fmt.Errorf("%s cannot set", k) } setter, ok := v.(Setter) if !ok { if v == nil { field.Set(reflect.New(field.Type()).Elem()) } else { field.Set(reflect.ValueOf(v)) } s.statesTmp[k] = v } else { switch setter.T { case 2: // setArray fallthrough case 3: // setSlice ele := field.Index(setter.Index) if !ele.CanSet() { return fmt.Errorf("%s %d cannot set", k, setter.Index) } if setter.V == nil { ele.Set(reflect.New(ele.Type()).Elem()) } else { ele.Set(reflect.ValueOf(setter.V)) } case 4: // setMap field.SetMapIndex(reflect.ValueOf(setter.K2), reflect.ValueOf(setter.V)) case 5: // setStruct field2 := field.FieldByName(setter.K2) if !field2.CanSet() { return fmt.Errorf("%s.%s cannot set", k, setter.K2) } if setter.V == nil { field2.Set(reflect.New(field2.Type()).Elem()) } else { field2.Set(reflect.ValueOf(setter.V)) } case 6: // append slice if !field.CanSet() { return fmt.Errorf("%s.%s cannot set", k, setter.K) } if setter.V == nil { field.Set(reflect.Append(field, reflect.New(field.Type().Elem()).Elem())) } else { field.Set(reflect.Append(field, reflect.ValueOf(setter.V))) } case 7: // pop slice newV := field.Slice(0, field.Len()-setter.Index) field.Set(newV) case 8: // shift slice newV := field.Slice(setter.Index, field.Len()) field.Set(newV) } setter.K = k s.settersTmp = append(s.settersTmp, setter) } } return } func (s *State) Close() { s.done <- true close(s.c) return }