printer.go 14 KB

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