@things-factory/integration-base 9.0.0-beta.68 → 9.0.0-beta.69

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.
@@ -86,21 +86,16 @@ async function MqttSubscribe(step, context) {
86
86
  const { connection: connectionName, params: { topic, dataFormat }, name: stepName } = step;
87
87
  const { domain, logger, closures } = context;
88
88
  // MQTT 브로커 접속 정보 가져오기
89
- const { connection: { endpoint: uri, params: { user, password } } } = connection_manager_js_1.ConnectionManager.getConnectionInstanceByName(domain, connectionName);
89
+ const connectionInstance = connection_manager_js_1.ConnectionManager.getConnectionInstanceByName(domain, connectionName);
90
+ const { client } = connectionInstance;
90
91
  if (!topic) {
91
92
  throw Error(`토픽이 지정되지 않음: ${connectionName}`);
92
93
  }
93
- // 브로커 연결 키 생성
94
- const connectionOptions = user && password ? { username: user, password } : undefined;
95
- const brokerKey = MqttBrokerManager.getBrokerKey(uri, connectionOptions);
96
94
  // 구독자 ID 생성 (도메인, 연결명, 토픽, 스텝명 조합)
97
95
  const subscriberId = `${domain}_${connectionName}_${topic}_${stepName}`;
98
96
  try {
99
- // 브로커 연결 (또는 기존 연결 가져오기)
100
- await MqttBrokerManager.getBroker(uri, connectionOptions);
101
- logger.info(`MQTT 연결 완료: ${connectionName}:${uri}`);
102
97
  // 토픽 구독 등록
103
- await MqttBrokerManager.subscribe(brokerKey, topic);
98
+ await MqttBrokerManager.subscribe(client, topic);
104
99
  logger.info(`토픽 구독 완료: ${topic}`);
105
100
  // 리졸버 저장소 초기화
106
101
  if (!context.__mqtt_resolvers) {
@@ -114,8 +109,8 @@ async function MqttSubscribe(step, context) {
114
109
  context.__mqtt_handlers = new Map();
115
110
  }
116
111
  // 연결 추적 (중복 종료 방지)
117
- if (!context.__mqtt_connections.has(brokerKey)) {
118
- context.__mqtt_connections.add(brokerKey);
112
+ if (!context.__mqtt_connections.has(connectionName)) {
113
+ context.__mqtt_connections.add(connectionName);
119
114
  // 연결 종료 함수 등록
120
115
  closures.push(async () => {
121
116
  try {
@@ -134,7 +129,7 @@ async function MqttSubscribe(step, context) {
134
129
  context.__mqtt_resolvers.clear();
135
130
  }
136
131
  // 브로커 연결 종료는 하지 않음
137
- logger.info(`MQTT 구독자 종료: ${connectionName}:${uri}`);
132
+ logger.info(`MQTT 구독자 종료: ${connectionName}`);
138
133
  }
139
134
  catch (e) {
140
135
  logger.error(`MQTT 구독자 종료 오류: ${e.message}`);
@@ -156,7 +151,7 @@ async function MqttSubscribe(step, context) {
156
151
  }
157
152
  }
158
153
  // 새로운 메시지 핸들러 등록
159
- const removeHandler = MqttBrokerManager.registerMessageHandler(brokerKey, topic, subscriberId, (messageTopic, message) => {
154
+ const removeHandler = MqttBrokerManager.registerMessageHandler(client, topic, subscriberId, (messageTopic, message) => {
160
155
  var _a, _b;
161
156
  try {
162
157
  // 메시지 변환
@@ -1 +1 @@
1
- {"version":3,"file":"mqtt-subscribe.js","sourceRoot":"","sources":["../../../server/engine/task/mqtt-subscribe.ts"],"names":[],"mappings":"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","sourcesContent":["import mqtt from 'async-mqtt'\n\nimport { TaskRegistry } from '../task-registry.js'\nimport { ConnectionManager } from '../connection-manager.js'\nimport { InputStep } from '../../service/step/step-type.js'\nimport { Context } from '../types.js'\n\nfunction convertDataFormat(data, format) {\n if (format == 'json') {\n try {\n return JSON.parse(data)\n } catch (e) {\n console.error('JSON 파싱 오류:', e.message)\n return data.toString()\n }\n } else {\n return data.toString()\n }\n}\n\n// MQTT 연결을 위한 브로커 관리 클래스\nclass MqttBrokerManager {\n private static brokers: Record<\n string,\n {\n client: mqtt.AsyncMqttClient\n topics: Set<string>\n messageHandlers: Map<string, (topic: string, message: Buffer) => void>\n }\n > = {}\n\n // 브로커 연결 (또는 기존 연결 반환)\n static async getBroker(uri: string, options?: mqtt.IClientOptions) {\n const brokerKey = `${uri}_${JSON.stringify(options || {})}`\n\n if (!this.brokers[brokerKey]) {\n const client = await mqtt.connectAsync(uri, options)\n\n this.brokers[brokerKey] = {\n client,\n topics: new Set<string>(),\n messageHandlers: new Map()\n }\n\n // 메시지 수신 핸들러\n client.on('message', (topic, message) => {\n // 해당 토픽에 등록된 핸들러가 있으면 호출\n this.brokers[brokerKey].messageHandlers.forEach((handler, handlerId) => {\n if (handlerId.startsWith(`${topic}:`)) {\n handler(topic, message)\n }\n })\n })\n }\n\n return this.brokers[brokerKey]\n }\n\n // 토픽 구독 등록\n static async subscribe(brokerKey: string, topic: string) {\n const broker = this.brokers[brokerKey]\n if (!broker) {\n throw new Error(`브로커가 연결되지 않음: ${brokerKey}`)\n }\n\n // 새 토픽인 경우 구독\n if (!broker.topics.has(topic)) {\n await broker.client.subscribe(topic)\n broker.topics.add(topic)\n }\n }\n\n // 메시지 핸들러 등록\n static registerMessageHandler(\n brokerKey: string,\n topic: string,\n handlerId: string,\n handler: (topic: string, message: Buffer) => void\n ) {\n const broker = this.brokers[brokerKey]\n if (!broker) {\n throw new Error(`브로커가 연결되지 않음: ${brokerKey}`)\n }\n\n // 핸들러 ID는 topic:handlerId 형식으로 저장\n const fullHandlerId = `${topic}:${handlerId}`\n broker.messageHandlers.set(fullHandlerId, handler)\n\n return () => {\n // 핸들러 제거 함수 반환\n broker.messageHandlers.delete(fullHandlerId)\n }\n }\n\n // 연결 종료\n static async disconnect(brokerKey: string) {\n const broker = this.brokers[brokerKey]\n if (broker) {\n await broker.client.end()\n delete this.brokers[brokerKey]\n }\n }\n\n // 브로커 키 생성 유틸리티\n static getBrokerKey(uri: string, options?: any) {\n return `${uri}_${JSON.stringify(options || {})}`\n }\n}\n\ninterface MqttContext extends Context {\n __mqtt_connections?: Set<string>\n __mqtt_handlers?: Map<string, () => void>\n __mqtt_resolvers?: Map<string, (result: any) => void>\n}\n\nasync function MqttSubscribe(step: InputStep, context: MqttContext) {\n const {\n connection: connectionName,\n params: { topic, dataFormat },\n name: stepName\n } = step\n\n const { domain, logger, closures } = context\n\n // MQTT 브로커 접속 정보 가져오기\n const {\n connection: {\n endpoint: uri,\n params: { user, password }\n }\n } = ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n\n if (!topic) {\n throw Error(`토픽이 지정되지 않음: ${connectionName}`)\n }\n\n // 브로커 연결 키 생성\n const connectionOptions = user && password ? { username: user, password } : undefined\n const brokerKey = MqttBrokerManager.getBrokerKey(uri, connectionOptions)\n\n // 구독자 ID 생성 (도메인, 연결명, 토픽, 스텝명 조합)\n const subscriberId = `${domain}_${connectionName}_${topic}_${stepName}`\n\n try {\n // 브로커 연결 (또는 기존 연결 가져오기)\n await MqttBrokerManager.getBroker(uri, connectionOptions)\n logger.info(`MQTT 연결 완료: ${connectionName}:${uri}`)\n\n // 토픽 구독 등록\n await MqttBrokerManager.subscribe(brokerKey, topic)\n logger.info(`토픽 구독 완료: ${topic}`)\n\n // 리졸버 저장소 초기화\n if (!context.__mqtt_resolvers) {\n context.__mqtt_resolvers = new Map()\n }\n\n // 클로저에 연결 종료 함수 등록\n if (!context.__mqtt_connections) {\n context.__mqtt_connections = new Set()\n }\n\n if (!context.__mqtt_handlers) {\n context.__mqtt_handlers = new Map()\n }\n\n // 연결 추적 (중복 종료 방지)\n if (!context.__mqtt_connections.has(brokerKey)) {\n context.__mqtt_connections.add(brokerKey)\n\n // 연결 종료 함수 등록\n closures.push(async () => {\n try {\n // 핸들러 모두 제거\n if (context.__mqtt_handlers) {\n context.__mqtt_handlers.forEach(removeHandler => {\n removeHandler()\n })\n context.__mqtt_handlers.clear()\n }\n\n // 대기 중인 모든 Promise 해결\n if (context.__mqtt_resolvers) {\n context.__mqtt_resolvers.forEach(resolver => {\n resolver({ data: null, terminated: true })\n })\n context.__mqtt_resolvers.clear()\n }\n\n // 브로커 연결 종료는 하지 않음\n logger.info(`MQTT 구독자 종료: ${connectionName}:${uri}`)\n } catch (e) {\n logger.error(`MQTT 구독자 종료 오류: ${e.message}`)\n }\n })\n }\n\n // Promise로 메시지 수신 대기\n return new Promise(resolve => {\n // 이 태스크의 resolver 저장\n if (context.__mqtt_resolvers) {\n context.__mqtt_resolvers.set(subscriberId, resolve)\n }\n\n // 이미 등록된 핸들러가 있으면 제거\n if (context.__mqtt_handlers?.has(subscriberId)) {\n const removeHandler = context.__mqtt_handlers.get(subscriberId)\n if (removeHandler) {\n removeHandler()\n }\n }\n\n // 새로운 메시지 핸들러 등록\n const removeHandler = MqttBrokerManager.registerMessageHandler(\n brokerKey,\n topic,\n subscriberId,\n (messageTopic, message) => {\n try {\n // 메시지 변환\n const convertedMessage = convertDataFormat(message, dataFormat)\n\n // resolver 가져오기 및 삭제\n if (context.__mqtt_resolvers?.has(subscriberId)) {\n const resolver = context.__mqtt_resolvers.get(subscriberId)\n context.__mqtt_resolvers.delete(subscriberId)\n\n // 이 태스크에 대한 핸들러 제거 (한 번만 실행되도록)\n if (context.__mqtt_handlers?.has(subscriberId)) {\n const removeHandler = context.__mqtt_handlers.get(subscriberId)\n if (removeHandler) {\n removeHandler()\n }\n context.__mqtt_handlers.delete(subscriberId)\n }\n\n // Promise 해결\n if (resolver) {\n resolver({\n data: convertedMessage\n })\n }\n }\n } catch (error) {\n logger.error(`메시지 처리 오류: ${error.message}`)\n }\n }\n )\n\n // 핸들러 제거 함수 저장\n if (context.__mqtt_handlers) {\n context.__mqtt_handlers.set(subscriberId, removeHandler)\n }\n\n logger.info(`MQTT 메시지 대기 중: ${topic}`)\n })\n } catch (e) {\n logger.error(`MQTT 구독 오류: ${e.message}`)\n throw e\n }\n}\n\nMqttSubscribe.parameterSpec = [\n {\n type: 'string',\n name: 'topic',\n label: 'topic'\n },\n {\n type: 'select',\n label: 'data-format',\n name: 'dataFormat',\n property: {\n options: [\n {\n display: 'Plain Text',\n value: 'text'\n },\n {\n display: 'JSON',\n value: 'json'\n }\n ]\n }\n }\n]\n\nMqttSubscribe.help = 'integration/task/mqtt-subscribe'\n\nTaskRegistry.registerTaskHandler('mqtt-subscribe', MqttSubscribe)\n"]}
1
+ {"version":3,"file":"mqtt-subscribe.js","sourceRoot":"","sources":["../../../server/engine/task/mqtt-subscribe.ts"],"names":[],"mappings":"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","sourcesContent":["import mqtt from 'async-mqtt'\n\nimport { TaskRegistry } from '../task-registry.js'\nimport { ConnectionManager } from '../connection-manager.js'\nimport { InputStep } from '../../service/step/step-type.js'\nimport { Context } from '../types.js'\n\nfunction convertDataFormat(data, format) {\n if (format == 'json') {\n try {\n return JSON.parse(data)\n } catch (e) {\n console.error('JSON 파싱 오류:', e.message)\n return data.toString()\n }\n } else {\n return data.toString()\n }\n}\n\n// MQTT 연결을 위한 브로커 관리 클래스\nclass MqttBrokerManager {\n private static brokers: Record<\n string,\n {\n client: mqtt.AsyncMqttClient\n topics: Set<string>\n messageHandlers: Map<string, (topic: string, message: Buffer) => void>\n }\n > = {}\n\n // 브로커 연결 (또는 기존 연결 반환)\n static async getBroker(uri: string, options?: mqtt.IClientOptions) {\n const brokerKey = `${uri}_${JSON.stringify(options || {})}`\n\n if (!this.brokers[brokerKey]) {\n const client = await mqtt.connectAsync(uri, options)\n\n this.brokers[brokerKey] = {\n client,\n topics: new Set<string>(),\n messageHandlers: new Map()\n }\n\n // 메시지 수신 핸들러\n client.on('message', (topic, message) => {\n // 해당 토픽에 등록된 핸들러가 있으면 호출\n this.brokers[brokerKey].messageHandlers.forEach((handler, handlerId) => {\n if (handlerId.startsWith(`${topic}:`)) {\n handler(topic, message)\n }\n })\n })\n }\n\n return this.brokers[brokerKey]\n }\n\n // 토픽 구독 등록\n static async subscribe(brokerKey: string, topic: string) {\n const broker = this.brokers[brokerKey]\n if (!broker) {\n throw new Error(`브로커가 연결되지 않음: ${brokerKey}`)\n }\n\n // 새 토픽인 경우 구독\n if (!broker.topics.has(topic)) {\n await broker.client.subscribe(topic)\n broker.topics.add(topic)\n }\n }\n\n // 메시지 핸들러 등록\n static registerMessageHandler(\n brokerKey: string,\n topic: string,\n handlerId: string,\n handler: (topic: string, message: Buffer) => void\n ) {\n const broker = this.brokers[brokerKey]\n if (!broker) {\n throw new Error(`브로커가 연결되지 않음: ${brokerKey}`)\n }\n\n // 핸들러 ID는 topic:handlerId 형식으로 저장\n const fullHandlerId = `${topic}:${handlerId}`\n broker.messageHandlers.set(fullHandlerId, handler)\n\n return () => {\n // 핸들러 제거 함수 반환\n broker.messageHandlers.delete(fullHandlerId)\n }\n }\n\n // 연결 종료\n static async disconnect(brokerKey: string) {\n const broker = this.brokers[brokerKey]\n if (broker) {\n await broker.client.end()\n delete this.brokers[brokerKey]\n }\n }\n\n // 브로커 키 생성 유틸리티\n static getBrokerKey(uri: string, options?: any) {\n return `${uri}_${JSON.stringify(options || {})}`\n }\n}\n\ninterface MqttContext extends Context {\n __mqtt_connections?: Set<string>\n __mqtt_handlers?: Map<string, () => void>\n __mqtt_resolvers?: Map<string, (result: any) => void>\n}\n\nasync function MqttSubscribe(step: InputStep, context: MqttContext) {\n const {\n connection: connectionName,\n params: { topic, dataFormat },\n name: stepName\n } = step\n\n const { domain, logger, closures } = context\n\n // MQTT 브로커 접속 정보 가져오기\n const connectionInstance = ConnectionManager.getConnectionInstanceByName(domain, connectionName)\n const { client } = connectionInstance\n\n if (!topic) {\n throw Error(`토픽이 지정되지 않음: ${connectionName}`)\n }\n\n // 구독자 ID 생성 (도메인, 연결명, 토픽, 스텝명 조합)\n const subscriberId = `${domain}_${connectionName}_${topic}_${stepName}`\n\n try {\n // 토픽 구독 등록\n await MqttBrokerManager.subscribe(client, topic)\n logger.info(`토픽 구독 완료: ${topic}`)\n\n // 리졸버 저장소 초기화\n if (!context.__mqtt_resolvers) {\n context.__mqtt_resolvers = new Map()\n }\n\n // 클로저에 연결 종료 함수 등록\n if (!context.__mqtt_connections) {\n context.__mqtt_connections = new Set()\n }\n\n if (!context.__mqtt_handlers) {\n context.__mqtt_handlers = new Map()\n }\n\n // 연결 추적 (중복 종료 방지)\n if (!context.__mqtt_connections.has(connectionName)) {\n context.__mqtt_connections.add(connectionName)\n\n // 연결 종료 함수 등록\n closures.push(async () => {\n try {\n // 핸들러 모두 제거\n if (context.__mqtt_handlers) {\n context.__mqtt_handlers.forEach(removeHandler => {\n removeHandler()\n })\n context.__mqtt_handlers.clear()\n }\n\n // 대기 중인 모든 Promise 해결\n if (context.__mqtt_resolvers) {\n context.__mqtt_resolvers.forEach(resolver => {\n resolver({ data: null, terminated: true })\n })\n context.__mqtt_resolvers.clear()\n }\n\n // 브로커 연결 종료는 하지 않음\n logger.info(`MQTT 구독자 종료: ${connectionName}`)\n } catch (e) {\n logger.error(`MQTT 구독자 종료 오류: ${e.message}`)\n }\n })\n }\n\n // Promise로 메시지 수신 대기\n return new Promise(resolve => {\n // 이 태스크의 resolver 저장\n if (context.__mqtt_resolvers) {\n context.__mqtt_resolvers.set(subscriberId, resolve)\n }\n\n // 이미 등록된 핸들러가 있으면 제거\n if (context.__mqtt_handlers?.has(subscriberId)) {\n const removeHandler = context.__mqtt_handlers.get(subscriberId)\n if (removeHandler) {\n removeHandler()\n }\n }\n\n // 새로운 메시지 핸들러 등록\n const removeHandler = MqttBrokerManager.registerMessageHandler(\n client,\n topic,\n subscriberId,\n (messageTopic, message) => {\n try {\n // 메시지 변환\n const convertedMessage = convertDataFormat(message, dataFormat)\n\n // resolver 가져오기 및 삭제\n if (context.__mqtt_resolvers?.has(subscriberId)) {\n const resolver = context.__mqtt_resolvers.get(subscriberId)\n context.__mqtt_resolvers.delete(subscriberId)\n\n // 이 태스크에 대한 핸들러 제거 (한 번만 실행되도록)\n if (context.__mqtt_handlers?.has(subscriberId)) {\n const removeHandler = context.__mqtt_handlers.get(subscriberId)\n if (removeHandler) {\n removeHandler()\n }\n context.__mqtt_handlers.delete(subscriberId)\n }\n\n // Promise 해결\n if (resolver) {\n resolver({\n data: convertedMessage\n })\n }\n }\n } catch (error) {\n logger.error(`메시지 처리 오류: ${error.message}`)\n }\n }\n )\n\n // 핸들러 제거 함수 저장\n if (context.__mqtt_handlers) {\n context.__mqtt_handlers.set(subscriberId, removeHandler)\n }\n\n logger.info(`MQTT 메시지 대기 중: ${topic}`)\n })\n } catch (e) {\n logger.error(`MQTT 구독 오류: ${e.message}`)\n throw e\n }\n}\n\nMqttSubscribe.parameterSpec = [\n {\n type: 'string',\n name: 'topic',\n label: 'topic'\n },\n {\n type: 'select',\n label: 'data-format',\n name: 'dataFormat',\n property: {\n options: [\n {\n display: 'Plain Text',\n value: 'text'\n },\n {\n display: 'JSON',\n value: 'json'\n }\n ]\n }\n }\n]\n\nMqttSubscribe.help = 'integration/task/mqtt-subscribe'\n\nTaskRegistry.registerTaskHandler('mqtt-subscribe', MqttSubscribe)\n"]}