rtss-core/model/model.go

233 lines
5.9 KiB
Go

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 {
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
}