package model import ( "fmt" "log/slog" ) type RtssModel interface { // RtssModel unique id Uid() string } // 通道端口 type PipePort = string var ( // PipePortA 通道端口A PipePortA PipePort = "A" // PipePortB 通道端口B PipePortB PipePort = "B" // PipePortC 通道端口C PipePortC PipePort = "C" ) var ( twoPorts = []PipePort{PipePortA, PipePortB} threePorts = []PipePort{PipePortA, PipePortB, PipePortC} ) // 通道连接关系 type PipeLink struct { // 通道元素 Pipe PipeElement // 端口 Port PipePort } func NewPipeLink(pipe PipeElement, port PipePort) *PipeLink { if pipe == nil { panic("pipe is nil") } return &PipeLink{ Pipe: pipe, Port: port, } } func (pl *PipeLink) Debug() string { return DebugPipeLink(pl.Pipe, pl.Port) } func DebugPipeLink(p PipeElement, port PipePort) string { return fmt.Sprintf("{pipeUid=%s, port=%s}", p.Uid(), port) } // 通道元素 type PipeElement interface { RtssModel // 获取通道端口 Ports() []PipePort IsTwoPorts() bool IsThreePorts() bool // 获取指定端口连接的通道连接关系 GetLinkedElement(port PipePort) *PipeLink // 设置指定端口的通道连接关系 SetLinkedElement(port PipePort, pipeLink *PipeLink) error // 检查通道连接关系 CheckPipeLink() error } type TwoPortsPipeElement interface { PipeElement // 获取指定端口的对端通道连接关系 OppositePipeLink(port PipePort) *PipeLink } type ThreePortsPipeElement interface { PipeElement } func checkPipePortLink(pe PipeElement, port PipePort, pipeLink *PipeLink) error { if pipeLink == nil { slog.Debug("检查通道端口连接关系", "通道端口", DebugPipeLink(pe, port), "连接关系", "无连接") return nil } slog.Debug("检查通道端口连接关系", "通道端口", DebugPipeLink(pe, port), "连接关系", pipeLink.Debug()) plink := pipeLink.Pipe.GetLinkedElement(pipeLink.Port) if plink == nil { return fmt.Errorf("通道端口{uid=%s, port=%s}关联通道端口{uid=%s, port=%s},但关联通道的对应端口却未关联通道端口", pe.Uid(), port, pipeLink.Pipe.Uid(), pipeLink.Port) } else if plink.Pipe.Uid() != pe.Uid() || plink.Port != port { return fmt.Errorf("通道端口{uid=%s, port=%s}关联通道端口{uid=%s, port=%s},但关联通道的对应端口却关联了其他通道端口: {uid=%s, port=%s}", pe.Uid(), port, pipeLink.Pipe.Uid(), pipeLink.Port, plink.Pipe.Uid(), plink.Port) } return nil } var _ TwoPortsPipeElement = (*TwoPortsPipeElementImpl)(nil) // 两端口的线性通道元素 type TwoPortsPipeElementImpl struct { uid string paPipeLink *PipeLink pbPipeLink *PipeLink } func (t *TwoPortsPipeElementImpl) Uid() string { return t.uid } func (t *TwoPortsPipeElementImpl) Ports() []PipePort { return twoPorts } func (t *TwoPortsPipeElementImpl) IsTwoPorts() bool { return true } func (t *TwoPortsPipeElementImpl) IsThreePorts() bool { return false } func (s *TwoPortsPipeElementImpl) GetLinkedElement(port PipePort) *PipeLink { if port == PipePortA { return s.paPipeLink } else if port == PipePortB { return s.pbPipeLink } return nil } func (t *TwoPortsPipeElementImpl) OppositePipeLink(port PipePort) *PipeLink { if port == PipePortA { return t.pbPipeLink } return t.paPipeLink } func (s *TwoPortsPipeElementImpl) SetLinkedElement(port PipePort, pipeLink *PipeLink) error { if port == PipePortA { if s.paPipeLink != nil { return fmt.Errorf("区段{uid=%s}端口A已经设置关联元素: {uid=%s, port=%s}", s.uid, s.paPipeLink.Pipe.Uid(), s.paPipeLink.Port) } s.paPipeLink = pipeLink } else if port == PipePortB { if s.pbPipeLink != nil { return fmt.Errorf("区段{uid=%s}端口B已经设置关联元素: {uid=%s, port=%s}", s.uid, s.pbPipeLink.Pipe.Uid(), s.pbPipeLink.Port) } s.pbPipeLink = pipeLink } else { return fmt.Errorf("区段{uid=%s}设置关联元素端口错误,不支持C端口", s.uid) } return nil } func (s *TwoPortsPipeElementImpl) CheckPipeLink() error { if s.paPipeLink == nil && s.pbPipeLink == nil { return fmt.Errorf("区段{uid=%s}两端都没有关联通道连接关系", s.uid) } err := checkPipePortLink(s, PipePortA, s.paPipeLink) if err != nil { return err } err = checkPipePortLink(s, PipePortB, s.pbPipeLink) return err } var _ PipeElement = (*ThreePortsPipeElementImpl)(nil) // 三端口的通道元素 type ThreePortsPipeElementImpl struct { uid string paPipeLink *PipeLink pbPipeLink *PipeLink pcPipeLink *PipeLink } func (t *ThreePortsPipeElementImpl) Uid() string { return t.uid } func (t *ThreePortsPipeElementImpl) Ports() []PipePort { return threePorts } func (t *ThreePortsPipeElementImpl) IsTwoPorts() bool { return false } func (t *ThreePortsPipeElementImpl) IsThreePorts() bool { return true } func (t *ThreePortsPipeElementImpl) GetLinkedElement(port PipePort) *PipeLink { if port == PipePortA { return t.paPipeLink } else if port == PipePortB { return t.pbPipeLink } else if port == PipePortC { return t.pcPipeLink } return nil } func (t *ThreePortsPipeElementImpl) SetLinkedElement(port PipePort, pipeLink *PipeLink) error { if port == PipePortA { if t.paPipeLink != nil { return fmt.Errorf("道岔{uid=%s}端口A已经设置关联元素: {uid=%s, port=%s}", t.uid, t.paPipeLink.Pipe.Uid(), t.paPipeLink.Port) } t.paPipeLink = pipeLink } else if port == PipePortB { if t.pbPipeLink != nil { return fmt.Errorf("道岔{uid=%s}端口B已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pbPipeLink.Pipe.Uid(), t.pbPipeLink.Port) } t.pbPipeLink = pipeLink } else if port == PipePortC { if t.pcPipeLink != nil { return fmt.Errorf("道岔{uid=%s}端口C已经设置关联元素: {uid=%s, port=%s}", t.uid, t.pcPipeLink.Pipe.Uid(), t.pcPipeLink.Port) } t.pcPipeLink = pipeLink } return nil } func (t *ThreePortsPipeElementImpl) CheckPipeLink() error { err := checkPipePortLink(t, PipePortA, t.paPipeLink) if err != nil { return err } err = checkPipePortLink(t, PipePortB, t.pbPipeLink) if err != nil { return err } err = checkPipePortLink(t, PipePortC, t.pcPipeLink) return err }