printer.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. package pio
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. "io/ioutil"
  7. "strconv"
  8. "sync"
  9. "sync/atomic"
  10. "github.com/kataras/pio/terminal"
  11. )
  12. type (
  13. // Handler is the signature implemented by callers
  14. // that want to be notified about the results
  15. // that are being printed to the Printer's output.
  16. //
  17. // Look `Printer#Handle` for more.
  18. Handler func(PrintResult)
  19. )
  20. // Printer is responsible to print the end result.
  21. type Printer struct {
  22. Name string
  23. IsTerminal bool
  24. priority int // higher means try to print first from this printer, from `Registry#Print`
  25. // if Chained is true then the parent `Registry#Print`
  26. // will continue to search for a compatible printer
  27. // even if this printer succeed to print the contents.
  28. Chained bool
  29. Output io.Writer
  30. // The "outputs" field holds the total writers,
  31. // the "Output" and any writer added by an `AddOutput` call.
  32. // The `AddOutput` method sets the Output to a new `io.MultiWriter`
  33. // but the underline struct is unexported therefore we don't have access to
  34. // to the total writers. However sometimes, we need those writers.
  35. // E.g. for the `WriteRich` feature;
  36. // in order to write color symbols in the writers that support 256-bit colors
  37. // and write raw text to those that do not (e.g. files).
  38. // Note: we could implementing our own multi writer and skip the use
  39. // of the std package, but let's don't do that unless is requested.
  40. outputs []*outputWriter
  41. mu sync.Mutex
  42. marshal MarshalerFunc
  43. hijack Hijacker
  44. handlers []Handler
  45. // These three will complete the interface of the:
  46. // https://golang.org/pkg/io/#ReadWriteCloser
  47. // in order to make possible to use everything inside the `io` package.
  48. // i.e
  49. // https://golang.org/pkg/io/#example_MultiWriter
  50. // https://golang.org/pkg/io/#example_TeeReader (piping)
  51. io.Reader
  52. io.Writer
  53. io.Closer
  54. // DirectOutput will output the contents and flush them as fast as possible,
  55. // without storing them to the buffer to complete the `ReadWriteCloser` std interface.
  56. // Enable this if you need performance and you don't use the standard functions like `TeeReader`.
  57. DirectOutput bool
  58. sync bool // See `SetSync`.
  59. }
  60. var (
  61. // TotalPrinters holds the number of
  62. // the total printers created, either by
  63. // `NewPrinter`, `NewTextPrinter`, `Register` or `RegisterPrinter`
  64. TotalPrinters int32
  65. )
  66. // NewPrinter returns a new named printer
  67. // if "output" is nil then it doesn't prints anywhere.
  68. //
  69. // If "name" is empty then it will be filled with
  70. // "printer_$printers.len".
  71. //
  72. // If the marshaler is nil, meaning that this writer's
  73. // result will never being proceed, caller should
  74. // add a marshaler using the `Marshal` function.
  75. //
  76. // Look `OutputFrom` too.
  77. func NewPrinter(name string, output io.Writer) *Printer {
  78. if output == nil {
  79. output = NopOutput()
  80. }
  81. atomic.AddInt32(&TotalPrinters, 1)
  82. if name == "" {
  83. totalPrinters := atomic.LoadInt32(&TotalPrinters)
  84. lens := strconv.Itoa(int(totalPrinters))
  85. name = "printer_" + lens
  86. }
  87. buf := &bytes.Buffer{}
  88. isOuputTerminal := SupportColors(output)
  89. p := &Printer{
  90. Name: name,
  91. Output: output,
  92. outputs: wrapWriters(output),
  93. Writer: buf,
  94. Reader: buf,
  95. Closer: NopCloser(),
  96. IsTerminal: isOuputTerminal,
  97. }
  98. // If "output" is terminal then a text marshaler will be
  99. // added to the Printer's marshalers.
  100. //
  101. // if p.IsTerminal {
  102. // p.Marshal(Text)
  103. // }
  104. //
  105. // let's think of it
  106. // if a user don't want it we can't force this printer
  107. // to print texts too, the end-developer
  108. // may have split his logic about logging
  109. // so don't do it automatically, instead
  110. // create a new function which will return a text printer
  111. // and allow this printer to accept more than one marshalers.
  112. return p
  113. }
  114. // NewTextPrinter same as NewPrinter but registers
  115. // a text marshaler, no matter what kind of "output",
  116. // which converts string type
  117. // to a compatible form of slice of bytes.
  118. //
  119. // If "name" is empty then it will be filled with
  120. // "printer_$printers.len".
  121. //
  122. // Look `OutputFrom` too.
  123. func NewTextPrinter(name string, output io.Writer) *Printer {
  124. p := NewPrinter(name, output)
  125. p.Marshal(Text)
  126. return p
  127. }
  128. // Priority changes the order of this printer.
  129. // Higher value means that the `Registry#Print`
  130. // will try to print first from this printer.
  131. // Default order is 0 for all printers.
  132. //
  133. // Returns it self.
  134. func (p *Printer) Priority(prio int) *Printer {
  135. p.mu.Lock()
  136. p.priority = prio
  137. p.mu.Unlock()
  138. return p
  139. }
  140. // Marshal adds a "marshaler" to the printer.
  141. // Returns itself.
  142. func (p *Printer) Marshal(marshaler Marshaler) *Printer {
  143. return p.MarshalFunc(marshaler.Marshal)
  144. }
  145. // MarshalFunc adds a "marshaler" to the printer.
  146. // Returns itself.
  147. func (p *Printer) MarshalFunc(marshaler func(v interface{}) ([]byte, error)) *Printer {
  148. p.mu.Lock()
  149. defer p.mu.Unlock()
  150. if p.marshal == nil {
  151. p.marshal = marshaler
  152. return p
  153. }
  154. oldM := p.marshal
  155. newM := marshaler
  156. // false on first failure
  157. p.marshal = func(v interface{}) ([]byte, error) {
  158. b, err := oldM(v)
  159. // check if we can continue to the next marshal func
  160. if err != nil && err.Error() == ErrMarshalNotResponsible.Error() {
  161. b, err = newM(v)
  162. }
  163. // if no data return but err is nil, then something went wrong
  164. if len(b) <= 0 && err == nil {
  165. return b, ErrSkipped
  166. }
  167. return b, err // p.addNewLineInneed(b), err
  168. }
  169. return p
  170. }
  171. // WithMarshalers same as `Marshal` but accepts more than one marshalers
  172. // and returns the Printer itself in order to be used side by side with the creational
  173. // function.
  174. func (p *Printer) WithMarshalers(marshalers ...Marshaler) *Printer {
  175. if len(marshalers) == 0 {
  176. return p
  177. }
  178. for _, marshaler := range marshalers {
  179. p.Marshal(marshaler)
  180. }
  181. return p
  182. }
  183. // AddOutput adds one or more io.Writer to the Printer.
  184. // Returns itself.
  185. //
  186. // Look `OutputFrom` and `Wrap` too.
  187. func (p *Printer) AddOutput(writers ...io.Writer) *Printer {
  188. p.mu.Lock()
  189. defer p.mu.Unlock()
  190. for _, w := range writers {
  191. // set is terminal to false
  192. // if at least one of the writers
  193. // is not a terminal-based.
  194. if !terminal.IsTerminal(w) {
  195. p.IsTerminal = false
  196. break
  197. }
  198. }
  199. p.outputs = append(p.outputs, wrapWriters(writers...)...)
  200. w := io.MultiWriter(append(writers, p.Output)...)
  201. p.Output = w
  202. return p
  203. }
  204. // SetOutput sets accepts one or more io.Writer
  205. // and set a multi-writter instance to the Printer's Output.
  206. // Returns itself.
  207. //
  208. // Look `OutputFrom` too.
  209. func (p *Printer) SetOutput(writers ...io.Writer) *Printer {
  210. var w io.Writer
  211. if l := len(writers); l == 0 {
  212. return p
  213. } else if l == 1 {
  214. w = writers[0]
  215. } else {
  216. w = io.MultiWriter(writers...)
  217. }
  218. p.mu.Lock()
  219. p.outputs = wrapWriters(writers...)
  220. p.Output = w
  221. p.IsTerminal = terminal.IsTerminal(w)
  222. p.mu.Unlock()
  223. return p
  224. }
  225. // EnableDirectOutput will output the contents and flush them as fast as possible,
  226. // without storing them to the buffer to complete the `ReadWriteCloser` std interface.
  227. // Enable this if you need performance and you don't use the standard functions like `TeeReader`.
  228. // Returns itself.
  229. func (p *Printer) EnableDirectOutput() *Printer {
  230. p.mu.Lock()
  231. p.DirectOutput = true
  232. p.mu.Unlock()
  233. return p
  234. }
  235. // SetSync protects the output writer(s) with a lock.
  236. func (p *Printer) SetSync(useLocks bool) *Printer {
  237. p.mu.Lock()
  238. p.sync = true
  239. p.mu.Unlock()
  240. return p
  241. }
  242. func (p *Printer) lock() {
  243. if p.sync {
  244. p.mu.Lock()
  245. }
  246. }
  247. func (p *Printer) unlock() {
  248. if p.sync {
  249. p.mu.Unlock()
  250. }
  251. }
  252. // Print of a Printer accepts a value of "v",
  253. // tries to marshal its contents and flushes the result
  254. // to the Printer's output.
  255. //
  256. // If "v" implements the `Marshaler` type, then this marshaler
  257. // is called automatically, first.
  258. //
  259. // Print -> Store[Marshal -> err != nil && result -> Hijack(result) -> Write(result)] -> Flush[Printer.Write(buf) and Handle(buf)]
  260. //
  261. // Returns how much written and an error on failure.
  262. func (p *Printer) Print(v interface{}) (int, error) {
  263. return p.print(v, false)
  264. }
  265. // Println accepts a value of "v",
  266. // tries to marshal its contents and flushes the result
  267. // to this "p" Printer, it adds a new line at the ending,
  268. // the result doesn't contain this new line, therefore result's contents kept as expected.
  269. func (p *Printer) Println(v interface{}) (int, error) {
  270. return p.print(v, true)
  271. }
  272. func (p *Printer) print(v interface{}, appendNewLine bool) (int, error) {
  273. var (
  274. b []byte
  275. err error
  276. )
  277. if p.DirectOutput {
  278. b, err = p.WriteTo(v, p.Output, appendNewLine)
  279. } else {
  280. _, err = p.WriteTo(v, p.Writer, appendNewLine)
  281. if err != nil {
  282. return -1, err
  283. }
  284. b, err = p.Flush()
  285. }
  286. // flush error return last,
  287. // we should call handlers even if the result is a failure.
  288. if len(p.handlers) > 0 {
  289. // create the print result instance
  290. // only when printer uses handlers, so we can reduce the factory calls.
  291. res := withValue(v).withErr(err).withContents(b)
  292. for _, h := range p.handlers {
  293. // do NOT run each handler on its own goroutine because we need sync with the messages.
  294. // let end-developer decide the pattern.
  295. h(res)
  296. }
  297. }
  298. return len(b), err
  299. }
  300. func (p *Printer) readAndConsume() ([]byte, error) {
  301. b, err := ioutil.ReadAll(p.Reader)
  302. if err != nil && err != io.EOF {
  303. return b, err
  304. }
  305. return b, nil
  306. }
  307. // Flush will consume and flush the Printer's current contents.
  308. func (p *Printer) Flush() ([]byte, error) {
  309. p.lock()
  310. defer p.unlock()
  311. b, err := p.readAndConsume()
  312. if err != nil {
  313. return nil, err
  314. }
  315. _, err = p.Output.Write(b)
  316. return b, err
  317. }
  318. // Store will store-only the contents of "v".
  319. // Returns a PrintResult type in order to the final contents
  320. // be accessible by third-party tools.
  321. //
  322. // If you want to Print and Flush to the Printer's Output use `Print` instead.
  323. //
  324. // If "appendNewLine" is true then it writes a new line to the
  325. // Printer's output. Note that it doesn't concat it to the
  326. // returning PrintResult, therefore the "appendNewLine" it is not affect the rest
  327. // of the implementation like custom hijackers and handlers.
  328. func (p *Printer) Store(v interface{}, appendNewLine bool) error {
  329. _, err := p.WriteTo(v, p.Writer, appendNewLine)
  330. return err
  331. }
  332. // Write implements the io.Writer for the `Printer`.
  333. func (p *Printer) Write(b []byte) (n int, err error) {
  334. p.lock()
  335. if p.DirectOutput {
  336. n, err = p.Output.Write(b)
  337. } else {
  338. n, err = p.Writer.Write(b)
  339. }
  340. p.unlock()
  341. return
  342. }
  343. // WriteTo marshals and writes the "v" to the "w" writer.
  344. //
  345. // Returns this WriteTo's result information such as error, written.
  346. func (p *Printer) WriteTo(v interface{}, w io.Writer, appendNewLine bool) ([]byte, error) {
  347. var (
  348. b []byte
  349. err error
  350. )
  351. if hijack := p.hijack; hijack != nil {
  352. ctx := acquireCtx(v, p)
  353. defer releaseCtx(ctx)
  354. hijack(ctx)
  355. if ctx.canceled {
  356. return nil, ErrCanceled
  357. }
  358. b, err = ctx.marshalResult.b, ctx.marshalResult.err
  359. if err != nil {
  360. if err == ErrHandled {
  361. return b, nil
  362. }
  363. return b, err
  364. }
  365. }
  366. // needs marshal
  367. if len(b) == 0 {
  368. var marshaler Marshaler
  369. // check if implements the Marshaled
  370. if m, ok := v.(Marshaled); ok {
  371. marshaler = fromMarshaled(m)
  372. // check if implements the Marshaler
  373. } else if m, ok := v.(Marshaler); ok {
  374. marshaler = m
  375. // otherwise make check if printer has a marshaler
  376. // if not skip this WriteTo operation,
  377. // else set the marshaler to that (most common).
  378. } else {
  379. if p.marshal != nil {
  380. marshaler = p.marshal
  381. }
  382. }
  383. if marshaler == nil {
  384. return nil, ErrSkipped
  385. }
  386. b, err = marshaler.Marshal(v)
  387. if err != nil {
  388. return b, err
  389. }
  390. }
  391. p.lock()
  392. _, err = w.Write(b)
  393. if appendNewLine && err == nil {
  394. w.Write(NewLine) // we don't care about this error.
  395. }
  396. p.unlock()
  397. return b, err
  398. }
  399. // Hijack registers a callback which is executed
  400. // when ever `Print` or `WriteTo` is called,
  401. // this callback can intercept the final result
  402. // which will be written or be printed.
  403. //
  404. // Returns itself.
  405. func (p *Printer) Hijack(cb func(ctx *Ctx)) *Printer {
  406. p.mu.Lock()
  407. defer p.mu.Unlock()
  408. if p.hijack == nil {
  409. p.hijack = cb
  410. return p
  411. }
  412. oldCb := p.hijack
  413. newCb := cb
  414. // return the first failure
  415. p.hijack = func(ctx *Ctx) {
  416. oldCb(ctx)
  417. if ctx.continueToNext {
  418. newCb(ctx)
  419. }
  420. }
  421. return p
  422. }
  423. // PrintResult contains some useful information for a `Print` or `WriteTo` action that
  424. // are available inside handlers.
  425. type PrintResult struct {
  426. Written int
  427. Error error
  428. Contents []byte
  429. Value interface{}
  430. }
  431. // IsOK returns true if result's content is available,
  432. // otherwise false.
  433. func (p PrintResult) IsOK() bool {
  434. return p.Error == nil && len(p.Contents) > 0
  435. }
  436. // IsFailure returns true if result's content is not safe to read or it's available,
  437. // otherwise false.
  438. func (p PrintResult) IsFailure() bool {
  439. return !p.IsOK()
  440. }
  441. var printResult = PrintResult{}
  442. func withValue(v interface{}) PrintResult {
  443. printResult.Value = v
  444. return printResult
  445. }
  446. func (p PrintResult) withErr(err error) PrintResult {
  447. if err != nil {
  448. p.Written = -1
  449. }
  450. p.Error = err
  451. return p
  452. }
  453. func (p PrintResult) withContents(b []byte) PrintResult {
  454. if p.Error != nil {
  455. p.Written = -1
  456. } else {
  457. p.Written = len(b)
  458. p.Contents = b
  459. }
  460. return p
  461. }
  462. // Handle adds a callback which is called
  463. // whenever a `Print` is successfully executed, it's being executed
  464. // after the contents are written to its output.
  465. //
  466. // The callback accepts the final result,
  467. // can be used as an easy, pluggable, access to all the logs passed to the `Print`.
  468. // i.e: `Handle(func(result PrintResult){ fmt.Printf("%s\n", result.Contents)})`
  469. //
  470. // Returns itself.
  471. func (p *Printer) Handle(h func(PrintResult)) *Printer {
  472. p.mu.Lock()
  473. p.handlers = append(p.handlers, h)
  474. p.mu.Unlock()
  475. return p
  476. }
  477. func (p *Printer) restore(b []byte) {
  478. p.Writer.Write(b)
  479. }
  480. // Scan scans everything from "r" and prints
  481. // its new contents to the "p" Printer,
  482. // forever or until the returning "cancel" is fired, once.
  483. func (p *Printer) Scan(r io.Reader, addNewLine bool) (cancel func()) {
  484. var canceled uint32
  485. shouldCancel := func() bool {
  486. return atomic.LoadUint32(&canceled) > 0
  487. }
  488. cancel = func() {
  489. atomic.StoreUint32(&canceled, 1)
  490. }
  491. go func() {
  492. scanner := bufio.NewScanner(r)
  493. for {
  494. if shouldCancel() {
  495. break
  496. }
  497. if scanner.Scan() {
  498. if shouldCancel() {
  499. // re-store the bytes?
  500. p.restore(scanner.Bytes())
  501. break
  502. }
  503. text := scanner.Bytes()
  504. if addNewLine {
  505. text = append(text, NewLine...)
  506. }
  507. p.Print(text)
  508. }
  509. if err := scanner.Err(); err != nil {
  510. // TODO: do something with that or ignore it.
  511. }
  512. }
  513. }()
  514. return cancel
  515. }