package main import ( "fmt" "sync" "time" occ "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/clients/operatorchannelclient" oc "git.novox.be/novox/mesh-contracts/operator-and-conversation/go/seats/operatorchannel" ) // fakeOperator is the gate's bucket asks and the teller behind it: it keeps the asks written, and answers as the test says // (the teller's answer under the ask's key). In auto mode it approves every ask the moment it is read (the tests of other // behaviour, which are not about the Approve). An ask is known here by its key (meshdeliveryclient MergeAskKey), as the // delivery keeps it. type fakeOperator struct { mu sync.Mutex now func() time.Time auto bool asked []oc.Ask byKey map[string]Ask order []string seen map[string]bool cancelled []string state map[string]string answers map[string]*Answer refuse error } func newFakeOperator(now func() time.Time) *fakeOperator { return &fakeOperator{now: now, byKey: map[string]Ask{}, seen: map[string]bool{}, state: map[string]string{}, answers: map[string]*Answer{}} } func (o *fakeOperator) Ask(key string, a Ask) error { o.mu.Lock() defer o.mu.Unlock() if o.refuse != nil { return o.refuse } ask, err := askOf(a) if err != nil { return err } if err := occ.Check(ask, o.now()); err != nil { return err } if _, err := EncodeAsk(a); err != nil { return err } if o.state[key] == "open" && SameAsk(o.byKey[key], a) { return nil // the same ask is there, as kvOperator leaves it } o.asked = append(o.asked, ask) o.byKey[key] = a if _, known := o.seen[key]; !known { o.order = append(o.order, key) o.seen[key] = true } o.state[key] = "open" delete(o.answers, key) return nil } func (o *fakeOperator) Cancel(key string) error { o.mu.Lock() defer o.mu.Unlock() o.cancelled = append(o.cancelled, key) o.state[key] = "cancelled" return nil } func (o *fakeOperator) Where(key string) (*Answer, error) { o.mu.Lock() defer o.mu.Unlock() if o.auto && o.state[key] == "open" { o.answerLocked(key, OptionApprove) } return o.answers[key], nil } // ask is the router's ask at a key, as the gate composed it. func (o *fakeOperator) ask(key string) oc.Ask { if a, ok := o.byKey[key]; ok { ask, err := askOf(a) if err != nil { panic(err) } return ask } panic("no ask " + key) } func (o *fakeOperator) answerLocked(key, option string) { a := o.ask(key) opt, _ := occ.OptionOf(a, option) o.state[key] = "answered" o.answers[key] = &Answer{Option: option, Warrant: fmt.Sprintf("%s@%s", a.ID, o.now().UTC().Format(time.RFC3339)), Words: "the operator, via telegram, chose " + opt.Label} } // answer is the operator's choice, proven to the teller by the router and written by it. func (o *fakeOperator) answer(key, option string) { o.mu.Lock() defer o.mu.Unlock() o.answerLocked(key, option) } // open is the keys of the asks waiting for an answer, in the order asked. func (o *fakeOperator) open() []string { o.mu.Lock() defer o.mu.Unlock() var out []string for _, k := range o.order { if o.state[k] == "open" { out = append(out, k) } } return out } func (o *fakeOperator) count() int { o.mu.Lock(); defer o.mu.Unlock(); return len(o.asked) }