registry.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package pio
  2. import (
  3. "errors"
  4. "io"
  5. "sort"
  6. "sync"
  7. )
  8. // Registry is the Printer(s) container.
  9. //
  10. // It can be used as follows:
  11. // reg := NewRegistry().
  12. // RegisterPrinter(NewPrinter("err", os.Stderr)).
  13. // RegisterPrinter(NewPrinter("default", os.Stdout)).
  14. // Print("something")
  15. type Registry struct {
  16. // can change via `Register` or `RegisterPrinter` with mutex.
  17. // whenever a tool needs an `io.Writer` to do something
  18. // end-developers can pass this `Printer`.
  19. printers []*Printer
  20. mu sync.Mutex
  21. once sync.Once
  22. }
  23. // NewRegistry returns an empty printer Registry.
  24. //
  25. // Note that:
  26. // Registry have a zero value, so it can be
  27. // declared with a simple `var` keyword and without pointer.
  28. func NewRegistry() *Registry {
  29. return new(Registry)
  30. }
  31. // RegisterPrinter registers an already-created printer to the
  32. // registry.
  33. //
  34. // If `Printer#Name` is empty then it will be filled with
  35. // "printer_$printers.len".
  36. //
  37. // If a printer with the same `Printer#Name` is already
  38. // registered then it will be overridden by
  39. // this new "printer".
  40. //
  41. // Returns this Registry, therefore it can be used as builder.
  42. func (reg *Registry) RegisterPrinter(printer *Printer) *Registry {
  43. // if exists then remove first and then add the new one.
  44. if printerName := printer.Name; reg.Get(printerName) != nil {
  45. reg.Remove(printerName)
  46. }
  47. reg.mu.Lock()
  48. // no printer.Handle(s.handlers...)
  49. reg.printers = append(reg.printers, printer)
  50. reg.mu.Unlock()
  51. return reg
  52. }
  53. // Register creates and registers a new Printer
  54. // based on a name(string) and an "output"(io.Writer).
  55. //
  56. // If "printerName" is empty then it will be filled with
  57. // "printer_$printers.len".
  58. //
  59. // If a printer with the same `Printer#Name` is already
  60. // registered then it will be overridden by
  61. // this new "printer".
  62. //
  63. // Look `OutputFrom` too.
  64. //
  65. // Returns the just created Printer.
  66. func (reg *Registry) Register(printerName string, output io.Writer) *Printer {
  67. p := NewPrinter(printerName, output)
  68. reg.RegisterPrinter(p)
  69. return p
  70. }
  71. // Get returns a Printer based on the "printerName".
  72. // If printer with this name can't be found then
  73. // this function will return nil, so a check for
  74. // nil is always a good practice.
  75. func (reg *Registry) Get(printerName string) *Printer {
  76. reg.mu.Lock()
  77. defer reg.mu.Unlock()
  78. for _, p := range reg.printers {
  79. if p.Name == printerName {
  80. return p
  81. }
  82. }
  83. return nil
  84. }
  85. // Remove deletes a printer item from the printers collection
  86. // by its name.
  87. //
  88. // Returns this Registry, so it can be used as builder.
  89. func (reg *Registry) Remove(printerName string) *Registry {
  90. reg.mu.Lock()
  91. for i, p := range reg.printers {
  92. if p.Name == printerName {
  93. reg.printers = append(reg.printers[:i], reg.printers[i+1:]...)
  94. break
  95. }
  96. }
  97. reg.mu.Unlock()
  98. return reg
  99. }
  100. // Print accepts a value of "v",
  101. // tries to marshal its contents and flushes the result
  102. // to all available printers.
  103. func (reg *Registry) Print(v interface{}) (n int, err error) {
  104. return reg.printAll(v, false)
  105. }
  106. // Println accepts a value of "v",
  107. // tries to marshal its contents and flushes the result
  108. // to all available printers, it adds a new line at the ending,
  109. // the result doesn't contain this new line, therefore result's contents kept as expected.
  110. func (reg *Registry) Println(v interface{}) (n int, err error) {
  111. return reg.printAll(v, true)
  112. }
  113. func (reg *Registry) printAll(v interface{}, appendNewLine bool) (n int, err error) {
  114. // order once at first print.
  115. reg.once.Do(func() {
  116. reg.mu.Lock()
  117. sort.Slice(reg.printers, func(i, j int) bool {
  118. return reg.printers[i].priority > reg.printers[j].priority
  119. })
  120. reg.mu.Unlock()
  121. })
  122. for _, p := range reg.printers {
  123. prevErr := err
  124. printFunc := p.Print
  125. if appendNewLine {
  126. printFunc = p.Println
  127. }
  128. n, err = printFunc(v)
  129. if !p.Chained && n > 0 {
  130. break
  131. }
  132. n, err = combineOutputResult(n, err, prevErr)
  133. }
  134. return
  135. }
  136. func combineOutputResult(n int, err error, prevErr error) (totalN int, totalErr error) {
  137. if err != nil {
  138. if prevErr != nil {
  139. totalErr = errors.New(prevErr.Error() + string(NewLine) + err.Error())
  140. }
  141. }
  142. totalN += n
  143. return
  144. }
  145. // Scan scans everything from "r" and prints
  146. // its new contents to the printers,
  147. // forever or until the returning "cancel" is fired, once.
  148. func (reg *Registry) Scan(r io.Reader, addNewLine bool) (cancel func()) {
  149. lp := len(reg.printers)
  150. if lp == 0 {
  151. return func() {}
  152. }
  153. cancelFuncs := make([]func(), lp, lp)
  154. cancel = func() {
  155. for _, c := range cancelFuncs {
  156. c()
  157. }
  158. }
  159. for i, p := range reg.printers {
  160. cancelFuncs[i] = p.Scan(r, addNewLine)
  161. }
  162. return cancel
  163. }
  164. func (reg *Registry) restore(b []byte) {
  165. for _, p := range reg.printers {
  166. p.restore(b)
  167. }
  168. }