ipc.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. const ipc = require('@achrinza/node-ipc')
  2. const DEFAULT_ID = process.env.VUE_CLI_IPC || 'vue-cli'
  3. const DEFAULT_IDLE_TIMEOUT = 3000
  4. const DEFAULT_OPTIONS = {
  5. networkId: DEFAULT_ID,
  6. autoConnect: true,
  7. disconnectOnIdle: false,
  8. idleTimeout: DEFAULT_IDLE_TIMEOUT,
  9. namespaceOnProject: true
  10. }
  11. const PROJECT_ID = process.env.VUE_CLI_PROJECT_ID
  12. exports.IpcMessenger = class IpcMessenger {
  13. constructor (options = {}) {
  14. options = Object.assign({}, DEFAULT_OPTIONS, options)
  15. ipc.config.id = this.id = options.networkId
  16. ipc.config.retry = 1500
  17. ipc.config.silent = true
  18. this.connected = false
  19. this.connecting = false
  20. this.disconnecting = false
  21. this.queue = null
  22. this.options = options
  23. this.listeners = []
  24. this.disconnectTimeout = 15000
  25. this.idleTimer = null
  26. // Prevent forced process exit
  27. // (or else ipc messages may not be sent before kill)
  28. process.exit = code => {
  29. process.exitCode = code
  30. }
  31. this._reset()
  32. }
  33. checkConnection () {
  34. if (!ipc.of[this.id]) {
  35. this.connected = false
  36. }
  37. }
  38. send (data, type = 'message') {
  39. this.checkConnection()
  40. if (this.connected) {
  41. if (this.options.namespaceOnProject && PROJECT_ID) {
  42. data = {
  43. _projectId: PROJECT_ID,
  44. _data: data
  45. }
  46. }
  47. ipc.of[this.id].emit(type, data)
  48. clearTimeout(this.idleTimer)
  49. if (this.options.disconnectOnIdle) {
  50. this.idleTimer = setTimeout(() => {
  51. this.disconnect()
  52. }, this.options.idleTimeout)
  53. }
  54. } else {
  55. this.queue.push(data)
  56. if (this.options.autoConnect && !this.connecting) {
  57. this.connect()
  58. }
  59. }
  60. }
  61. connect () {
  62. this.checkConnection()
  63. if (this.connected || this.connecting) return
  64. this.connecting = true
  65. this.disconnecting = false
  66. ipc.connectTo(this.id, () => {
  67. this.connected = true
  68. this.connecting = false
  69. this.queue && this.queue.forEach(data => this.send(data))
  70. this.queue = null
  71. ipc.of[this.id].on('message', this._onMessage)
  72. })
  73. }
  74. disconnect () {
  75. this.checkConnection()
  76. if (!this.connected || this.disconnecting) return
  77. this.disconnecting = true
  78. this.connecting = false
  79. const ipcTimer = setTimeout(() => {
  80. this._disconnect()
  81. }, this.disconnectTimeout)
  82. this.send({ done: true }, 'ack')
  83. ipc.of[this.id].on('ack', data => {
  84. if (data.ok) {
  85. clearTimeout(ipcTimer)
  86. this._disconnect()
  87. }
  88. })
  89. }
  90. on (listener) {
  91. this.listeners.push(listener)
  92. }
  93. off (listener) {
  94. const index = this.listeners.indexOf(listener)
  95. if (index !== -1) this.listeners.splice(index, 1)
  96. }
  97. _reset () {
  98. this.queue = []
  99. this.connected = false
  100. }
  101. _disconnect () {
  102. this.connected = false
  103. this.disconnecting = false
  104. ipc.disconnect(this.id)
  105. this._reset()
  106. }
  107. _onMessage (data) {
  108. this.listeners.forEach(fn => {
  109. if (this.options.namespaceOnProject && data._projectId) {
  110. if (data._projectId === PROJECT_ID) {
  111. data = data._data
  112. } else {
  113. return
  114. }
  115. }
  116. fn(data)
  117. })
  118. }
  119. }