callbacks-registry.js 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. 'use strict'
  2. const v8Util = process.atomBinding('v8_util')
  3. class CallbacksRegistry {
  4. constructor () {
  5. this.nextId = 0
  6. this.callbacks = {}
  7. }
  8. add (callback) {
  9. // The callback is already added.
  10. let id = v8Util.getHiddenValue(callback, 'callbackId')
  11. if (id != null) return id
  12. id = this.nextId += 1
  13. // Capture the location of the function and put it in the ID string,
  14. // so that release errors can be tracked down easily.
  15. const regexp = /at (.*)/gi
  16. const stackString = (new Error()).stack
  17. let filenameAndLine
  18. let match
  19. while ((match = regexp.exec(stackString)) !== null) {
  20. const location = match[1]
  21. if (location.includes('(native)')) continue
  22. if (location.includes('(<anonymous>)')) continue
  23. if (location.includes('electron.asar')) continue
  24. const ref = /([^/^)]*)\)?$/gi.exec(location)
  25. filenameAndLine = ref[1]
  26. break
  27. }
  28. this.callbacks[id] = callback
  29. v8Util.setHiddenValue(callback, 'callbackId', id)
  30. v8Util.setHiddenValue(callback, 'location', filenameAndLine)
  31. return id
  32. }
  33. get (id) {
  34. return this.callbacks[id] || function () {}
  35. }
  36. apply (id, ...args) {
  37. return this.get(id).apply(global, ...args)
  38. }
  39. remove (id) {
  40. const callback = this.callbacks[id]
  41. if (callback) {
  42. v8Util.deleteHiddenValue(callback, 'callbackId')
  43. delete this.callbacks[id]
  44. }
  45. }
  46. }
  47. module.exports = CallbacksRegistry