registry.go 4.6 KB

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