github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/graph/graph.go (about)

     1  package graph
     2  
     3  import (
     4  	"github.com/15mga/kiwi"
     5  	"github.com/15mga/kiwi/util"
     6  )
     7  
     8  type IGraph interface {
     9  	Name() string
    10  	Data() util.M
    11  	SetData(m util.M)
    12  	Plugin() IPlugin
    13  	SetPlugin(plugin IPlugin)
    14  	Start() *util.Err
    15  	AddNode(name string) (INode, *util.Err)
    16  	GetNode(name string) (INode, *util.Err)
    17  	GetNodeByPath(names ...string) (INode, *util.Err)
    18  	FindNode(name string) (INode, bool)
    19  	FindNodes(name string, nodes *[]INode)
    20  	IterNode(fn func(INode))
    21  	AnyNode(fn func(INode) bool) bool
    22  	Link(outNode, outPoint, inNode, inPoint string) (ILink, *util.Err)
    23  	IterLink(fn func(ILink))
    24  	AnyLink(fn func(ILink) bool) bool
    25  	AddSubGraph(name string) (ISubGraph, *util.Err)
    26  	GetSubGraph(graph string) (ISubGraph, *util.Err)
    27  	IterSubGraph(fn func(ISubGraph))
    28  	AnySubGraph(fn func(ISubGraph) bool) bool
    29  }
    30  
    31  type (
    32  	option struct {
    33  		plugin IPlugin
    34  	}
    35  	Option func(*option)
    36  )
    37  
    38  func Plugin(plugin IPlugin) Option {
    39  	return func(o *option) {
    40  		o.plugin = plugin
    41  	}
    42  }
    43  
    44  func NewGraph(name string, opts ...Option) IGraph {
    45  	opt := &option{}
    46  	for _, o := range opts {
    47  		o(opt)
    48  	}
    49  	g := &graph{
    50  		option:      opt,
    51  		name:        name,
    52  		data:        util.M{},
    53  		nameToNode:  make(map[string]INode),
    54  		nameToGraph: make(map[string]ISubGraph),
    55  		nameToLink:  make(map[string]ILink),
    56  	}
    57  	return g
    58  }
    59  
    60  type graph struct {
    61  	option      *option
    62  	name        string
    63  	data        util.M
    64  	nameToNode  map[string]INode
    65  	nameToGraph map[string]ISubGraph
    66  	nameToLink  map[string]ILink
    67  }
    68  
    69  func (g *graph) Name() string {
    70  	return g.name
    71  }
    72  
    73  func (g *graph) Data() util.M {
    74  	return g.data
    75  }
    76  
    77  func (g *graph) SetData(data util.M) {
    78  	g.data = data
    79  }
    80  
    81  func (g *graph) Plugin() IPlugin {
    82  	return g.option.plugin
    83  }
    84  
    85  func (g *graph) SetPlugin(plugin IPlugin) {
    86  	g.option.plugin = plugin
    87  }
    88  
    89  func (g *graph) Start() *util.Err {
    90  	for _, nd := range g.nameToNode {
    91  		err := nd.Start()
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  	for _, lnk := range g.nameToLink {
    97  		err := lnk.Start()
    98  		if err != nil {
    99  			return err
   100  		}
   101  	}
   102  	if g.option.plugin != nil {
   103  		g.option.plugin.OnStart(g)
   104  	}
   105  	return nil
   106  }
   107  
   108  func (g *graph) AddNode(name string) (INode, *util.Err) {
   109  	_, ok := g.nameToNode[name]
   110  	if ok {
   111  		return nil, util.NewErr(util.EcExist, util.M{
   112  			"node name": name,
   113  			"graph":     g.Name(),
   114  		})
   115  	}
   116  	nd := NewNode(g, name)
   117  	g.nameToNode[name] = nd
   118  	if g.option.plugin != nil {
   119  		g.option.plugin.OnAddNode(g, nd)
   120  	}
   121  	return nd, nil
   122  }
   123  
   124  func (g *graph) GetNode(name string) (INode, *util.Err) {
   125  	n, ok := g.nameToNode[name]
   126  	if ok {
   127  		return n, nil
   128  	}
   129  	return nil, util.NewErr(util.EcNotExist, util.M{
   130  		"node name": name,
   131  		"graph":     g.Name(),
   132  	})
   133  }
   134  
   135  func (g *graph) GetNodeByPath(names ...string) (INode, *util.Err) {
   136  	switch len(names) {
   137  	case 0:
   138  		return nil, util.NewErr(util.EcLengthErr, nil)
   139  	case 1:
   140  		return g.GetNode(names[0])
   141  	default:
   142  		sgn := names[0]
   143  		sg, ok := g.nameToGraph[sgn]
   144  		if !ok {
   145  			return nil, util.NewErr(util.EcNotExist, util.M{
   146  				"subgraph name": sgn,
   147  				"graph":         g.Name(),
   148  			})
   149  		}
   150  		return sg.GetNodeByPath(names[1:]...)
   151  	}
   152  }
   153  
   154  func (g *graph) FindNode(name string) (INode, bool) {
   155  	for nm, nd := range g.nameToNode {
   156  		if nm == name {
   157  			return nd, true
   158  		}
   159  	}
   160  	return nil, false
   161  }
   162  
   163  func (g *graph) FindNodes(name string, nodes *[]INode) {
   164  	for nm, nd := range g.nameToNode {
   165  		if nm == name {
   166  			*nodes = append(*nodes, nd)
   167  		}
   168  	}
   169  	for _, sg := range g.nameToGraph {
   170  		sg.FindNodes(name, nodes)
   171  	}
   172  }
   173  
   174  func (g *graph) IterNode(fn func(INode)) {
   175  	for _, nd := range g.nameToNode {
   176  		fn(nd)
   177  	}
   178  }
   179  
   180  func (g *graph) AnyNode(fn func(INode) bool) bool {
   181  	for _, nd := range g.nameToNode {
   182  		if fn(nd) {
   183  			return true
   184  		}
   185  	}
   186  	return false
   187  }
   188  
   189  func (g *graph) Link(outNode, outPoint, inNode, inPoint string) (ILink, *util.Err) {
   190  	name := LinkName(outNode, outPoint, inNode, inPoint)
   191  	_, ok := g.nameToLink[name]
   192  	if ok {
   193  		return nil, util.NewErr(util.EcExist, util.M{
   194  			"name":  name,
   195  			"graph": g.Name(),
   196  		})
   197  	}
   198  
   199  	on, err := g.GetNode(outNode)
   200  	if err != nil {
   201  		err.AddParam("graph", g.Name())
   202  		return nil, err
   203  	}
   204  	op, err := on.GetOut(outPoint)
   205  	if err != nil {
   206  		err.AddParam("graph", g.Name())
   207  		return nil, err
   208  	}
   209  
   210  	in, err := g.GetNode(inNode)
   211  	if err != nil {
   212  		err.AddParam("graph", g.Name())
   213  		return nil, err
   214  	}
   215  	ip, err := in.GetIn(inPoint)
   216  	if err != nil {
   217  		err.AddParam("graph", g.Name())
   218  		return nil, err
   219  	}
   220  
   221  	if ip.Type() != op.Type() {
   222  		return nil, util.NewErr(util.EcParamsErr, util.M{
   223  			"name":          name,
   224  			"graph":         g.Name(),
   225  			"in node type":  ip.Type(),
   226  			"out node type": op.Type(),
   227  		})
   228  	}
   229  
   230  	lnk := newLink(g, name, op, ip)
   231  	op.AddLink(lnk)
   232  	ip.AddLink(lnk)
   233  	g.nameToLink[name] = lnk
   234  	if g.option.plugin != nil {
   235  		g.option.plugin.OnAddLink(g, lnk)
   236  	}
   237  	return lnk, nil
   238  }
   239  
   240  func (g *graph) IterLink(fn func(ILink)) {
   241  	for _, lnk := range g.nameToLink {
   242  		fn(lnk)
   243  	}
   244  }
   245  
   246  func (g *graph) AnyLink(fn func(ILink) bool) bool {
   247  	for _, lnk := range g.nameToLink {
   248  		if fn(lnk) {
   249  			return true
   250  		}
   251  	}
   252  	return false
   253  }
   254  
   255  func (g *graph) AddSubGraph(name string) (ISubGraph, *util.Err) {
   256  	_, ok := g.nameToNode[name]
   257  	if ok {
   258  		return nil, util.NewErr(util.EcExist, util.M{
   259  			"name":  name,
   260  			"graph": g.Name(),
   261  		})
   262  	}
   263  	sg := newSubGraph(g, name)
   264  	g.nameToGraph[name] = sg
   265  	g.nameToNode[name] = sg
   266  	if g.option.plugin != nil {
   267  		g.option.plugin.OnAddNode(g, sg)
   268  		g.option.plugin.OnAddSubGraph(g, sg)
   269  	}
   270  	return sg, nil
   271  }
   272  
   273  func (g *graph) GetSubGraph(name string) (ISubGraph, *util.Err) {
   274  	sg, ok := g.nameToGraph[name]
   275  	if !ok {
   276  		return nil, util.NewErr(util.EcNotExist, util.M{
   277  			"name":  name,
   278  			"graph": g.Name(),
   279  		})
   280  	}
   281  	return sg, nil
   282  }
   283  
   284  func (g *graph) IterSubGraph(fn func(ISubGraph)) {
   285  	for _, sg := range g.nameToGraph {
   286  		fn(sg)
   287  	}
   288  }
   289  
   290  func (g *graph) AnySubGraph(fn func(ISubGraph) bool) bool {
   291  	for _, sg := range g.nameToGraph {
   292  		if fn(sg) {
   293  			return true
   294  		}
   295  	}
   296  	return false
   297  }
   298  
   299  func NewGraphWithConf(conf Conf, opts ...Option) IGraph {
   300  	g := NewGraph(conf.Name, opts...)
   301  	for _, nc := range conf.Nodes {
   302  		_, err := AddNodeWithConf(g, nc)
   303  		if err != nil {
   304  			kiwi.Error(err)
   305  		}
   306  	}
   307  	for _, gc := range conf.SubGraphs {
   308  		_, err := AddSubGraphWithConf(g, gc)
   309  		if err != nil {
   310  			kiwi.Error(err)
   311  		}
   312  	}
   313  	for _, lc := range conf.Links {
   314  		_, err := LinkWithConf(g, lc)
   315  		if err != nil {
   316  			kiwi.Error(err)
   317  		}
   318  	}
   319  	return g
   320  }
   321  
   322  func AddNodeWithConf(g IGraph, conf NodeConf) (INode, *util.Err) {
   323  	n, err := g.AddNode(conf.Name)
   324  	if err != nil {
   325  		return nil, err
   326  	}
   327  	n.SetComment(conf.Comment)
   328  	if conf.M != nil {
   329  		n.SetData(conf.M)
   330  	} else {
   331  		n.SetData(util.M{})
   332  	}
   333  
   334  	for _, ip := range conf.Ins {
   335  		err := n.AddIn(ip.Type, ip.Name)
   336  		if err != nil {
   337  			kiwi.Error(err)
   338  		}
   339  	}
   340  	for _, op := range conf.Outs {
   341  		err := n.AddOut(op.Type, op.Name)
   342  		if err != nil {
   343  			kiwi.Error(err)
   344  		}
   345  	}
   346  
   347  	for pnt, name := range conf.PointToProcessor {
   348  		pcr, ok := _MsgProcessors[name]
   349  		if !ok {
   350  			kiwi.Error2(util.EcNotExist, util.M{
   351  				"name": name,
   352  			})
   353  			continue
   354  		}
   355  		n.BindFn(pnt, pcr)
   356  	}
   357  	return n, nil
   358  }
   359  
   360  func AddSubGraphWithConf(g IGraph, conf SubConf) (ISubGraph, *util.Err) {
   361  	sg, err := g.AddSubGraph(conf.Name)
   362  	if err != nil {
   363  		err.AddParam("graph", g.Name())
   364  		return nil, err
   365  	}
   366  
   367  	for _, nc := range conf.Nodes {
   368  		_, err = AddNodeWithConf(sg, nc)
   369  		if err != nil {
   370  			err.AddParam("graph", g.Name())
   371  			kiwi.Error(err)
   372  		}
   373  	}
   374  
   375  	for _, gc := range conf.SubGraphs {
   376  		_, err = AddSubGraphWithConf(sg, gc)
   377  		if err != nil {
   378  			err.AddParam("graph", g.Name())
   379  			kiwi.Error(err)
   380  		}
   381  	}
   382  	_ = sg.SetInNode(conf.In)
   383  	_ = sg.SetOutNode(conf.Out)
   384  
   385  	for _, lc := range conf.Links {
   386  		_, err = LinkWithConf(sg, lc)
   387  		if err != nil {
   388  			err.AddParam("graph", g.Name())
   389  			kiwi.Error(err)
   390  		}
   391  	}
   392  	return sg, nil
   393  }
   394  
   395  func LinkWithConf(g IGraph, conf LinkConf) (ILink, *util.Err) {
   396  	return g.Link(conf.OutNode, conf.OutPoint, conf.InNode, conf.InPoint)
   397  }