// package kbus_base -- базовая часть шины данных. package kbus_base import ( "gitp78su.ipnodns.ru/svi/kern/v4/d0" "gitp78su.ipnodns.ru/svi/kern/v4/d1" "gitp78su.ipnodns.ru/svi/kern/v4/d2/kern_ctx" "gitp78su.ipnodns.ru/svi/kern/v4/d2/kern_ent/stream_name" "gitp78su.ipnodns.ru/svi/kern/v4/d2/lti/bus_ent/topic" "gitp78su.ipnodns.ru/svi/kern/v4/d2/lti/bus_spec" "gitp78su.ipnodns.ru/svi/kern/v4/d2/lti/kbus/dict_topic_serve" "gitp78su.ipnodns.ru/svi/kern/v4/d2/lti/kbus/dict_topic_sub" ) // KBusBase -- базовая часть шины данных. type KBusBase struct { owner *d0.LOwner streamName *stream_name.AStreamName KCtx_ *kern_ctx.KernCtx IsWork_ *d0.MSafeBool lCtx *d1.LocalCtx log *d1.LogBuf dictSub bus_spec.IDictTopicSub dictServe bus_spec.IDictTopicServe } var ( Bus_ *KBusBase block = d0.MutSafeMutex() ) // GetKernelBusBase -- возвращает базовую шину сообщений. func GetKernelBusBase() *KBusBase { block.Lock() defer block.Unlock() if Bus_ != nil { return Bus_ } owner := d0.LetOwner(1, "isol_kern_bus_base") kCtx := kern_ctx.GetKernCtx() lCtx := d1.NewLocalCtx(owner, kCtx.SelfCtx()) Bus_ = &KBusBase{ owner: owner, streamName: stream_name.NewAStreamName(owner, "bus_base"), KCtx_: kCtx, IsWork_: d0.MutSafeBool(owner, false), dictSub: dict_topic_sub.NewDictTopicSub(owner), dictServe: dict_topic_serve.NewDictServe(owner), lCtx: lCtx, } Bus_.log = Bus_.lCtx.Log() go Bus_.close() go Bus_.run() Bus_.IsWork_.Set() Bus_.KCtx_.Wg().Add(Bus_.streamName) Bus_.KCtx_.Set(d0.LetTxt(owner, "kernBusBase"), Bus_, "base of data bus") _ = bus_spec.IKernelBus(Bus_) return Bus_ } // Owner -- возвращает владельца базовой шины func (sf *KBusBase) Owner() *d0.LOwner { return sf.owner } // Log -- возвращает лог шины. func (sf *KBusBase) Log() *d1.LogBuf { return sf.log } func (sf *KBusBase) run() { sf.log.Debug("KBusBase.run()") for { break } } // Unsubscribe -- отписывает обработчик от топика. func (sf *KBusBase) Unsubscribe(handler bus_spec.IBusHandlerSubscribe) { msg := d0.LetTxt(sf.owner, "KBusBase.Unsubscribe(): handler='%v'", handler.Name()) sf.log.Debug(msg.Get()) sf.dictSub.Unsubscribe(handler) } // Subscribe -- подписывает обработчик на топик. func (sf *KBusBase) Subscribe(handler bus_spec.IBusHandlerSubscribe) *d0.Result[d0.Bool] { msg := d0.LetTxt(sf.owner, "KBusBase.Subscribe(): handler='%v'", handler.Name()).Get() sf.log.Debug(msg) d0.If(sf.IsWork_.IsNot()). Hassert("KBusBase.Subscribe(): handler='%v', bus already closed", []any{handler.Name()}) sf.dictSub.Subscribe(handler) return d0.ResOk(d0.Bool(true)) } // SendRequest -- отправляет запрос в шину данных. func (sf *KBusBase) SendRequest(topic *topic.LTopic, binReq []byte) *d0.Result[[]byte] { msg := d0.LetTxt(sf.owner, "KBusBase.SendRequest(): topic='%v'", topic.Get()).Get() sf.log.Debug(msg) if sf.IsWork_.IsNot() { err := d0.LetErr(sf.owner, "KBusBase.SendRequest(): topic='%v', bus already closed", topic.Get()) sf.log.Err(err) return d0.ResErr[[]byte](err) } res := sf.dictServe.SendRequest(topic, binReq) if res.IsErr() { err := d0.LetErr(sf.owner, "KBusBase.SendRequest(): topic='%v', err=\n\t%w", topic.Get(), res.Err()) sf.log.Err(err) return d0.ResErr[[]byte](err) } return res } // RegisterServe -- регистрирует обработчики входящих запросов. func (sf *KBusBase) RegisterServe(handler bus_spec.IBusHandlerServe) *d0.Result[d0.Bool] { if handler == nil { err := d0.LetErr(sf.owner, "KBusBase.RegisterServe(): IBusHandlerServe==nil") return d0.ResErr[d0.Bool](err) } msg := d0.LetTxt(sf.owner, "KBusBase.RegisterServe(): handler='%v'", handler.Name()).Get() sf.log.Debug(msg) res := sf.dictServe.Register(handler) if res.IsErr() { err := d0.LetErr(sf.owner, "KBusBase.RegisterServe(): handler='%v', err=\n\t%w", handler.Name(), res.Err()) sf.log.Err(err) return d0.ResErr[d0.Bool](err) } return d0.ResOk(d0.Bool(true)) } // Publish -- публикует сообщение в шину. func (sf *KBusBase) Publish(topic *topic.LTopic, binMsg []byte) *d0.Result[d0.Bool] { msg := d0.LetTxt(sf.owner, "KBusBase.Publish(): topic='%v'", topic).Get() sf.log.Debug(msg) if sf.IsWork_.IsNot() { err := d0.LetErr(sf.owner, "KBusBase.Publish(): topic='%v',bus already closed", topic) sf.log.Err(err) return d0.ResErr[d0.Bool](err) } // Асинхронный запуск чтения go sf.dictSub.Read(topic, binMsg) return d0.ResOk(d0.Bool(true)) } // IsWork -- возвращает признак работы шины. func (sf *KBusBase) IsWork() d0.Bool { return sf.IsWork_.IsOk() } // Ожидает закрытия шины в отдельном потоке. func (sf *KBusBase) close() { sf.KCtx_.Wait() sf.KCtx_.Lock() defer sf.KCtx_.Unlock() if sf.IsWork_.IsNot() { return } sf.IsWork_.Reset() sf.KCtx_.Wg().Done(sf.streamName) sf.log.Debug("KBusBase.close(): done") }