bufferizedPTY.js 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. /** @hidden */
  2. module.exports = function patchPTYModule (mod) {
  3. const oldSpawn = mod.spawn
  4. if (mod.patched) {
  5. return
  6. }
  7. mod.patched = true
  8. mod.spawn = (file, args, opt) => {
  9. let terminal = oldSpawn(file, args, opt)
  10. let timeout = null
  11. let buffer = Buffer.from('')
  12. let lastFlush = 0
  13. let nextTimeout = 0
  14. // Minimum prebuffering window (ms) if the input is non-stop flowing
  15. const minWindow = 5
  16. // Maximum buffering time (ms) until output must be flushed unconditionally
  17. const maxWindow = 100
  18. function flush () {
  19. if (buffer.length) {
  20. terminal.emit('data-buffered', buffer)
  21. }
  22. lastFlush = Date.now()
  23. buffer = Buffer.from('')
  24. }
  25. function reschedule () {
  26. if (timeout) {
  27. clearTimeout(timeout)
  28. }
  29. nextTimeout = Date.now() + minWindow
  30. timeout = setTimeout(() => {
  31. timeout = null
  32. flush()
  33. }, minWindow)
  34. }
  35. terminal.on('data', data => {
  36. if (typeof data === 'string') {
  37. data = Buffer.from(data)
  38. }
  39. buffer = Buffer.concat([buffer, data])
  40. if (Date.now() - lastFlush > maxWindow) {
  41. // Taking too much time buffering, flush to keep things interactive
  42. flush()
  43. } else {
  44. if (Date.now() > nextTimeout - maxWindow / 10) {
  45. // Extend the window if it's expiring
  46. reschedule()
  47. }
  48. }
  49. })
  50. return terminal
  51. }
  52. }