objects-registry.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. 'use strict'
  2. const v8Util = process.atomBinding('v8_util')
  3. class ObjectsRegistry {
  4. constructor () {
  5. this.nextId = 0
  6. // Stores all objects by ref-counting.
  7. // (id) => {object, count}
  8. this.storage = {}
  9. // Stores the IDs of objects referenced by WebContents.
  10. // (webContentsId) => [id]
  11. this.owners = {}
  12. }
  13. // Register a new object and return its assigned ID. If the object is already
  14. // registered then the already assigned ID would be returned.
  15. add (webContents, obj) {
  16. // Get or assign an ID to the object.
  17. const id = this.saveToStorage(obj)
  18. // Add object to the set of referenced objects.
  19. const webContentsId = webContents.getId()
  20. let owner = this.owners[webContentsId]
  21. if (!owner) {
  22. owner = this.owners[webContentsId] = new Set()
  23. this.registerDeleteListener(webContents, webContentsId)
  24. }
  25. if (!owner.has(id)) {
  26. owner.add(id)
  27. // Increase reference count if not referenced before.
  28. this.storage[id].count++
  29. }
  30. return id
  31. }
  32. // Get an object according to its ID.
  33. get (id) {
  34. const pointer = this.storage[id]
  35. if (pointer != null) return pointer.object
  36. }
  37. // Dereference an object according to its ID.
  38. remove (webContentsId, id) {
  39. // Dereference from the storage.
  40. this.dereference(id)
  41. // Also remove the reference in owner.
  42. let owner = this.owners[webContentsId]
  43. if (owner) {
  44. owner.delete(id)
  45. }
  46. }
  47. // Clear all references to objects refrenced by the WebContents.
  48. clear (webContentsId) {
  49. let owner = this.owners[webContentsId]
  50. if (!owner) return
  51. for (let id of owner) this.dereference(id)
  52. delete this.owners[webContentsId]
  53. }
  54. // Private: Saves the object into storage and assigns an ID for it.
  55. saveToStorage (object) {
  56. let id = v8Util.getHiddenValue(object, 'atomId')
  57. if (!id) {
  58. id = ++this.nextId
  59. this.storage[id] = {
  60. count: 0,
  61. object: object
  62. }
  63. v8Util.setHiddenValue(object, 'atomId', id)
  64. }
  65. return id
  66. }
  67. // Private: Dereference the object from store.
  68. dereference (id) {
  69. let pointer = this.storage[id]
  70. if (pointer == null) {
  71. return
  72. }
  73. pointer.count -= 1
  74. if (pointer.count === 0) {
  75. v8Util.deleteHiddenValue(pointer.object, 'atomId')
  76. delete this.storage[id]
  77. }
  78. }
  79. // Private: Clear the storage when webContents is reloaded/navigated.
  80. registerDeleteListener (webContents, webContentsId) {
  81. const processId = webContents.getProcessId()
  82. const listener = (event, deletedProcessId) => {
  83. if (deletedProcessId === processId) {
  84. webContents.removeListener('render-view-deleted', listener)
  85. this.clear(webContentsId)
  86. }
  87. }
  88. webContents.on('render-view-deleted', listener)
  89. }
  90. }
  91. module.exports = new ObjectsRegistry()