framework.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. package svcfw
  2. import (
  3. "context"
  4. "fmt"
  5. "git.swzry.com/zry/GoHiedaLogger/hiedabke_console"
  6. "git.swzry.com/zry/GoHiedaLogger/hiedalog"
  7. "git.swzry.com/zry/zry-go-program-framework/core"
  8. ordmap "github.com/edofic/go-ordmap/v2"
  9. "github.com/oklog/run"
  10. "io"
  11. "sync"
  12. )
  13. var _ core.IAppFramework = (*AppFramework)(nil)
  14. var _ core.IModuleLogger = (*AppFramework)(nil)
  15. var _ core.IModuleLogLevelLimiter = (*AppFramework)(nil)
  16. type AppFramework struct {
  17. rg *run.Group
  18. logger *hiedalog.HiedaLogger
  19. gctx context.Context
  20. gcncl context.CancelFunc
  21. subSvc ordmap.NodeBuiltin[string, *core.SubServiceWrapper]
  22. moduleLoggers map[string]core.IModuleLogger
  23. moduleLoggersLock sync.RWMutex
  24. appLogModuleName string
  25. globalDebugSwitch bool
  26. prepared bool
  27. consoleLogBackend *hiedabke_console.ConsoleBackend
  28. mainLogLevelLimit uint8
  29. core.IModuleLogger
  30. core.IModuleLogLevelLimiter
  31. }
  32. func NewAppFramework(globalDebugMode bool, appLogModuleName string) *AppFramework {
  33. f := &AppFramework{
  34. rg: &run.Group{},
  35. logger: hiedalog.NewHiedaLogger(),
  36. subSvc: ordmap.NewBuiltin[string, *core.SubServiceWrapper](),
  37. appLogModuleName: appLogModuleName,
  38. moduleLoggers: map[string]core.IModuleLogger{},
  39. globalDebugSwitch: globalDebugMode,
  40. prepared: false,
  41. mainLogLevelLimit: 0,
  42. }
  43. mlog := core.NewModuleLogger(appLogModuleName, f)
  44. f.moduleLoggers[appLogModuleName] = mlog
  45. f.IModuleLogger = mlog
  46. f.IModuleLogLevelLimiter = mlog
  47. return f
  48. }
  49. // InitConsoleLogBackend add a hiedalog console backend to logger system
  50. // if lv == "", for globalDebugMode is on, will use hiedalog.DLN_DEBUG;
  51. // for globalDebugMode is off, will use hiedalog.DLN_INFO.
  52. func (f *AppFramework) InitConsoleLogBackend(writer io.Writer, lv string) {
  53. klv := lv
  54. if klv == "" {
  55. if f.globalDebugSwitch {
  56. klv = hiedalog.DLN_DEBUG
  57. } else {
  58. klv = hiedalog.DLN_INFO
  59. }
  60. }
  61. f.consoleLogBackend = hiedabke_console.NewConsoleBackend(writer)
  62. f.logger.AddBackend(f.consoleLogBackend, f.logger.LevelFilter.NameToID(klv))
  63. }
  64. // ShutdownConsoleLogBackend shutdown the console backend which created by InitConsoleLogBackend
  65. func (f *AppFramework) ShutdownConsoleLogBackend() {
  66. if f.consoleLogBackend != nil {
  67. f.consoleLogBackend.Shutdown()
  68. }
  69. }
  70. // AddSubSvc add a sub service
  71. func (f *AppFramework) AddSubSvc(name string, svc core.ISubService) {
  72. _, ok := f.subSvc.Get(name)
  73. if ok {
  74. panic("SubService name exists.")
  75. }
  76. sw := core.NewSubServiceWrapper(f, name, svc)
  77. f.subSvc = f.subSvc.Insert(name, sw)
  78. f.rg.Add(sw.Run, sw.Stop)
  79. }
  80. // GetRawLogger get the HiedaLogger inside this
  81. func (f *AppFramework) GetRawLogger() *hiedalog.HiedaLogger {
  82. return f.logger
  83. }
  84. func (f *AppFramework) GetModuleLogger(module string) core.IModuleLogger {
  85. f.moduleLoggersLock.RLock()
  86. v, ok := f.moduleLoggers[module]
  87. if !ok {
  88. f.moduleLoggersLock.RUnlock()
  89. f.moduleLoggersLock.Lock()
  90. v = core.NewModuleLogger(module, f)
  91. f.moduleLoggers[module] = v
  92. f.moduleLoggersLock.Unlock()
  93. } else {
  94. f.moduleLoggersLock.RUnlock()
  95. }
  96. return v
  97. }
  98. // Prepare call the `Prepare()` of each SubService by order of addition
  99. func (f *AppFramework) Prepare() error {
  100. var err error
  101. for i := f.subSvc.Iterate(); !i.Done(); i.Next() {
  102. f.DebugF("preparing for sub service '%s'...", i.GetKey())
  103. err = i.GetValue().Prepare()
  104. if err != nil {
  105. f.ErrorF("failed prepare sub service '%s': %v", i.GetKey(), err)
  106. return err
  107. }
  108. }
  109. f.prepared = true
  110. return nil
  111. }
  112. // Run start the app
  113. func (f *AppFramework) Run() error {
  114. if !f.prepared {
  115. return fmt.Errorf("failed run app: `Prepare()` not called")
  116. }
  117. return f.RunWithContext(context.Background())
  118. }
  119. // RunWithContext start the app with custom context
  120. func (f AppFramework) RunWithContext(ctx context.Context) error {
  121. ctx, cncl := context.WithCancel(ctx)
  122. f.gcncl = cncl
  123. f.gctx = ctx
  124. f.rg.Add(f.bgRun, f.bgStop)
  125. return f.rg.Run()
  126. }
  127. // Stop stop the app
  128. func (f *AppFramework) Stop() {
  129. if f.gcncl != nil {
  130. f.gcncl()
  131. }
  132. }
  133. func (f *AppFramework) bgRun() error {
  134. select {
  135. case <-f.gctx.Done():
  136. return nil
  137. }
  138. }
  139. func (f *AppFramework) bgStop(xerr error) {
  140. f.Stop()
  141. }
  142. func (f *AppFramework) GetContext() context.Context {
  143. return f.gctx
  144. }
  145. func (f *AppFramework) IsGlobalDebugMode() bool {
  146. return f.globalDebugSwitch
  147. }
  148. func (f *AppFramework) SetGlobalDebugMode(en bool) {
  149. f.globalDebugSwitch = en
  150. }