homebridge 2.0.0-alpha.4 → 2.0.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +1 -1
  2. package/bin/homebridge.js +22 -0
  3. package/dist/api.d.ts +210 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +140 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/bridgeService.d.ts +122 -0
  8. package/dist/bridgeService.d.ts.map +1 -0
  9. package/dist/bridgeService.js +396 -0
  10. package/dist/bridgeService.js.map +1 -0
  11. package/dist/childBridgeFork.d.ts +38 -0
  12. package/dist/childBridgeFork.d.ts.map +1 -0
  13. package/dist/childBridgeFork.js +241 -2
  14. package/dist/childBridgeFork.js.map +1 -7
  15. package/dist/childBridgeService.d.ts +204 -0
  16. package/dist/childBridgeService.d.ts.map +1 -0
  17. package/dist/childBridgeService.js +452 -0
  18. package/dist/childBridgeService.js.map +1 -0
  19. package/dist/childMatterBridgeFork.d.ts +108 -0
  20. package/dist/childMatterBridgeFork.d.ts.map +1 -0
  21. package/dist/childMatterBridgeFork.js +330 -0
  22. package/dist/childMatterBridgeFork.js.map +1 -0
  23. package/dist/childMatterBridgeService.d.ts +166 -0
  24. package/dist/childMatterBridgeService.d.ts.map +1 -0
  25. package/dist/childMatterBridgeService.js +623 -0
  26. package/dist/childMatterBridgeService.js.map +1 -0
  27. package/dist/cli.d.ts +3 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +90 -2
  30. package/dist/cli.js.map +1 -7
  31. package/dist/externalPortService.d.ts +33 -0
  32. package/dist/externalPortService.d.ts.map +1 -0
  33. package/dist/externalPortService.js +59 -0
  34. package/dist/externalPortService.js.map +1 -0
  35. package/dist/index.d.ts +90 -1099
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +21 -2
  38. package/dist/index.js.map +1 -7
  39. package/dist/ipcService.d.ts +46 -0
  40. package/dist/ipcService.d.ts.map +1 -0
  41. package/dist/ipcService.js +62 -0
  42. package/dist/ipcService.js.map +1 -0
  43. package/dist/logger.d.ts +78 -0
  44. package/dist/logger.d.ts.map +1 -0
  45. package/dist/logger.js +138 -0
  46. package/dist/logger.js.map +1 -0
  47. package/dist/matter/index.d.ts +13 -0
  48. package/dist/matter/index.d.ts.map +1 -0
  49. package/dist/matter/index.js +12 -0
  50. package/dist/matter/index.js.map +1 -0
  51. package/dist/matter/matterBridge.d.ts +64 -0
  52. package/dist/matter/matterBridge.d.ts.map +1 -0
  53. package/dist/matter/matterBridge.js +154 -0
  54. package/dist/matter/matterBridge.js.map +1 -0
  55. package/dist/matter/matterConfigValidator.d.ts +27 -0
  56. package/dist/matter/matterConfigValidator.d.ts.map +1 -0
  57. package/dist/matter/matterConfigValidator.js +162 -0
  58. package/dist/matter/matterConfigValidator.js.map +1 -0
  59. package/dist/matter/matterDevice.d.ts +107 -0
  60. package/dist/matter/matterDevice.d.ts.map +1 -0
  61. package/dist/matter/matterDevice.js +913 -0
  62. package/dist/matter/matterDevice.js.map +1 -0
  63. package/dist/matter/matterDiagnostics.d.ts +121 -0
  64. package/dist/matter/matterDiagnostics.d.ts.map +1 -0
  65. package/dist/matter/matterDiagnostics.js +323 -0
  66. package/dist/matter/matterDiagnostics.js.map +1 -0
  67. package/dist/matter/matterErrorHandler.d.ts +113 -0
  68. package/dist/matter/matterErrorHandler.d.ts.map +1 -0
  69. package/dist/matter/matterErrorHandler.js +482 -0
  70. package/dist/matter/matterErrorHandler.js.map +1 -0
  71. package/dist/matter/matterNetworkMonitor.d.ts +65 -0
  72. package/dist/matter/matterNetworkMonitor.d.ts.map +1 -0
  73. package/dist/matter/matterNetworkMonitor.js +227 -0
  74. package/dist/matter/matterNetworkMonitor.js.map +1 -0
  75. package/dist/matter/matterServer.d.ts +110 -0
  76. package/dist/matter/matterServer.d.ts.map +1 -0
  77. package/dist/matter/matterServer.js +584 -0
  78. package/dist/matter/matterServer.js.map +1 -0
  79. package/dist/matter/matterSharedTypes.d.ts +167 -0
  80. package/dist/matter/matterSharedTypes.d.ts.map +1 -0
  81. package/dist/matter/matterSharedTypes.js +55 -0
  82. package/dist/matter/matterSharedTypes.js.map +1 -0
  83. package/dist/matter/matterTypes.d.ts +35 -0
  84. package/dist/matter/matterTypes.d.ts.map +1 -0
  85. package/dist/matter/matterTypes.js +278 -0
  86. package/dist/matter/matterTypes.js.map +1 -0
  87. package/dist/matter/portAllocator.d.ts +85 -0
  88. package/dist/matter/portAllocator.d.ts.map +1 -0
  89. package/dist/matter/portAllocator.js +296 -0
  90. package/dist/matter/portAllocator.js.map +1 -0
  91. package/dist/platformAccessory.d.ts +56 -0
  92. package/dist/platformAccessory.d.ts.map +1 -0
  93. package/dist/platformAccessory.js +105 -0
  94. package/dist/platformAccessory.js.map +1 -0
  95. package/dist/plugin.d.ts +30 -0
  96. package/dist/plugin.d.ts.map +1 -0
  97. package/dist/plugin.js +182 -0
  98. package/dist/plugin.js.map +1 -0
  99. package/dist/pluginManager.d.ts +77 -0
  100. package/dist/pluginManager.d.ts.map +1 -0
  101. package/dist/pluginManager.js +375 -0
  102. package/dist/pluginManager.js.map +1 -0
  103. package/dist/server.d.ts +67 -0
  104. package/dist/server.d.ts.map +1 -0
  105. package/dist/server.js +799 -0
  106. package/dist/server.js.map +1 -0
  107. package/dist/storageService.d.ts +13 -0
  108. package/dist/storageService.d.ts.map +1 -0
  109. package/dist/storageService.js +41 -0
  110. package/dist/storageService.js.map +1 -0
  111. package/dist/user.d.ts +13 -0
  112. package/dist/user.d.ts.map +1 -0
  113. package/dist/user.js +29 -0
  114. package/dist/user.js.map +1 -0
  115. package/dist/util/mac.d.ts +5 -0
  116. package/dist/util/mac.d.ts.map +1 -0
  117. package/dist/util/mac.js +14 -0
  118. package/dist/util/mac.js.map +1 -0
  119. package/dist/version.d.ts +3 -0
  120. package/dist/version.d.ts.map +1 -0
  121. package/dist/version.js +16 -0
  122. package/dist/version.js.map +1 -0
  123. package/package.json +31 -34
  124. package/bin/homebridge +0 -19
@@ -1,2 +1,241 @@
1
- import y from"node:process";import{AccessoryEventTypes as G,HAPStorage as De}from"hap-nodejs";import{EventEmitter as Pe}from"node:events";import Y from"hap-nodejs";import ye from"semver";import K from"node:util";import S from"chalk";var c=class s{static internal=new s;static loggerCache=new Map;static debugEnabled=!1;static timestampEnabled=!0;prefix;constructor(e){this.prefix=e}static withPrefix(e){let i=s.loggerCache.get(e);if(i)return i;{let t=new s(e),r=t.info.bind(t);r.info=t.info,r.success=t.success,r.warn=t.warn,r.error=t.error,r.debug=t.debug,r.log=t.log,r.prefix=t.prefix;let n=r;return s.loggerCache.set(e,n),n}}static setDebugEnabled(e=!0){s.debugEnabled=e}static setTimestampEnabled(e=!0){s.timestampEnabled=e}static forceColor(){S.level=1}info(e,...i){this.log("info",e,...i)}success(e,...i){this.log("success",e,...i)}warn(e,...i){this.log("warn",e,...i)}error(e,...i){this.log("error",e,...i)}debug(e,...i){this.log("debug",e,...i)}log(e,i,...t){if(e==="debug"&&!s.debugEnabled)return;i=K.format(i,...t);let r=console.log;switch(e){case"success":i=S.green(i);break;case"warn":i=S.yellow(i),r=console.error;break;case"error":i=S.red(i),r=console.error;break;case"debug":i=S.gray(i);break}if(this.prefix&&(i=`${p(this.prefix)} ${i}`),s.timestampEnabled){let n=new Date;i=S.white(`[${n.toLocaleString()}] `)+i}r(i)}};function p(s){return S.cyan(`[${s}]`)}import{EventEmitter as Z}from"node:events";import{Accessory as k,AccessoryEventTypes as ee,Categories as ie}from"hap-nodejs";var m=class s extends Z{static injectedAccessory;_associatedPlugin;_associatedPlatform;_associatedHAPAccessory;displayName;UUID;category;services=[];context={};constructor(e,i,t){super(),this._associatedHAPAccessory=s.injectedAccessory?s.injectedAccessory:new k(e,i),t&&(this._associatedHAPAccessory.category=t),this.displayName=this._associatedHAPAccessory.displayName,this.UUID=this._associatedHAPAccessory.UUID,this.category=t||ie.OTHER,this.services=this._associatedHAPAccessory.services,this._associatedHAPAccessory.on(ee.IDENTIFY,(r,n)=>{this.emit("identify",r,()=>{}),n()})}addService(e,...i){return this._associatedHAPAccessory.addService(e,...i)}removeService(e){this._associatedHAPAccessory.removeService(e)}getService(e){return this._associatedHAPAccessory.getService(e)}getServiceById(e,i){return this._associatedHAPAccessory.getServiceById(e,i)}configureController(e){this._associatedHAPAccessory.configureController(e)}removeController(e){this._associatedHAPAccessory.removeController(e)}static serialize(e){return{plugin:e._associatedPlugin,platform:e._associatedPlatform,context:e.context,...k.serialize(e._associatedHAPAccessory)}}static deserialize(e){let i=k.deserialize(e);s.injectedAccessory=i;let t=new s(i.displayName,i.UUID);return s.injectedAccessory=void 0,t._associatedPlugin=e.plugin,t._associatedPlatform=e.platform,t.context=e.context,t.category=e.category,t}};import{execSync as ue}from"node:child_process";import C from"node:fs";import{createRequire as he}from"node:module";import f from"node:path";import R from"node:process";import le from"node:assert";import de from"node:path";import z from"node:process";import{pathToFileURL as ge}from"node:url";import{satisfies as W}from"semver";import te from"node:fs";import{dirname as re,join as se}from"node:path";import{fileURLToPath as ne}from"node:url";var oe=ne(import.meta.url),ae=re(oe);function ce(){let s=se(ae,"../package.json");return JSON.parse(te.readFileSync(s,{encoding:"utf8"}))}function A(){return ce().version}var N=c.internal,L=class{pluginName;scope;pluginPath;isESM;disabled=!1;version;main;loadContext;pluginInitializer;registeredAccessories=new Map;registeredPlatforms=new Map;activeDynamicPlatforms=new Map;constructor(e,i,t,r){if(this.pluginName=e,this.scope=r,this.pluginPath=i,this.version=t.version||"0.0.0",this.main="",t.exports)if(typeof t.exports=="string")this.main=t.exports;else{let n=t.exports.import||t.exports.require||t.exports.node||t.exports.default||t.exports["."];typeof n!="string"?n.import?this.main=n.import:this.main=n.require||n.node||n.default:this.main=n}this.main||(this.main=t.main||"./index.js"),this.isESM=this.main.endsWith(".mjs")||this.main.endsWith(".js")&&t.type==="module",t.peerDependencies&&(!t.engines||!t.engines.homebridge)&&(t.engines=t.engines||{},t.engines.homebridge=t.peerDependencies.homebridge),this.loadContext={engines:t.engines,dependencies:t.dependencies}}getPluginIdentifier(){return(this.scope?`${this.scope}/`:"")+this.pluginName}getPluginPath(){return this.pluginPath}registerAccessory(e,i){if(this.registeredAccessories.has(e))throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register an accessory '${e}' which has already been registered!`);this.disabled||N.info("Registering accessory '%s'",`${this.getPluginIdentifier()}.${e}`),this.registeredAccessories.set(e,i)}registerPlatform(e,i){if(this.registeredPlatforms.has(e))throw new Error(`Plugin '${this.getPluginIdentifier()}' tried to register a platform '${e}' which has already been registered!`);this.disabled||N.info("Registering platform '%s'",`${this.getPluginIdentifier()}.${e}`),this.registeredPlatforms.set(e,i)}getAccessoryConstructor(e){let i=u.getAccessoryName(e),t=this.registeredAccessories.get(i);if(!t)throw new Error(`The requested accessory '${i}' was not registered by the plugin '${this.getPluginIdentifier()}'.`);return t}getPlatformConstructor(e){let i=u.getPlatformName(e),t=this.registeredPlatforms.get(i);if(!t)throw new Error(`The requested platform '${i}' was not registered by the plugin '${this.getPluginIdentifier()}'.`);if(this.activeDynamicPlatforms.has(i))throw new Error(`The dynamic platform ${i} from the plugin ${this.getPluginIdentifier()} is configured times in your config.json.`);return t}assignDynamicPlatform(e,i){let t=u.getPlatformName(e),r=this.activeDynamicPlatforms.get(t);r||(r=[],this.activeDynamicPlatforms.set(t,r)),r.unshift(i)}getActiveDynamicPlatform(e){let i=this.activeDynamicPlatforms.get(e);return i&&i[0]}async load(){let e=this.loadContext;if(le(e,"Reached illegal state. Plugin state is undefined!"),this.loadContext=void 0,!e.engines||!e.engines.homebridge)throw new Error(`Plugin ${this.pluginPath} does not contain the 'homebridge' package in 'engines'.`);let i=e.engines.homebridge,t=e.engines.node;W(A(),i,{includePrerelease:!0})||N.error(`The plugin "${this.pluginName}" requires a Homebridge version of ${i} which does not satisfy the current Homebridge version of ${A()}. You may need to update this plugin (or Homebridge) to a newer version. You may face unexpected issues or stability problems running this plugin.`),t&&!W(z.version,t)&&N.warn(`The plugin "${this.pluginName}" requires Node.js version of ${t} which does not satisfy the current Node.js version of ${z.version}. You may need to upgrade your installation of Node.js - see https://homebridge.io/w/JTKEF`);let r=e.dependencies||{};(r.homebridge||r["hap-nodejs"])&&N.error(`The plugin "${this.pluginName}" defines 'homebridge' and/or 'hap-nodejs' in their 'dependencies' section, meaning they carry an additional copy of homebridge and hap-nodejs. This not only wastes disk space, but also can cause major incompatibility issues and thus is considered bad practice. Please inform the developer to update their plugin!`);let n=de.join(this.pluginPath,this.main),o=await import(ge(n).href);if(typeof o=="function")this.pluginInitializer=o;else if(o&&typeof o.default=="function")this.pluginInitializer=o.default;else throw new Error(`Plugin ${this.pluginPath} does not export a initializer function from main.`)}initialize(e){if(!this.pluginInitializer)throw new Error("Tried to initialize a plugin which hasn't been loaded yet!");return this.pluginInitializer(e)}};var l=c.internal,pe=he(import.meta.url),q=pe.resolve.paths(""),u=class s{static PLUGIN_IDENTIFIER_PATTERN=/^((@[\w-]*)\/)?(homebridge-[\w-]*)$/;api;searchPaths=new Set;strictPluginResolution=!1;activePlugins;disabledPlugins;plugins=new Map;pluginIdentifierTranslation=new Map;accessoryToPluginMap=new Map;platformToPluginMap=new Map;currentInitializingPlugin;constructor(e,i){this.api=e,i&&(i.customPluginPath&&this.searchPaths.add(f.resolve(R.cwd(),i.customPluginPath)),this.strictPluginResolution=i.strictPluginResolution||!1,this.activePlugins=i.activePlugins,this.disabledPlugins=Array.isArray(i.disabledPlugins)?i.disabledPlugins:void 0),this.api.on("registerAccessory",this.handleRegisterAccessory.bind(this)),this.api.on("registerPlatform",this.handleRegisterPlatform.bind(this))}static isQualifiedPluginIdentifier(e){return s.PLUGIN_IDENTIFIER_PATTERN.test(e)}static extractPluginName(e){return e.match(s.PLUGIN_IDENTIFIER_PATTERN)[3]}static extractPluginScope(e){return e.match(s.PLUGIN_IDENTIFIER_PATTERN)[2]}static getAccessoryName(e){return e.includes(".")?e.split(".")[1]:e}static getPlatformName(e){return e.includes(".")?e.split(".")[1]:e}static getPluginIdentifier(e){return e.split(".")[0]}async initializeInstalledPlugins(){l.info("---"),this.loadInstalledPlugins();for(let[e,i]of this.plugins){try{await i.load()}catch(t){l.error("===================="),l.error(`ERROR LOADING PLUGIN ${e}:`),l.error(t.stack),l.error("===================="),this.plugins.delete(e);continue}this.disabledPlugins&&this.disabledPlugins.includes(i.getPluginIdentifier())&&(i.disabled=!0),i.disabled?l.warn(`Disabled plugin: ${e}@${i.version}`):l.info(`Loaded plugin: ${e}@${i.version}`),await this.initializePlugin(i,e),l.info("---")}this.currentInitializingPlugin=void 0}async initializePlugin(e,i){try{this.currentInitializingPlugin=e,await e.initialize(this.api)}catch(t){l.error("===================="),l.error(`ERROR INITIALIZING PLUGIN ${i}:`),l.error(t.stack),l.error("===================="),this.plugins.delete(i)}}handleRegisterAccessory(e,i,t){if(!this.currentInitializingPlugin)throw new Error(`Unexpected accessory registration. Plugin ${t?`'${t}' `:""}tried to register outside the initializer function!`);t&&t!==this.currentInitializingPlugin.getPluginIdentifier()&&(l.info(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${t}'. Please report this to the developer!`),this.pluginIdentifierTranslation.set(t,this.currentInitializingPlugin.getPluginIdentifier())),this.currentInitializingPlugin.registerAccessory(e,i);let r=this.accessoryToPluginMap.get(e);r||(r=[],this.accessoryToPluginMap.set(e,r)),r.push(this.currentInitializingPlugin)}handleRegisterPlatform(e,i,t){if(!this.currentInitializingPlugin)throw new Error(`Unexpected platform registration. Plugin ${t?`'${t}' `:""}tried to register outside the initializer function!`);t&&t!==this.currentInitializingPlugin.getPluginIdentifier()&&(l.debug(`Plugin '${this.currentInitializingPlugin.getPluginIdentifier()}' tried to register with an incorrect plugin identifier: '${t}'. Please report this to the developer!`),this.pluginIdentifierTranslation.set(t,this.currentInitializingPlugin.getPluginIdentifier())),this.currentInitializingPlugin.registerPlatform(e,i);let r=this.platformToPluginMap.get(e);r||(r=[],this.platformToPluginMap.set(e,r)),r.push(this.currentInitializingPlugin)}getPluginForAccessory(e){let i;if(e.includes(".")){let t=s.getPluginIdentifier(e);if(!this.hasPluginRegistered(t))throw new Error(`The requested plugin '${t}' was not registered.`);i=this.getPlugin(t)}else{let t=this.accessoryToPluginMap.get(e);if(!t)throw new Error(`No plugin was found for the accessory "${e}" in your config.json. Please make sure the corresponding plugin is installed correctly.`);if(t.length>1){let r=t.map(n=>`${n.getPluginIdentifier()}.${e}`).join(", ");if(t=t.filter(n=>!n.disabled),t.length!==1)throw new Error(`The requested accessory '${e}' has been registered multiple times. Please be more specific by writing one of: ${r}`)}i=t[0],e=`${i.getPluginIdentifier()}.${e}`}return i}getPluginForPlatform(e){let i;if(e.includes(".")){let t=s.getPluginIdentifier(e);if(!this.hasPluginRegistered(t))throw new Error(`The requested plugin '${t}' was not registered.`);i=this.getPlugin(t)}else{let t=this.platformToPluginMap.get(e);if(!t)throw new Error(`No plugin was found for the platform "${e}" in your config.json. Please make sure the corresponding plugin is installed correctly.`);if(t.length>1){let r=t.map(n=>`${n.getPluginIdentifier()}.${e}`).join(", ");if(t=t.filter(n=>!n.disabled),t.length!==1)throw new Error(`The requested platform '${e}' has been registered multiple times. Please be more specific by writing one of: ${r}`)}i=t[0],e=`${i.getPluginIdentifier()}.${e}`}return i}hasPluginRegistered(e){return this.plugins.has(e)||this.pluginIdentifierTranslation.has(e)}getPlugin(e){let i=this.plugins.get(e);if(i)return i;{let t=this.pluginIdentifierTranslation.get(e);if(t)return this.plugins.get(t)}}getPluginByActiveDynamicPlatform(e){let i=(this.platformToPluginMap.get(e)||[]).filter(t=>!!t.getActiveDynamicPlatform(e));if(i.length!==0)if(i.length>1){let t=i.map(r=>r.getPluginIdentifier()).join(", ");throw new Error(`'${e}' is an ambiguous platform name. It was registered by multiple plugins: ${t}`)}else return i[0]}loadInstalledPlugins(){this.loadDefaultPaths(),this.searchPaths.forEach(e=>{if(C.existsSync(e))if(C.existsSync(f.join(e,"package.json")))try{this.loadPlugin(e)}catch(i){l.warn(i.message)}else{let i=C.readdirSync(e).filter(t=>{try{return C.statSync(f.resolve(e,t)).isDirectory()}catch(r){return l.debug(`Ignoring path ${f.resolve(e,t)} - ${r.message}`),!1}});i.slice().filter(t=>t.charAt(0)==="@").forEach(t=>{let r=i.indexOf(t);i.splice(r,1);let n=f.join(e,t);C.readdirSync(n).filter(o=>s.isQualifiedPluginIdentifier(o)).filter(o=>{try{return C.statSync(f.resolve(n,o)).isDirectory()}catch(d){return l.debug(`Ignoring path ${f.resolve(n,o)} - ${d.message}`),!1}}).forEach(o=>i.push(`${t}/${o}`))}),i.filter(t=>s.isQualifiedPluginIdentifier(t)&&(!this.activePlugins||this.activePlugins.includes(t))).forEach(t=>{try{let r=f.resolve(e,t);this.loadPlugin(r)}catch(r){l.warn(r.message)}})}}),this.plugins.size===0&&l.warn("No plugins found.")}loadPlugin(e){let i=s.loadPackageJSON(e),t=i.name,r=s.extractPluginName(t),n=s.extractPluginScope(t),o=this.plugins.get(t);if(o)throw new Error(`Warning: skipping plugin found at '${e}' since we already loaded the same plugin from '${o.getPluginPath()}'.`);let d=new L(r,e,i,n);return this.plugins.set(t,d),d}static loadPackageJSON(e){let i=f.join(e,"package.json"),t;if(!C.existsSync(i))throw new Error(`Plugin ${e} does not contain a package.json.`);try{t=JSON.parse(C.readFileSync(i,{encoding:"utf8"}))}catch(r){throw new Error(`Plugin ${e} contains an invalid package.json. Error: ${r}`)}if(!t.name||!s.isQualifiedPluginIdentifier(t.name))throw new Error(`Plugin ${e} does not have a package name that begins with 'homebridge-' or '@scope/homebridge-.`);if(!t.keywords||!t.keywords.includes("homebridge-plugin"))throw new Error(`Plugin ${e} package.json does not contain the keyword 'homebridge-plugin'.`);return t}loadDefaultPaths(){if(this.strictPluginResolution){this.searchPaths.size===0&&this.addNpmPrefixToSearchPaths();return}q&&q.forEach(e=>this.searchPaths.add(e)),R.env.NODE_PATH?R.env.NODE_PATH.split(f.delimiter).filter(e=>!!e).forEach(e=>this.searchPaths.add(e)):(R.platform!=="win32"&&(this.searchPaths.add("/usr/local/lib/node_modules"),this.searchPaths.add("/usr/lib/node_modules")),this.addNpmPrefixToSearchPaths())}addNpmPrefixToSearchPaths(){R.platform==="win32"?this.searchPaths.add(f.join(R.env.APPDATA,"npm/node_modules")):this.searchPaths.add(ue('/bin/echo -n "$(npm -g prefix)/lib/node_modules"',{env:Object.assign({npm_config_loglevel:"silent",npm_update_notifier:"false"},R.env)}).toString("utf8"))}};import me from"node:os";import D from"node:path";var I=class s{static customStoragePath;static storageAccessed=!1;static configPath(){return D.join(s.storagePath(),"config.json")}static persistPath(){return D.join(s.storagePath(),"persist")}static cachedAccessoryPath(){return D.join(s.storagePath(),"accessories")}static storagePath(){return s.storageAccessed=!0,s.customStoragePath?s.customStoragePath:D.join(me.homedir(),".homebridge")}static setStoragePath(...e){if(s.storageAccessed)throw new Error("Storage path was already accessed and cannot be changed anymore. Try initializing your custom storage path earlier!");s.customStoragePath=D.resolve(...e)}};var Ae=c.internal;var x=class extends Pe{version=2.7;serverVersion=A();user=I;hap=Y;hapLegacyTypes=Y.LegacyTypes;platformAccessory=m;constructor(){super()}versionGreaterOrEqual(e){return ye.gte(this.serverVersion,e)}static isDynamicPlatformPlugin(e){return"configureAccessory"in e}static isStaticPlatformPlugin(e){return"accessories"in e}signalFinished(){this.emit("didFinishLaunching")}signalShutdown(){this.emit("shutdown")}registerAccessory(e,i,t){typeof i=="function"?(t=i,i=e,this.emit("registerAccessory",i,t)):this.emit("registerAccessory",i,t,e)}registerPlatform(e,i,t){typeof i=="function"?(t=i,i=e,this.emit("registerPlatform",i,t)):this.emit("registerPlatform",i,t,e)}publishCameraAccessories(e,i){this.publishExternalAccessories(e,i)}publishExternalAccessories(e,i){u.isQualifiedPluginIdentifier(e)||Ae.info(`One of your plugins incorrectly registered an external accessory using the platform name (${e}) and not the plugin identifier. Please report this to the developer!`),i.forEach(t=>{if(!(t instanceof m))throw new TypeError(`${e} attempt to register an accessory that isn't PlatformAccessory!`);t._associatedPlugin=e}),this.emit("publishExternalAccessories",i)}registerPlatformAccessories(e,i,t){t.forEach(r=>{if(!(r instanceof m))throw new TypeError(`${e} - ${i} attempt to register an accessory that isn't PlatformAccessory!`);r._associatedPlugin=e,r._associatedPlatform=i}),this.emit("registerPlatformAccessories",t)}updatePlatformAccessories(e){this.emit("updatePlatformAccessories",e)}unregisterPlatformAccessories(e,i,t){t.forEach(r=>{if(!(r instanceof m))throw new TypeError(`${e} - ${i} attempt to unregister an accessory that isn't PlatformAccessory!`)}),this.emit("unregisterPlatformAccessories",t)}};import{Accessory as be,AccessoryEventTypes as E,Bridge as Ce,Categories as Ie,Characteristic as T,CharacteristicEventTypes as Ee,CharacteristicWarningType as w,HAPLibraryVersion as Se,once as Re,Service as $,uuid as Q}from"hap-nodejs";import v from"node:path";import P from"fs-extra";var M=class{constructor(e){this.baseDirectory=e}initSync(){return P.ensureDirSync(this.baseDirectory)}getItemSync(e){let i=v.resolve(this.baseDirectory,e);return P.pathExistsSync(i)?P.readJsonSync(i):null}async getItem(e){let i=v.resolve(this.baseDirectory,e);return await P.pathExists(i)?await P.readJson(i):null}setItemSync(e,i){return P.writeJsonSync(v.resolve(this.baseDirectory,e),i)}setItem(e,i){return P.writeJson(v.resolve(this.baseDirectory,e),i)}copyItem(e,i){return P.copyFile(v.resolve(this.baseDirectory,e),v.resolve(this.baseDirectory,i))}copyItemSync(e,i){return P.copyFileSync(v.resolve(this.baseDirectory,e),v.resolve(this.baseDirectory,i))}removeItemSync(e){return P.removeSync(v.resolve(this.baseDirectory,e))}};import ve from"node:crypto";function V(s){let e=ve.createHash("sha1");e.update(s);let i=e.digest("hex"),t=0;return"xx:xx:xx:xx:xx:xx".replace(/x/g,()=>i[t++]).toUpperCase()}var a=c.internal,U=class s{constructor(e,i,t,r,n,o){this.api=e;this.pluginManager=i;this.externalPortService=t;this.bridgeOptions=r;this.bridgeConfig=n;this.config=o;this.storageService=new M(this.bridgeOptions.cachedAccessoriesDir),this.storageService.initSync(),this.allowInsecureAccess=this.bridgeOptions.insecureAccess||!1,this.api.on("registerPlatformAccessories",this.handleRegisterPlatformAccessories.bind(this)),this.api.on("updatePlatformAccessories",this.handleUpdatePlatformAccessories.bind(this)),this.api.on("unregisterPlatformAccessories",this.handleUnregisterPlatformAccessories.bind(this)),this.api.on("publishExternalAccessories",this.handlePublishExternalAccessories.bind(this)),this.bridge=new Ce(n.name,Q.generate("HomeBridge")),this.bridge.on(E.CHARACTERISTIC_WARNING,()=>{})}bridge;storageService;allowInsecureAccess;cachedPlatformAccessories=[];cachedAccessoriesFileLoaded=!1;publishedExternalAccessories=new Map;static printCharacteristicWriteWarning(e,i,t,r){let n="See https://homebridge.io/w/JtMGR for more info.";switch(r.type){case w.SLOW_READ:case w.SLOW_WRITE:t.ignoreSlow||a.info(p(e.getPluginIdentifier()),"This plugin slows down Homebridge.",r.message,n);break;case w.TIMEOUT_READ:case w.TIMEOUT_WRITE:a.error(p(e.getPluginIdentifier()),"This plugin slows down Homebridge.",r.message,n);break;case w.WARN_MESSAGE:a.info(p(e.getPluginIdentifier()),`This plugin generated a warning from the characteristic '${r.characteristic.displayName}':`,`${r.message}.`,n);break;case w.ERROR_MESSAGE:a.error(p(e.getPluginIdentifier()),`This plugin threw an error from the characteristic '${r.characteristic.displayName}':`,`${r.message}.`,n);break;case w.DEBUG_MESSAGE:a.debug(p(e.getPluginIdentifier()),`Characteristic '${r.characteristic.displayName}':`,`${r.message}.`,n);break;default:a.info(p(e.getPluginIdentifier()),`This plugin generated a warning from the characteristic '${r.characteristic.displayName}':`,`${r.message}.`,n);break}r.stack&&a.debug(p(e.getPluginIdentifier()),r.stack)}publishBridge(){let e=this.bridgeConfig,i=this.bridge.getService($.AccessoryInformation);i.setCharacteristic(T.Manufacturer,e.manufacturer||"homebridge.io"),i.setCharacteristic(T.Model,e.model||"homebridge"),i.setCharacteristic(T.SerialNumber,e.username),i.setCharacteristic(T.FirmwareRevision,e.firmwareRevision||A()),this.bridge.on(E.LISTENING,r=>{a.success("Homebridge v%s (HAP v%s) (%s) is running on port %s.",A(),Se(),e.name,r)});let t={username:e.username,port:e.port,pincode:e.pin,category:Ie.BRIDGE,bind:e.bind,addIdentifyingMaterial:!0,advertiser:e.advertiser};e.setupID&&e.setupID.length===4&&(t.setupID=e.setupID),a.debug("Publishing bridge accessory (name: %s, publishInfo: %o).",this.bridge.displayName,s.strippingPinCode(t)),this.bridge.publish(t,this.allowInsecureAccess)}async loadCachedPlatformAccessoriesFromDisk(){let e=null;try{e=await this.storageService.getItem(this.bridgeOptions.cachedAccessoriesItemName)}catch(i){a.error("Failed to load cached accessories from disk:",i.message),i instanceof SyntaxError?e=await this.restoreCachedAccessoriesBackup():a.error("Not restoring cached accessories - some accessories may be reset.")}e&&(a.info(`Loaded ${e.length} cached accessories from ${this.bridgeOptions.cachedAccessoriesItemName}.`),this.cachedPlatformAccessories=e.map(i=>m.deserialize(i)),e.length&&await this.createCachedAccessoriesBackup()),this.cachedAccessoriesFileLoaded=!0}get backupCacheFileName(){return`.${this.bridgeOptions.cachedAccessoriesItemName}.bak`}async createCachedAccessoriesBackup(){try{await this.storageService.copyItem(this.bridgeOptions.cachedAccessoriesItemName,this.backupCacheFileName)}catch(e){a.warn(`Failed to create a backup of the ${this.bridgeOptions.cachedAccessoriesItemName} cached accessories file:`,e.message)}}async restoreCachedAccessoriesBackup(){try{let e=await this.storageService.getItem(this.backupCacheFileName);return e&&e.length&&a.warn(`Recovered ${e.length} accessories from ${this.bridgeOptions.cachedAccessoriesItemName} cache backup.`),e}catch{return null}}restoreCachedPlatformAccessories(){this.cachedPlatformAccessories=this.cachedPlatformAccessories.filter(e=>{let i=this.pluginManager.getPlugin(e._associatedPlugin);if(!i)try{i=this.pluginManager.getPluginByActiveDynamicPlatform(e._associatedPlatform),i&&(a.info(`When searching for the associated plugin of the accessory '${e.displayName}' it seems like the plugin name changed from '${e._associatedPlugin}' to '${i.getPluginIdentifier()}'. Plugin association is now being transformed!`),e._associatedPlugin=i.getPluginIdentifier())}catch(r){a.info(`Could not find the associated plugin for the accessory '${e.displayName}'. Tried to find the plugin by the platform name but ${r.message}`)}let t=i&&i.getActiveDynamicPlatform(e._associatedPlatform);if(i&&e._associatedHAPAccessory.on(E.CHARACTERISTIC_WARNING,s.printCharacteristicWriteWarning.bind(this,i,e._associatedHAPAccessory,{})),t)e.getService($.AccessoryInformation)?.setCharacteristic(T.FirmwareRevision,"0"),t.configureAccessory(e);else if(a.info(`Failed to find plugin to handle accessory ${e._associatedHAPAccessory.displayName}`),!this.bridgeOptions.keepOrphanedCachedAccessories)return a.info(`Removing orphaned accessory ${e._associatedHAPAccessory.displayName}`),!1;try{this.bridge.addBridgedAccessory(e._associatedHAPAccessory)}catch(r){return a.warn(`${e._associatedPlugin?p(e._associatedPlugin):""} Could not restore cached accessory '${e._associatedHAPAccessory.displayName}':`,r.message),!1}return!0})}saveCachedPlatformAccessoriesOnDisk(){try{if(this.cachedAccessoriesFileLoaded){let e=this.cachedPlatformAccessories.map(i=>m.serialize(i));this.storageService.setItemSync(this.bridgeOptions.cachedAccessoriesItemName,e)}}catch(e){a.error("Failed to save cached accessories to disk:",e.message),a.error("Your accessories will not persist between restarts until this issue is resolved.")}}handleRegisterPlatformAccessories(e){let i=e.map(t=>{this.cachedPlatformAccessories.push(t);let r=this.pluginManager.getPlugin(t._associatedPlugin);return r?(r.getActiveDynamicPlatform(t._associatedPlatform)||a.warn("The plugin '%s' registered a new accessory for the platform '%s'. The platform couldn't be found though!",t._associatedPlugin,t._associatedPlatform),t._associatedHAPAccessory.on(E.CHARACTERISTIC_WARNING,s.printCharacteristicWriteWarning.bind(this,r,t._associatedHAPAccessory,{}))):a.warn("A platform configured a new accessory under the plugin name '%s'. However no loaded plugin could be found for the name!",t._associatedPlugin),t._associatedHAPAccessory});this.bridge.addBridgedAccessories(i),this.saveCachedPlatformAccessoriesOnDisk()}handleUpdatePlatformAccessories(){this.saveCachedPlatformAccessoriesOnDisk()}handleUnregisterPlatformAccessories(e){let i=e.map(t=>{let r=this.cachedPlatformAccessories.indexOf(t);return r>=0&&this.cachedPlatformAccessories.splice(r,1),t._associatedHAPAccessory});this.bridge.removeBridgedAccessories(i),this.saveCachedPlatformAccessoriesOnDisk()}async handlePublishExternalAccessories(e){let i=this.bridgeConfig.pin;for(let t of e){let r=t._associatedHAPAccessory,n=V(r.UUID),o=await this.externalPortService.requestPort(n);if(this.publishedExternalAccessories.has(n))throw new Error(`Accessory ${r.displayName} experienced an address collision.`);this.publishedExternalAccessories.set(n,t);let d=this.pluginManager.getPlugin(t._associatedPlugin);d?r.on(E.CHARACTERISTIC_WARNING,s.printCharacteristicWriteWarning.bind(this,d,r,{ignoreSlow:!0})):u.isQualifiedPluginIdentifier(t._associatedPlugin)&&a.warn("A platform configured a external accessory under the plugin name '%s'. However no loaded plugin could be found for the name!",t._associatedPlugin),r.on(E.LISTENING,h=>{a.success("%s is running on port %s.",r.displayName,h),a.info("Please add [%s] manually in Home app. Setup Code: %s",r.displayName,i)});let b={username:n,pincode:i,category:t.category,port:o,bind:this.bridgeConfig.bind,addIdentifyingMaterial:!0,advertiser:this.bridgeConfig.advertiser};a.debug("Publishing external accessory (name: %s, publishInfo: %o).",r.displayName,s.strippingPinCode(b)),r.publish(b,this.allowInsecureAccess)}}createHAPAccessory(e,i,t,r,n){let o=(i.getServices()||[]).filter(g=>!!g),d=(i.getControllers&&i.getControllers()||[]).filter(g=>!!g);if(o.length===0&&d.length===0)return;let b=Q.generate(`${r}:${n||t}`),h=new be(t,b);i.identify&&h.on(E.IDENTIFY,(g,_)=>{i.identify(()=>{}),_()});let O=h.getService($.AccessoryInformation);return o.forEach(g=>{g instanceof $.AccessoryInformation?(g.setCharacteristic(T.Name,t),g.getCharacteristic(T.Identify).removeAllListeners(Ee.SET),O.replaceCharacteristicsFromService(g)):h.addService(g)}),h.on(E.CHARACTERISTIC_WARNING,s.printCharacteristicWriteWarning.bind(this,e,h,{})),d.forEach(g=>{h.configureController(g)}),h}async loadPlatformAccessories(e,i,t,r){return new Promise(n=>{let o=setInterval(()=>{a.warn(p(e.getPluginIdentifier()),"This plugin is taking long time to load and preventing Homebridge from starting. See https://homebridge.io/w/JtMGR for more info.")},2e4);i.accessories(Re(d=>{clearInterval(o),d.forEach((b,h)=>{let O=b.name,g=b.uuid_base;a.info("Initializing platform accessory '%s'...",O);let _=this.createHAPAccessory(e,b,O,t,g);_?this.bridge.addBridgedAccessory(_):r("Platform %s returned an accessory at index %d with an empty set of services. Won't adding it to the bridge!",t,h)}),n()}))})}teardown(){this.bridge.unpublish();for(let e of this.publishedExternalAccessories.values())e._associatedHAPAccessory.unpublish();this.saveCachedPlatformAccessoriesOnDisk(),this.api.signalShutdown()}static strippingPinCode(e){let i={...e};return i.pincode="***-**-***",i}};import Mi,{dirname as we}from"node:path";import{fileURLToPath as xe}from"node:url";import Bi from"fs-extra";var Ne=xe(import.meta.url),ji=we(Ne);var F=class{constructor(e){this.externalPorts=e}nextExternalPort;allocatedPorts=new Map;async requestPort(e){let i=this.allocatedPorts.get(e);if(i)return i;let t=this.getNextFreePort();return this.allocatedPorts.set(e,t),t}getNextFreePort(){if(this.externalPorts){if(this.nextExternalPort===void 0)return this.nextExternalPort=this.externalPorts.start,this.nextExternalPort;if(this.nextExternalPort++,this.nextExternalPort<=this.externalPorts.end)return this.nextExternalPort;c.internal.warn("External port pool ran out of ports. Falling back to random port assignment.")}}},B=class extends F{constructor(i){super();this.childBridge=i}async requestPort(i){return await this.childBridge.requestExternalPort(i)}};y.title="homebridge: child bridge";var j=class{bridgeService;api;pluginManager;externalPortService;type;plugin;identifier;pluginConfig;bridgeConfig;bridgeOptions;homebridgeConfig;portRequestCallback=new Map;constructor(){this.sendMessage("ready")}sendMessage(e,i){y.send&&y.send({id:e,data:i})}async loadPlugin(e){this.type=e.type,this.identifier=e.identifier,this.pluginConfig=e.pluginConfig,this.bridgeConfig=e.bridgeConfig,this.bridgeOptions=e.bridgeOptions,this.homebridgeConfig=e.homebridgeConfig;for(let i of this.pluginConfig)delete i._bridge;this.bridgeOptions.noLogTimestamps&&c.setTimestampEnabled(!1),this.bridgeOptions.debugModeEnabled&&c.setDebugEnabled(!0),this.bridgeOptions.forceColourLogging&&c.forceColor(),this.bridgeOptions.customStoragePath&&I.setStoragePath(this.bridgeOptions.customStoragePath),De.setCustomStoragePath(I.persistPath()),this.api=new x,this.pluginManager=new u(this.api),this.externalPortService=new B(this),this.plugin=this.pluginManager.loadPlugin(e.pluginPath),await this.plugin.load(),await this.pluginManager.initializePlugin(this.plugin,e.identifier),y.title=`homebridge: ${this.plugin.getPluginIdentifier()}`,this.sendMessage("loaded",{version:this.plugin.version})}async startBridge(){this.bridgeService=new U(this.api,this.pluginManager,this.externalPortService,this.bridgeOptions,this.bridgeConfig,this.homebridgeConfig),this.bridgeService.bridge.on(G.ADVERTISED,()=>{this.sendPairedStatusEvent()}),this.bridgeService.bridge.on(G.PAIRED,()=>{this.sendPairedStatusEvent()}),this.bridgeService.bridge.on(G.UNPAIRED,()=>{this.sendPairedStatusEvent()}),await this.bridgeService.loadCachedPlatformAccessoriesFromDisk();for(let e of this.pluginConfig)if(this.type==="platform"){let i=this.pluginManager.getPluginForPlatform(this.identifier),t=e.name||i.getPluginIdentifier(),r=c.withPrefix(t),n=i.getPlatformConstructor(this.identifier),o=new n(r,e,this.api);x.isDynamicPlatformPlugin(o)?i.assignDynamicPlatform(this.identifier,o):x.isStaticPlatformPlugin(o)&&await this.bridgeService.loadPlatformAccessories(i,o,this.identifier,r)}else if(this.type==="accessory"){let i=this.pluginManager.getPluginForAccessory(this.identifier),t=e.name;if(!t){c.internal.warn("Could not load accessory %s as it is missing the required 'name' property!",this.identifier);return}let r=c.withPrefix(t),n=i.getAccessoryConstructor(this.identifier),o=new n(r,e,this.api),d=this.bridgeService.createHAPAccessory(i,o,t,this.identifier,e.uuid_base);d?this.bridgeService.bridge.addBridgedAccessory(d):r("Accessory %s returned empty set of services. Won't adding it to the bridge!",this.identifier)}this.bridgeService.restoreCachedPlatformAccessories(),this.bridgeService.publishBridge(),this.api.signalFinished(),this.sendMessage("online")}async requestExternalPort(e){return new Promise(i=>{let t=setTimeout(()=>{c.internal.warn("Parent process did not respond to port allocation request within 5 seconds - assigning random port."),i(void 0)},5e3),r=n=>{clearTimeout(t),i(n),this.portRequestCallback.delete(e)};this.portRequestCallback.set(e,r),this.sendMessage("portRequest",{username:e})})}handleExternalResponse(e){let i=this.portRequestCallback.get(e.username);i&&i(e.port)}sendPairedStatusEvent(){this.sendMessage("status",{paired:this.bridgeService?.bridge?._accessoryInfo?.paired()??null,setupUri:this.bridgeService?.bridge?.setupURI()??null})}shutdown(){this.bridgeService.teardown()}},H=new j;y.on("message",s=>{if(!(typeof s!="object"||!s.id))switch(s.id){case"load":{H.loadPlugin(s.data);break}case"start":{H.startBridge();break}case"portAllocated":{H.handleExternalResponse(s.data);break}}});var J=!1;function X(s,e){if(!J){J=!0,c.internal.info("Got %s, shutting down child bridge process...",s);try{H.shutdown()}catch{}setTimeout(()=>y.exit(128+e),5e3)}}y.on("SIGINT",X.bind(void 0,"SIGINT",2));y.on("SIGTERM",X.bind(void 0,"SIGTERM",15));setInterval(()=>{y.connected||(c.internal.info("Parent process not connected, terminating process..."),y.exit(1))},5e3);export{j as ChildBridgeFork};
2
- //# sourceMappingURL=childBridgeFork.js.map
1
+ /* global NodeJS */
2
+ import process from 'node:process';
3
+ import { HAPStorage } from 'hap-nodejs';
4
+ import { HomebridgeAPI } from './api.js';
5
+ import { BridgeService } from './bridgeService.js';
6
+ import { ChildBridgeExternalPortService } from './externalPortService.js';
7
+ import { Logger } from './logger.js';
8
+ import { PluginManager } from './pluginManager.js';
9
+ import { User } from './user.js';
10
+ import 'source-map-support/register.js';
11
+ /**
12
+ * This is a standalone script executed as a child process fork
13
+ */
14
+ process.title = 'homebridge: child bridge';
15
+ export class ChildBridgeFork {
16
+ bridgeService;
17
+ api;
18
+ pluginManager;
19
+ externalPortService;
20
+ type;
21
+ plugin;
22
+ identifier;
23
+ pluginConfig;
24
+ bridgeConfig;
25
+ bridgeOptions;
26
+ homebridgeConfig;
27
+ portRequestCallback = new Map();
28
+ constructor() {
29
+ // tell the parent process we are ready to accept plugin config
30
+ this.sendMessage("ready" /* ChildProcessMessageEventType.READY */);
31
+ }
32
+ sendMessage(type, data) {
33
+ if (process.send) {
34
+ process.send({
35
+ id: type,
36
+ data,
37
+ });
38
+ }
39
+ }
40
+ async loadPlugin(data) {
41
+ // set data
42
+ this.type = data.type;
43
+ this.identifier = data.identifier;
44
+ this.pluginConfig = data.pluginConfig;
45
+ this.bridgeConfig = data.bridgeConfig;
46
+ this.bridgeOptions = data.bridgeOptions;
47
+ this.homebridgeConfig = data.homebridgeConfig;
48
+ // remove the _bridge key (some plugins do not like unknown config)
49
+ for (const config of this.pluginConfig) {
50
+ delete config._bridge;
51
+ }
52
+ // set bridge settings (inherited from main bridge)
53
+ if (this.bridgeOptions.noLogTimestamps) {
54
+ Logger.setTimestampEnabled(false);
55
+ }
56
+ if (this.bridgeOptions.debugModeEnabled) {
57
+ Logger.setDebugEnabled(true);
58
+ }
59
+ if (this.bridgeOptions.forceColourLogging) {
60
+ Logger.forceColor();
61
+ }
62
+ if (this.bridgeOptions.customStoragePath) {
63
+ User.setStoragePath(this.bridgeOptions.customStoragePath);
64
+ }
65
+ // Initialize HAP-NodeJS with a custom persist directory
66
+ HAPStorage.setCustomStoragePath(User.persistPath());
67
+ // load api
68
+ this.api = new HomebridgeAPI();
69
+ this.pluginManager = new PluginManager(this.api);
70
+ this.externalPortService = new ChildBridgeExternalPortService(this);
71
+ // load plugin
72
+ this.plugin = this.pluginManager.loadPlugin(data.pluginPath);
73
+ await this.plugin.load();
74
+ await this.pluginManager.initializePlugin(this.plugin, data.identifier);
75
+ // change process title to include plugin name
76
+ process.title = `homebridge: ${this.plugin.getPluginIdentifier()}`;
77
+ this.sendMessage("loaded" /* ChildProcessMessageEventType.LOADED */, {
78
+ version: this.plugin.version,
79
+ });
80
+ }
81
+ async startBridge() {
82
+ this.bridgeService = new BridgeService(this.api, this.pluginManager, this.externalPortService, this.bridgeOptions, this.bridgeConfig, this.homebridgeConfig);
83
+ // watch bridge events to check when server is online
84
+ this.bridgeService.bridge.on("advertised" /* AccessoryEventTypes.ADVERTISED */, () => {
85
+ this.sendPairedStatusEvent();
86
+ });
87
+ // watch for the paired event to update the server status
88
+ this.bridgeService.bridge.on("paired" /* AccessoryEventTypes.PAIRED */, () => {
89
+ this.sendPairedStatusEvent();
90
+ });
91
+ // watch for the unpaired event to update the server status
92
+ this.bridgeService.bridge.on("unpaired" /* AccessoryEventTypes.UNPAIRED */, () => {
93
+ this.sendPairedStatusEvent();
94
+ });
95
+ // load the cached accessories
96
+ await this.bridgeService.loadCachedPlatformAccessoriesFromDisk();
97
+ for (const config of this.pluginConfig) {
98
+ if (this.type === "platform" /* PluginType.PLATFORM */) {
99
+ const plugin = this.pluginManager.getPluginForPlatform(this.identifier);
100
+ const displayName = config.name || plugin.getPluginIdentifier();
101
+ const logger = Logger.withPrefix(displayName);
102
+ const constructor = plugin.getPlatformConstructor(this.identifier);
103
+ const platform = new constructor(logger, config, this.api);
104
+ if (HomebridgeAPI.isDynamicPlatformPlugin(platform)) {
105
+ plugin.assignDynamicPlatform(this.identifier, platform);
106
+ }
107
+ else if (HomebridgeAPI.isStaticPlatformPlugin(platform)) { // Plugin 1.0, load accessories
108
+ await this.bridgeService.loadPlatformAccessories(plugin, platform, this.identifier, logger);
109
+ }
110
+ else {
111
+ // otherwise it's a IndependentPlatformPlugin which doesn't expose any methods at all.
112
+ // We just call the constructor and let it be enabled.
113
+ }
114
+ }
115
+ else if (this.type === "accessory" /* PluginType.ACCESSORY */) {
116
+ const plugin = this.pluginManager.getPluginForAccessory(this.identifier);
117
+ const displayName = config.name;
118
+ if (!displayName) {
119
+ Logger.internal.warn('Could not load accessory %s as it is missing the required \'name\' property!', this.identifier);
120
+ return;
121
+ }
122
+ const logger = Logger.withPrefix(displayName);
123
+ const constructor = plugin.getAccessoryConstructor(this.identifier);
124
+ const accessoryInstance = new constructor(logger, config, this.api);
125
+ // pass accessoryIdentifier for UUID generation, and optional parameter uuid_base which can be used instead of displayName for UUID generation
126
+ const accessory = this.bridgeService.createHAPAccessory(plugin, accessoryInstance, displayName, this.identifier, config.uuid_base);
127
+ if (accessory) {
128
+ this.bridgeService.bridge.addBridgedAccessory(accessory);
129
+ }
130
+ else {
131
+ logger('Accessory %s returned empty set of services. Won\'t adding it to the bridge!', this.identifier);
132
+ }
133
+ }
134
+ }
135
+ // restore the cached accessories
136
+ this.bridgeService.restoreCachedPlatformAccessories();
137
+ this.bridgeService.publishBridge();
138
+ this.api.signalFinished();
139
+ // tell the parent we are online
140
+ this.sendMessage("online" /* ChildProcessMessageEventType.ONLINE */);
141
+ }
142
+ /**
143
+ * Request the next available external port from the parent process
144
+ * @param username
145
+ */
146
+ async requestExternalPort(username) {
147
+ return new Promise((resolve) => {
148
+ const requestTimeout = setTimeout(() => {
149
+ Logger.internal.warn('Parent process did not respond to port allocation request within 5 seconds - assigning random port.');
150
+ resolve(undefined);
151
+ }, 5000);
152
+ // setup callback
153
+ const callback = (port) => {
154
+ clearTimeout(requestTimeout);
155
+ resolve(port);
156
+ this.portRequestCallback.delete(username);
157
+ };
158
+ this.portRequestCallback.set(username, callback);
159
+ // send port request
160
+ this.sendMessage("portRequest" /* ChildProcessMessageEventType.PORT_REQUEST */, { username });
161
+ });
162
+ }
163
+ /**
164
+ * Handles the port allocation response message from the parent process
165
+ * @param data
166
+ */
167
+ handleExternalResponse(data) {
168
+ const callback = this.portRequestCallback.get(data.username);
169
+ if (callback) {
170
+ callback(data.port);
171
+ }
172
+ }
173
+ /**
174
+ * Sends the current pairing status of the child bridge to the parent process
175
+ */
176
+ sendPairedStatusEvent() {
177
+ this.sendMessage("status" /* ChildProcessMessageEventType.STATUS_UPDATE */, {
178
+ paired: this.bridgeService?.bridge?._accessoryInfo?.paired() ?? null,
179
+ setupUri: this.bridgeService?.bridge?.setupURI() ?? null,
180
+ });
181
+ }
182
+ shutdown() {
183
+ this.bridgeService.teardown();
184
+ }
185
+ }
186
+ /**
187
+ * Start Self
188
+ */
189
+ const childPluginFork = new ChildBridgeFork();
190
+ /**
191
+ * Handle incoming IPC messages from the parent Homebridge process
192
+ */
193
+ process.on('message', (message) => {
194
+ if (typeof message !== 'object' || !message.id) {
195
+ return;
196
+ }
197
+ switch (message.id) {
198
+ case "load" /* ChildProcessMessageEventType.LOAD */: {
199
+ childPluginFork.loadPlugin(message.data);
200
+ break;
201
+ }
202
+ case "start" /* ChildProcessMessageEventType.START */: {
203
+ childPluginFork.startBridge();
204
+ break;
205
+ }
206
+ case "portAllocated" /* ChildProcessMessageEventType.PORT_ALLOCATED */: {
207
+ childPluginFork.handleExternalResponse(message.data);
208
+ break;
209
+ }
210
+ }
211
+ });
212
+ /**
213
+ * Handle the sigterm shutdown signals
214
+ */
215
+ let shuttingDown = false;
216
+ function signalHandler(signal, signalNum) {
217
+ if (shuttingDown) {
218
+ return;
219
+ }
220
+ shuttingDown = true;
221
+ Logger.internal.info('Got %s, shutting down child bridge process...', signal);
222
+ try {
223
+ childPluginFork.shutdown();
224
+ }
225
+ catch (error) {
226
+ // do nothing
227
+ }
228
+ setTimeout(() => process.exit(128 + signalNum), 5000);
229
+ }
230
+ process.on('SIGINT', signalHandler.bind(undefined, 'SIGINT', 2));
231
+ process.on('SIGTERM', signalHandler.bind(undefined, 'SIGTERM', 15));
232
+ /**
233
+ * Ensure orphaned processes are cleaned up
234
+ */
235
+ setInterval(() => {
236
+ if (!process.connected) {
237
+ Logger.internal.info('Parent process not connected, terminating process...');
238
+ process.exit(1);
239
+ }
240
+ }, 5000);
241
+ //# sourceMappingURL=childBridgeFork.js.map