@tier0/node-red-contrib-opcda-client 1.0.3 → 1.0.5
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.
- package/opcda/opcda-read.html +1 -1
- package/opcda/opcda-read.js +21 -50
- package/opcda/opcda-server.html +11 -20
- package/opcda/opcda-server.js +28 -42
- package/opcda/opcda-write.html +1 -1
- package/opcda/opcda-write.js +17 -20
- package/package.json +4 -4
- package/OPCDA_Bridge_Setup_Guide.md +0 -132
- package/docker-compose.yml +0 -460
- package/opctest.py +0 -214
- package/patch-debug.js +0 -13
- package/patch-ntlm.js +0 -46
- package/patch-pwdcheck.js +0 -17
- package/test-connect.js +0 -69
- package/test-connect2.js +0 -30
- package/test-direct.js +0 -53
- package/test-ntlm-vectors.js +0 -100
- package/test-ntlm-verify.js +0 -77
- package/uns_import.json +0 -204
package/docker-compose.yml
DELETED
|
@@ -1,460 +0,0 @@
|
|
|
1
|
-
networks:
|
|
2
|
-
edge_network:
|
|
3
|
-
driver: bridge
|
|
4
|
-
|
|
5
|
-
services:
|
|
6
|
-
frontend:
|
|
7
|
-
image: tier0/tier0-frontend:1.0.1-R8
|
|
8
|
-
container_name: frontend
|
|
9
|
-
ports:
|
|
10
|
-
- "3010:3000"
|
|
11
|
-
- "4000:4000"
|
|
12
|
-
environment:
|
|
13
|
-
- LLM_MODEL=${LLM_MODEL}
|
|
14
|
-
- LLM_API_KEY=${LLM_API_KEY}
|
|
15
|
-
- LLM_TYPE=${LLM_TYPE}
|
|
16
|
-
- REACT_APP_OS_LANG=${LANGUAGE}
|
|
17
|
-
- TOKEN_MAX_AGE=${TOKEN_MAX_AGE}
|
|
18
|
-
- TZ=UTC
|
|
19
|
-
command: >
|
|
20
|
-
sh -c "
|
|
21
|
-
if [ -z \"$LLM_API_KEY\" ]; then
|
|
22
|
-
echo 'LLM_API_KEY为空,跳过Node.js服务启动'
|
|
23
|
-
concurrently \"serve -s /app/web-dist -l 3000\"
|
|
24
|
-
else
|
|
25
|
-
echo 'LLM_API_KEY已配置,启动所有服务'
|
|
26
|
-
concurrently \"serve -s /app/web-dist -l 3000\" \"node /app/services-express-dist/index.js\"
|
|
27
|
-
fi
|
|
28
|
-
"
|
|
29
|
-
volumes:
|
|
30
|
-
- /etc/docker/certs:/certs
|
|
31
|
-
networks:
|
|
32
|
-
- edge_network
|
|
33
|
-
restart: always
|
|
34
|
-
uns:
|
|
35
|
-
image: tier0/tier0-backend:1.0.1-R8
|
|
36
|
-
container_name: uns
|
|
37
|
-
environment:
|
|
38
|
-
- LLM_MODEL=${LLM_MODEL}
|
|
39
|
-
- LLM_API_KEY=${LLM_API_KEY}
|
|
40
|
-
- LLM_TYPE=${LLM_TYPE}
|
|
41
|
-
- REACT_APP_OS_LANG=${LANGUAGE}
|
|
42
|
-
- OAUTH_REDIRECT_URI=${BASE_URL}/inter-api/supos/auth/token
|
|
43
|
-
- OAUTH_SUPOS_HOME=${BASE_URL}/uns
|
|
44
|
-
- OAUTH_REALM=${OAUTH_REALM}
|
|
45
|
-
- OAUTH_CLIENT_NAME=${OAUTH_CLIENT_NAME}
|
|
46
|
-
- OAUTH_CLIENT_ID=${OAUTH_CLIENT_ID}
|
|
47
|
-
- OAUTH_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}
|
|
48
|
-
- OAUTH_GRANT_TYPE=${OAUTH_GRANT_TYPE}
|
|
49
|
-
- OAUTH_ISSUER_URI=${OAUTH_ISSUER_URI}
|
|
50
|
-
- OAUTH_REFRESH_TOKEN_TIME=${OAUTH_REFRESH_TOKEN_TIME}
|
|
51
|
-
- SYS_OS_APP_TITLE=${OS_NAME}
|
|
52
|
-
- SYS_OS_LOGIN_PATH=${OS_LOGIN_PATH}
|
|
53
|
-
- SYS_OS_LANG=${LANGUAGE}
|
|
54
|
-
- TOKEN_MAX_AGE=${TOKEN_MAX_AGE}
|
|
55
|
-
- TZ=UTC
|
|
56
|
-
- GRPC_POOL_CORE_SIZE=2
|
|
57
|
-
- GRPC_POOL_MAX_SIZE=4
|
|
58
|
-
- dbDSN=${UNS_DB_URL}
|
|
59
|
-
- SINK_PG_URL=${SINK_PG_URL}
|
|
60
|
-
- SINK_TSDB_URL=${SINK_TSDB_URL}
|
|
61
|
-
- NODE_RED_HOST=nodered
|
|
62
|
-
- NODE_RED_PORT=1880
|
|
63
|
-
- SYS_OS_MULTIPLE_TOPIC=false
|
|
64
|
-
- SYS_OS_VERSION=${OS_VERSION}
|
|
65
|
-
- SYS_OS_AUTH_ENABLE=${OS_AUTH_ENABLE}
|
|
66
|
-
- SYS_OS_LLM_TYPE=${OS_LLM_TYPE}
|
|
67
|
-
- SYS_OS_MQTT_TCP_PORT=${OS_MQTT_TCP_PORT}
|
|
68
|
-
- SYS_OS_MQTT_WEBSOCKET_TSL_PORT=${OS_MQTT_WEBSOCKET_TSL_PORT}
|
|
69
|
-
- SYS_OS_PLATFORM_TYPE=${OS_PLATFORM_TYPE}
|
|
70
|
-
- SYS_OS_ENTRANCE_URL=${BASE_URL}
|
|
71
|
-
- SYS_OS_QUALITY_NAME=quality
|
|
72
|
-
- SYS_OS_TIMESTAMP_NAME=timeStamp
|
|
73
|
-
- SYS_OS_LAZY_TREE=${LAZY_TREE}
|
|
74
|
-
- UNS_ADD_BATCH_SIZE=1000
|
|
75
|
-
volumes:
|
|
76
|
-
- ${VOLUMES_PATH}/edge/system/:/app/go-edge/system/
|
|
77
|
-
- ${VOLUMES_PATH}/edge/attachment/:/app/go-edge/attachment/
|
|
78
|
-
- ${VOLUMES_PATH}/edge/apps/:/app/data/apps/
|
|
79
|
-
- /etc/docker/certs:/certs
|
|
80
|
-
ports:
|
|
81
|
-
- "18998:8080"
|
|
82
|
-
networks:
|
|
83
|
-
- edge_network
|
|
84
|
-
depends_on:
|
|
85
|
-
postgresql:
|
|
86
|
-
condition: service_healthy
|
|
87
|
-
restart: always
|
|
88
|
-
extra_hosts:
|
|
89
|
-
- "host.docker.internal:host-gateway"
|
|
90
|
-
marimo:
|
|
91
|
-
image: suposce/marimo:latest
|
|
92
|
-
container_name: marimo
|
|
93
|
-
environment:
|
|
94
|
-
- TSDB_URL=postgresql+psycopg2://postgres:${TSDB_PASSWORD}@tsdb:5432/postgres
|
|
95
|
-
- PG_URL=postgresql+psycopg2://postgres:${POSTGRES_PASSWORD}@postgresql:5432/postgres
|
|
96
|
-
volumes:
|
|
97
|
-
- ${VOLUMES_PATH}/marimo/data:/app
|
|
98
|
-
# command: marimo edit /app/main.py --host 0.0.0.0 --port 8080 --no-token
|
|
99
|
-
restart: always
|
|
100
|
-
deploy:
|
|
101
|
-
resources:
|
|
102
|
-
limits:
|
|
103
|
-
memory: 2g
|
|
104
|
-
reservations:
|
|
105
|
-
memory: 512M
|
|
106
|
-
networks:
|
|
107
|
-
- edge_network
|
|
108
|
-
emqx:
|
|
109
|
-
image: emqx/emqx:5.8
|
|
110
|
-
container_name: emqx
|
|
111
|
-
ports:
|
|
112
|
-
- "1883:1883" # MQTT端口
|
|
113
|
-
- "8883:8883" # MQTT加密端口
|
|
114
|
-
- "8083:8083" # WebSocket端口
|
|
115
|
-
- "8084:8084" # WebSocket加密端口
|
|
116
|
-
- "18083:18083" # EMQX Dashboard端口
|
|
117
|
-
environment:
|
|
118
|
-
- EMQX_NAME=emqx
|
|
119
|
-
- EMQX_NODE__COOKIE=secretcookie # 节点通信时的cookie
|
|
120
|
-
- service_logo=emqx-original.svg
|
|
121
|
-
- service_description=aboutus.emqxDescription
|
|
122
|
-
- service_redirect_url=/emqx/home/
|
|
123
|
-
- service_account=admin
|
|
124
|
-
- service_password=public
|
|
125
|
-
volumes:
|
|
126
|
-
- /etc/localtime:/etc/localtime:ro
|
|
127
|
-
- ${VOLUMES_PATH}/emqx/data:/opt/emqx/data
|
|
128
|
-
- ${VOLUMES_PATH}/emqx/log:/opt/emqx/log
|
|
129
|
-
- ${VOLUMES_PATH}/emqx/config/emqx.conf:/opt/emqx/etc/emqx.conf
|
|
130
|
-
- ${VOLUMES_PATH}/emqx/config/default_api_key.conf:/opt/emqx/etc/default_api_key.conf
|
|
131
|
-
- ${VOLUMES_PATH}/emqx/config/acl.conf:/opt/emqx/etc/acl.conf
|
|
132
|
-
restart: always
|
|
133
|
-
networks:
|
|
134
|
-
- edge_network
|
|
135
|
-
nodered:
|
|
136
|
-
image: nodered/node-red:4.0.8-22
|
|
137
|
-
container_name: nodered
|
|
138
|
-
user: root
|
|
139
|
-
ports:
|
|
140
|
-
- "1880:1880" # Node-RED web UI端口
|
|
141
|
-
environment:
|
|
142
|
-
- service_logo=nodered-original.svg
|
|
143
|
-
- service_description=aboutus.nodeRedDescription
|
|
144
|
-
- FLOWS=/data/flows.json
|
|
145
|
-
- USE_ALIAS_AS_TOPIC=false
|
|
146
|
-
- TIMESTAMP_NAME=timeStamp
|
|
147
|
-
- QUALITY_NAME=quality
|
|
148
|
-
- TZ=UTC
|
|
149
|
-
- OS_LANG=${LANGUAGE}
|
|
150
|
-
- NODE_OPTIONS=--openssl-legacy-provider
|
|
151
|
-
- NODE_HTTP_API_PREFIX=/nodered-api
|
|
152
|
-
volumes:
|
|
153
|
-
- /etc/localtime:/etc/localtime:ro
|
|
154
|
-
- ${VOLUMES_PATH}/node-red:/data # 使用当前目录的 data 目录
|
|
155
|
-
depends_on:
|
|
156
|
-
- emqx
|
|
157
|
-
restart: always
|
|
158
|
-
networks:
|
|
159
|
-
- edge_network
|
|
160
|
-
eventflow:
|
|
161
|
-
image: nodered/node-red:4.0.8-22
|
|
162
|
-
container_name: eventflow
|
|
163
|
-
user: root
|
|
164
|
-
ports:
|
|
165
|
-
- "1889:1889" # Node-RED web UI端口
|
|
166
|
-
environment:
|
|
167
|
-
- service_logo=nodered-original.svg
|
|
168
|
-
- service_description=aboutus.nodeRedDescription
|
|
169
|
-
- FLOWS=/data/flows.json
|
|
170
|
-
- USE_ALIAS_AS_TOPIC=false
|
|
171
|
-
- QUALITY_NAME=status
|
|
172
|
-
- TIMESTAMP_NAME=timeStamp
|
|
173
|
-
- TZ=UTC
|
|
174
|
-
- OS_LANG=${LANGUAGE}
|
|
175
|
-
- NODE_OPTIONS=--openssl-legacy-provider
|
|
176
|
-
- NODE_HTTP_API_PREFIX=/eventflow-api
|
|
177
|
-
volumes:
|
|
178
|
-
- /etc/localtime:/etc/localtime:ro
|
|
179
|
-
- ${VOLUMES_PATH}/eventflow:/data # 使用当前目录的 data 目录
|
|
180
|
-
restart: always
|
|
181
|
-
networks:
|
|
182
|
-
- edge_network
|
|
183
|
-
grafana:
|
|
184
|
-
image: grafana/grafana:11.5.6
|
|
185
|
-
profiles:
|
|
186
|
-
- grafana
|
|
187
|
-
container_name: grafana
|
|
188
|
-
user: root
|
|
189
|
-
ports:
|
|
190
|
-
- "3000:3000" # Grafana web UI端口
|
|
191
|
-
volumes:
|
|
192
|
-
- ${VOLUMES_PATH}/grafana/data:/var/lib/grafana
|
|
193
|
-
# - ${VOLUMES_PATH}/grafana/data/plugins:/var/lib/grafana/plugins # 使用当前目录的 data 目录
|
|
194
|
-
environment:
|
|
195
|
-
service_logo: grafana-original.svg
|
|
196
|
-
service_description: aboutus.grafanaDescription
|
|
197
|
-
service_redirect_url: /grafana/home/dashboards/
|
|
198
|
-
# 设置管理员用户的初始密码
|
|
199
|
-
GF_SECURITY_ADMIN_PASSWORD: "supos"
|
|
200
|
-
# 开启 Grafana 的 Explore 功能
|
|
201
|
-
GF_EXPLORE_ENABLED: "true"
|
|
202
|
-
# 安装 Grafana 插件
|
|
203
|
-
# GF_INSTALL_PLUGINS: "grafana-clock-panel,grafana-mqtt-datasource,tdengine-datasource,yesoreyeram-infinity-datasource"
|
|
204
|
-
# 注释掉的设置,用于改变 Grafana 用户界面的语言
|
|
205
|
-
GF_VIEWER_LANGUAGE: "${GRAFANA_LANG:-en-US}"
|
|
206
|
-
GF_AUTH_ANONYMOUS_ENABLED: "true"
|
|
207
|
-
GF_AUTH_ANONYMOUS_ORG_ROLE: "Admin"
|
|
208
|
-
GF_SECURITY_ALLOW_EMBEDDING: "true"
|
|
209
|
-
GF_SERVER_ROOT_URL: "http://${ENTRANCE_DOMAIN}/grafana/home/"
|
|
210
|
-
GF_USERS_DEFAULT_THEME: "light"
|
|
211
|
-
GF_DATABASE_TYPE: postgres
|
|
212
|
-
GF_DATABASE_HOST: postgresql:5432
|
|
213
|
-
GF_DATABASE_NAME: grafana
|
|
214
|
-
GF_DATABASE_USER: postgres
|
|
215
|
-
GF_DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
|
|
216
|
-
restart: always
|
|
217
|
-
depends_on:
|
|
218
|
-
postgresql:
|
|
219
|
-
condition: service_healthy # 依赖 PostgreSQL 的健康状态
|
|
220
|
-
networks:
|
|
221
|
-
- edge_network
|
|
222
|
-
portainer:
|
|
223
|
-
image: portainer/portainer-ce:2.23.0
|
|
224
|
-
container_name: portainer
|
|
225
|
-
environment:
|
|
226
|
-
service_logo: portainer.svg
|
|
227
|
-
command: --admin-password="$$2y$$05$$ZTAqF7Tn.hil8X.ifVmQTuKiJQoZDiKDW3t1lRR2/VPR06QoHv4AC"
|
|
228
|
-
ports:
|
|
229
|
-
- "8000:8000"
|
|
230
|
-
- "9443:9443"
|
|
231
|
-
restart: always
|
|
232
|
-
volumes:
|
|
233
|
-
- /var/run/docker.sock:/var/run/docker.sock
|
|
234
|
-
- ${VOLUMES_PATH}/portainer:/data
|
|
235
|
-
networks:
|
|
236
|
-
- edge_network
|
|
237
|
-
postgresql:
|
|
238
|
-
image: timescale/timescaledb:2.20.0-pg17
|
|
239
|
-
container_name: postgresql
|
|
240
|
-
environment:
|
|
241
|
-
TZ: UTC # 设置容器时区
|
|
242
|
-
service_logo: postgresql-original.svg
|
|
243
|
-
service_description: aboutus.postgresqlDescription
|
|
244
|
-
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
245
|
-
ports:
|
|
246
|
-
- "5432:5432"
|
|
247
|
-
volumes:
|
|
248
|
-
- ${VOLUMES_PATH}/postgresql/conf/postgresql.conf:/etc/postgresql/custom.conf
|
|
249
|
-
- /etc/localtime:/etc/localtime:ro
|
|
250
|
-
- ${VOLUMES_PATH}/postgresql/pgdata:/var/lib/postgresql/data # 持久化数据
|
|
251
|
-
- ${VOLUMES_PATH}/postgresql/init-scripts:/docker-entrypoint-initdb.d # 加载初始化脚本
|
|
252
|
-
command:
|
|
253
|
-
- postgres
|
|
254
|
-
- -c
|
|
255
|
-
- config_file=/etc/postgresql/custom.conf
|
|
256
|
-
healthcheck:
|
|
257
|
-
test: [ "CMD-SHELL", "psql -U postgres -d keycloak -c '\\dt public.initialization_complete' | grep -q 'initialization_complete'" ]
|
|
258
|
-
interval: 15s
|
|
259
|
-
timeout: 15s
|
|
260
|
-
retries: 60
|
|
261
|
-
start_period: 120s
|
|
262
|
-
start_interval: 10s
|
|
263
|
-
restart: always
|
|
264
|
-
networks:
|
|
265
|
-
- edge_network
|
|
266
|
-
keycloak:
|
|
267
|
-
image: keycloak/keycloak:26.0 # 使用 Keycloak 的最新镜像
|
|
268
|
-
container_name: keycloak
|
|
269
|
-
ports:
|
|
270
|
-
- "8081:8080"
|
|
271
|
-
user: root
|
|
272
|
-
deploy:
|
|
273
|
-
resources:
|
|
274
|
-
limits:
|
|
275
|
-
memory: 2G
|
|
276
|
-
reservations:
|
|
277
|
-
memory: 512M
|
|
278
|
-
environment:
|
|
279
|
-
service_logo: keycloak-original.svg
|
|
280
|
-
JAVA_OPTS: >-
|
|
281
|
-
-Xms512m
|
|
282
|
-
-Xmx1g
|
|
283
|
-
-XX:MaxMetaspaceSize=256m
|
|
284
|
-
-XX:MetaspaceSize=256m
|
|
285
|
-
-Xss512k
|
|
286
|
-
-XX:+UseG1GC
|
|
287
|
-
service_description: aboutus.keycloakDescription
|
|
288
|
-
service_redirect_url: /keycloak/home/
|
|
289
|
-
service_account: admin
|
|
290
|
-
service_password: tier0
|
|
291
|
-
KC_SSL_REQUIRED: none # 不要求 SSL
|
|
292
|
-
KC_PROXY: passthrough # 设置代理模式
|
|
293
|
-
KC_HOSTNAME: "${ENTRANCE_DOMAIN}" # 指定主机名
|
|
294
|
-
KC_FRONTEND_URL: "${BASE_URL}" # 设置前端 URL
|
|
295
|
-
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
|
296
|
-
KC_BOOTSTRAP_ADMIN_PASSWORD: tier0
|
|
297
|
-
KC_COOKIE_SECURE: false # 禁用安全 cookie
|
|
298
|
-
KC_DB: postgres
|
|
299
|
-
KC_DB_URL: "jdbc:postgresql://postgresql:5432/keycloak"
|
|
300
|
-
KC_DB_USERNAME: postgres
|
|
301
|
-
KC_DB_PASSWORD: ${POSTGRES_PASSWORD}
|
|
302
|
-
KC_DB_POOL_INITIAL_SIZE: 2
|
|
303
|
-
KC_DB_POOL_MIN_SIZE: 2
|
|
304
|
-
KC_DB_POOL_MAX_SIZE: 4
|
|
305
|
-
KC_DB_POOL_MAX_LIFETIME: 1800
|
|
306
|
-
KC_HEALTH_ENABLED: true
|
|
307
|
-
KC_FEATURES: token-exchange
|
|
308
|
-
JAVA_OPTS_APPEND: -Dcom.sun.jndi.ldap.object.disableEndpointIdentification=true
|
|
309
|
-
volumes:
|
|
310
|
-
- /etc/localtime:/etc/localtime:ro
|
|
311
|
-
- ${VOLUMES_PATH}/keycloak/data:/opt/keycloak/data # 将 Keycloak 的数据目录挂载到本地
|
|
312
|
-
- ${VOLUMES_PATH}/keycloak/theme/keycloak.v2:/opt/keycloak/themes/wenhao
|
|
313
|
-
- ${VOLUMES_PATH}/keycloak/ca/ca.crt:/opt/keycloak/ca.crt
|
|
314
|
-
- ${VOLUMES_PATH}/keycloak/ca/init-ldaps-cert.sh:/opt/keycloak/init-ldaps-cert.sh
|
|
315
|
-
depends_on:
|
|
316
|
-
postgresql:
|
|
317
|
-
condition: service_healthy # 依赖 PostgreSQL 的健康状态
|
|
318
|
-
command: start-dev --hostname ${BASE_URL}/keycloak/home/auth --proxy-headers forwarded
|
|
319
|
-
healthcheck:
|
|
320
|
-
test: >
|
|
321
|
-
/bin/bash -c " exec 3<>/dev/tcp/localhost/8080"
|
|
322
|
-
interval: 10s
|
|
323
|
-
timeout: 5s
|
|
324
|
-
retries: 60
|
|
325
|
-
start_period: 120s # 新增:给予2分钟的启动宽限期
|
|
326
|
-
start_interval: 10s # 新增:宽限期内的检查间隔
|
|
327
|
-
restart: always
|
|
328
|
-
networks:
|
|
329
|
-
- edge_network
|
|
330
|
-
tsdb:
|
|
331
|
-
image: timescale/timescaledb:2.20.0-pg17
|
|
332
|
-
container_name: tsdb
|
|
333
|
-
environment:
|
|
334
|
-
TZ: UTC # 设置容器时区
|
|
335
|
-
service_logo: postgresql-original.svg
|
|
336
|
-
service_description: aboutus.postgresqlDescription
|
|
337
|
-
POSTGRES_PASSWORD: ${TSDB_PASSWORD}
|
|
338
|
-
ports:
|
|
339
|
-
- "2345:5432"
|
|
340
|
-
volumes:
|
|
341
|
-
- ${VOLUMES_PATH}/tsdb/conf/postgresql.conf:/etc/postgresql/custom.conf
|
|
342
|
-
- ${VOLUMES_PATH}/tsdb/data:/var/lib/postgresql/data # 持久化数据
|
|
343
|
-
- ${VOLUMES_PATH}/tsdb/init-scripts:/docker-entrypoint-initdb.d # 加载初始化脚本
|
|
344
|
-
command:
|
|
345
|
-
- postgres
|
|
346
|
-
- -c
|
|
347
|
-
- config_file=/etc/postgresql/custom.conf
|
|
348
|
-
healthcheck:
|
|
349
|
-
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
|
|
350
|
-
interval: 10s
|
|
351
|
-
timeout: 5s
|
|
352
|
-
retries: 10
|
|
353
|
-
start_period: 30s
|
|
354
|
-
start_interval: 60s
|
|
355
|
-
restart: always
|
|
356
|
-
networks:
|
|
357
|
-
- edge_network
|
|
358
|
-
kong:
|
|
359
|
-
image: kong:3.9.0
|
|
360
|
-
container_name: kong
|
|
361
|
-
environment:
|
|
362
|
-
KONG_WORKER_STATE_UPDATE_FREQUENCY: 30
|
|
363
|
-
KONG_DB_CACHE_TTL: 600
|
|
364
|
-
KONG_NGINX_WORKER_PROCESSES: 2
|
|
365
|
-
KONG_LUA_GC_PAUSE: 100 # 提高暂停率,降低 GC 触发频率
|
|
366
|
-
KONG_LUA_GC_STEPMUL: 200 # 增加单次回收强度
|
|
367
|
-
service_logo: konga-original.svg
|
|
368
|
-
service_description: aboutus.kongaDescription
|
|
369
|
-
service_redirect_url: /konga/home/
|
|
370
|
-
KONG_DATABASE: postgres
|
|
371
|
-
KONG_PG_HOST: postgresql
|
|
372
|
-
KONG_PG_PASSWORD: ${POSTGRES_PASSWORD}
|
|
373
|
-
KONG_PG_USER: postgres
|
|
374
|
-
KONG_ADMIN_LISTEN: 0.0.0.0:8001
|
|
375
|
-
KONG_SSL_CERT: /etc/kong/ssl/fullchain.cer
|
|
376
|
-
KONG_SSL_CERT_KEY: /etc/kong/ssl/private.key
|
|
377
|
-
KONG_PROXY_LISTEN: 0.0.0.0:8000, 0.0.0.0:8443 ssl
|
|
378
|
-
KONG_PLUGINS: bundled,supos-auth-checker,supos-url-transformer
|
|
379
|
-
KONG_PG_POOL_SIZE: 2
|
|
380
|
-
KONG_LOG_LEVEL: error
|
|
381
|
-
KONG_NGINX_HTTP_CLIENT_MAX_BODY_SIZE: 2048m
|
|
382
|
-
KONG_NGINX_PROXY_CLIENT_MAX_BODY_SIZE: 2048m
|
|
383
|
-
KONG_NGINX_HTTP_PROXY_CONNECT_TIMEOUT: 300000
|
|
384
|
-
KONG_NGINX_HTTP_PROXY_SEND_TIMEOUT: 300000
|
|
385
|
-
KONG_NGINX_HTTP_PROXY_READ_TIMEOUT: 300000
|
|
386
|
-
volumes:
|
|
387
|
-
- ${VOLUMES_PATH}/kong/certificationfile:/etc/kong/ssl:ro
|
|
388
|
-
- ${VOLUMES_PATH}/kong/kong_config.yml:/etc/kong/kong_config.yml
|
|
389
|
-
- ${VOLUMES_PATH}/kong/start.sh:/usr/local/bin/start.sh
|
|
390
|
-
- ${VOLUMES_PATH}/kong/kong-plugin-auth-checker:/usr/local/share/lua/5.1/kong/plugins/supos-auth-checker
|
|
391
|
-
- ${VOLUMES_PATH}/kong/kong-plugin-url-transformer:/usr/local/share/lua/5.1/kong/plugins/supos-url-transformer
|
|
392
|
-
ports:
|
|
393
|
-
- "${ENTRANCE_PORT:-8088}:8000"
|
|
394
|
-
- "${ENTRANCE_SSL_PORT:-8443}:8443"
|
|
395
|
-
- "8001:8001"
|
|
396
|
-
- "8444:8444"
|
|
397
|
-
depends_on:
|
|
398
|
-
- emqx
|
|
399
|
-
- uns
|
|
400
|
-
- keycloak
|
|
401
|
-
- postgresql
|
|
402
|
-
command: >
|
|
403
|
-
sh -c "kong migrations bootstrap &&
|
|
404
|
-
kong config db_import /etc/kong/kong_config.yml &&
|
|
405
|
-
kong start"
|
|
406
|
-
restart: always # 确保 Kong 自动重启
|
|
407
|
-
networks:
|
|
408
|
-
- edge_network
|
|
409
|
-
konga:
|
|
410
|
-
image: suposce/konga:1.0.0
|
|
411
|
-
container_name: konga
|
|
412
|
-
profiles:
|
|
413
|
-
- konga
|
|
414
|
-
environment:
|
|
415
|
-
# DB_ADAPTER: mysql # 使用 MySQL 作为数据库
|
|
416
|
-
# DB_HOST: konga_mysql_database # MySQL 容器的主机名
|
|
417
|
-
# DB_USER: konga # MySQL 用户
|
|
418
|
-
# DB_PASSWORD: konga # MySQL 用户密码
|
|
419
|
-
# DB_DATABASE: konga # MySQL 数据库名
|
|
420
|
-
# NODE_ENV: production # 设置 NODE_ENV 为生产环境
|
|
421
|
-
NO_AUTH: "true" # 禁用认证
|
|
422
|
-
KONGA_SEED_KONG_NODE_DATA_SOURCE_FILE: /node.data
|
|
423
|
-
ports:
|
|
424
|
-
- "1337:1337" # 映射 Konga 的端口到主机
|
|
425
|
-
volumes:
|
|
426
|
-
- ${VOLUMES_PATH}/konga/db/:/app/kongadata/
|
|
427
|
-
- ${VOLUMES_PATH}/konga/node.data:/node.data # 持久化数据库数据
|
|
428
|
-
restart: always
|
|
429
|
-
networks:
|
|
430
|
-
- edge_network
|
|
431
|
-
minio:
|
|
432
|
-
image: minio/minio:RELEASE.2024-12-18T13-15-44Z
|
|
433
|
-
container_name: minio
|
|
434
|
-
profiles:
|
|
435
|
-
- minio
|
|
436
|
-
environment:
|
|
437
|
-
- service_logo=minio-original.svg
|
|
438
|
-
- service_description=aboutus.minioDescription
|
|
439
|
-
- service_redirect_url=/minio/home/
|
|
440
|
-
- MINIO_ACCESS_KEY=admin
|
|
441
|
-
- MINIO_SECRET_KEY=adminpassword
|
|
442
|
-
- MINIO_BROWSER_REDIRECT_URL=${BASE_URL}/minio/home
|
|
443
|
-
- MINIO_IDENTITY_OPENID_CONFIG_URL=${OAUTH_ISSUER_URI}/realms/supos/.well-known/openid-configuration
|
|
444
|
-
- MINIO_IDENTITY_OPENID_CLIENT_ID=${OAUTH_CLIENT_ID}
|
|
445
|
-
- MINIO_IDENTITY_OPENID_CLIENT_SECRET=${OAUTH_CLIENT_SECRET}
|
|
446
|
-
- MINIO_IDENTITY_OPENID_SCOPES=openid
|
|
447
|
-
- MINIO_IDENTITY_OPENID_ROLE_POLICY=public-delete-policy
|
|
448
|
-
- MINIO_IDENTITY_OPENID_REDIRECT_URI=${BASE_URL}/minio/home/oauth_callback
|
|
449
|
-
ports:
|
|
450
|
-
- "9000:9000" # Web UI 端口
|
|
451
|
-
- "9001:9001" # Admin API 端口 (如果需要访问管理接口)
|
|
452
|
-
volumes:
|
|
453
|
-
- ${VOLUMES_PATH}/minio/data:/data # 数据存储位置
|
|
454
|
-
command: server /data --console-address ":9001"
|
|
455
|
-
depends_on:
|
|
456
|
-
keycloak:
|
|
457
|
-
condition: service_healthy
|
|
458
|
-
restart: always
|
|
459
|
-
networks:
|
|
460
|
-
- edge_network
|
package/opctest.py
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
import OpenOPC
|
|
3
|
-
import paho.mqtt.client as mqtt
|
|
4
|
-
import json
|
|
5
|
-
import time
|
|
6
|
-
import signal
|
|
7
|
-
import sys
|
|
8
|
-
reload(sys)
|
|
9
|
-
sys.setdefaultencoding('utf-8')
|
|
10
|
-
|
|
11
|
-
OPC_SERVER = 'Kepware.KEPServerEX.V6'
|
|
12
|
-
OPC_HOST = '192.168.31.75'
|
|
13
|
-
|
|
14
|
-
MQTT_BROKER = '192.168.31.45'
|
|
15
|
-
MQTT_PORT = 1883
|
|
16
|
-
MQTT_TOPIC_PREFIX = 'opcda'
|
|
17
|
-
|
|
18
|
-
POLL_INTERVAL = 1
|
|
19
|
-
|
|
20
|
-
TAGS = [
|
|
21
|
-
u'通道 1.设备 1.标记 1',
|
|
22
|
-
u'TI2022.PV',
|
|
23
|
-
u'TI2022.SV',
|
|
24
|
-
u'TI2022.MV',
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
running = True
|
|
28
|
-
|
|
29
|
-
def on_exit(sig, frame):
|
|
30
|
-
global running
|
|
31
|
-
print("\n[*] Shutting down...")
|
|
32
|
-
running = False
|
|
33
|
-
|
|
34
|
-
signal.signal(signal.SIGINT, on_exit)
|
|
35
|
-
signal.signal(signal.SIGTERM, on_exit)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def make_topic(tag):
|
|
39
|
-
parts = tag.split('.')
|
|
40
|
-
if len(parts) >= 2:
|
|
41
|
-
parent = '/'.join(parts[:-1])
|
|
42
|
-
leaf = parts[-1]
|
|
43
|
-
topic = '%s/%s/Metric/%s' % (MQTT_TOPIC_PREFIX, parent, leaf)
|
|
44
|
-
else:
|
|
45
|
-
topic = '%s/Metric/%s' % (MQTT_TOPIC_PREFIX, tag)
|
|
46
|
-
return topic.replace(' ', '_')
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
UNS_EXPORT_FILE = 'uns_import.json'
|
|
50
|
-
|
|
51
|
-
TOPIC_FIELDS = [
|
|
52
|
-
{"name": "timeStamp", "type": "DATETIME", "unique": True, "systemField": True},
|
|
53
|
-
{"name": "tag", "type": "LONG", "unique": True, "tbValueName": "tag", "systemField": True},
|
|
54
|
-
{"name": "value", "type": "FLOAT", "index": "double_1"},
|
|
55
|
-
{"name": "quality", "type": "LONG", "systemField": True},
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def generate_uns_json(tags):
|
|
60
|
-
def get_or_create(children, name, node_type="path", extra=None):
|
|
61
|
-
for child in children:
|
|
62
|
-
if child["name"] == name:
|
|
63
|
-
return child
|
|
64
|
-
node = {"type": node_type, "name": name}
|
|
65
|
-
if extra:
|
|
66
|
-
node.update(extra)
|
|
67
|
-
if node_type == "path":
|
|
68
|
-
node["children"] = []
|
|
69
|
-
children.append(node)
|
|
70
|
-
return node
|
|
71
|
-
|
|
72
|
-
root_children = []
|
|
73
|
-
for tag in tags:
|
|
74
|
-
parts = tag.replace(' ', '_').split('.')
|
|
75
|
-
if len(parts) >= 2:
|
|
76
|
-
path_parts = parts[:-1]
|
|
77
|
-
leaf = parts[-1]
|
|
78
|
-
else:
|
|
79
|
-
path_parts = []
|
|
80
|
-
leaf = parts[0]
|
|
81
|
-
|
|
82
|
-
current = root_children
|
|
83
|
-
prefix_node = get_or_create(current, MQTT_TOPIC_PREFIX)
|
|
84
|
-
current = prefix_node["children"]
|
|
85
|
-
|
|
86
|
-
for p in path_parts:
|
|
87
|
-
node = get_or_create(current, p)
|
|
88
|
-
current = node["children"]
|
|
89
|
-
|
|
90
|
-
metric_node = get_or_create(current, "Metric", extra={
|
|
91
|
-
"displayName": "Metric",
|
|
92
|
-
"dataType": "METRIC",
|
|
93
|
-
})
|
|
94
|
-
current = metric_node["children"]
|
|
95
|
-
|
|
96
|
-
topic_node = {
|
|
97
|
-
"type": "topic",
|
|
98
|
-
"name": leaf,
|
|
99
|
-
"fields": TOPIC_FIELDS,
|
|
100
|
-
"dataType": "TIME_SEQUENCE_TYPE",
|
|
101
|
-
"generateDashboard": "TRUE",
|
|
102
|
-
"enableHistory": "TRUE",
|
|
103
|
-
"mockData": "FALSE",
|
|
104
|
-
"writeData": "FALSE",
|
|
105
|
-
"topicType": "METRIC",
|
|
106
|
-
}
|
|
107
|
-
exists = False
|
|
108
|
-
for child in current:
|
|
109
|
-
if child["name"] == leaf:
|
|
110
|
-
exists = True
|
|
111
|
-
break
|
|
112
|
-
if not exists:
|
|
113
|
-
current.append(topic_node)
|
|
114
|
-
|
|
115
|
-
result = {"UNS": root_children}
|
|
116
|
-
with open(UNS_EXPORT_FILE, 'w') as f:
|
|
117
|
-
json.dump(result, f, indent=2, ensure_ascii=False)
|
|
118
|
-
print("[+] UNS import JSON written to %s" % UNS_EXPORT_FILE)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def run_bridge():
|
|
122
|
-
global running
|
|
123
|
-
|
|
124
|
-
print("[*] OPC DA -> MQTT Bridge")
|
|
125
|
-
print(" OPC Server: %s @ %s" % (OPC_SERVER, OPC_HOST))
|
|
126
|
-
print(" MQTT Broker: %s:%d" % (MQTT_BROKER, MQTT_PORT))
|
|
127
|
-
print(" Tags: %d" % len(TAGS))
|
|
128
|
-
print("")
|
|
129
|
-
|
|
130
|
-
opc = None
|
|
131
|
-
mqtt_client = None
|
|
132
|
-
|
|
133
|
-
try:
|
|
134
|
-
mqtt_client = mqtt.Client()
|
|
135
|
-
mqtt_client.connect(MQTT_BROKER, MQTT_PORT)
|
|
136
|
-
mqtt_client.loop_start()
|
|
137
|
-
print("[+] MQTT connected")
|
|
138
|
-
|
|
139
|
-
opc = OpenOPC.client()
|
|
140
|
-
opc.connect(OPC_SERVER, OPC_HOST)
|
|
141
|
-
print("[+] OPC DA connected")
|
|
142
|
-
|
|
143
|
-
generate_uns_json(TAGS)
|
|
144
|
-
|
|
145
|
-
print("[*] Publishing data every %ds (Ctrl+C to stop)..." % POLL_INTERVAL)
|
|
146
|
-
print("-" * 50)
|
|
147
|
-
|
|
148
|
-
while running:
|
|
149
|
-
try:
|
|
150
|
-
results = opc.read(TAGS)
|
|
151
|
-
except Exception as e:
|
|
152
|
-
print("[!] OPC read error: %s, reconnecting..." % str(e))
|
|
153
|
-
try:
|
|
154
|
-
opc.close()
|
|
155
|
-
except:
|
|
156
|
-
pass
|
|
157
|
-
opc = OpenOPC.client()
|
|
158
|
-
opc.connect(OPC_SERVER, OPC_HOST)
|
|
159
|
-
continue
|
|
160
|
-
|
|
161
|
-
for tag_name, value, quality, timestamp in results:
|
|
162
|
-
topic = make_topic(tag_name)
|
|
163
|
-
|
|
164
|
-
if isinstance(quality, str):
|
|
165
|
-
quality_code = 0 if quality == 'Good' else 1
|
|
166
|
-
else:
|
|
167
|
-
quality_code = 0 if quality is not None and int(quality) >= 192 else 1
|
|
168
|
-
|
|
169
|
-
if value is None:
|
|
170
|
-
out_value = 0.0
|
|
171
|
-
elif isinstance(value, (int, float)):
|
|
172
|
-
out_value = float(value)
|
|
173
|
-
else:
|
|
174
|
-
try:
|
|
175
|
-
out_value = float(value)
|
|
176
|
-
except (ValueError, TypeError):
|
|
177
|
-
out_value = str(value)
|
|
178
|
-
|
|
179
|
-
payload = json.dumps({
|
|
180
|
-
'value': out_value,
|
|
181
|
-
'quality': quality_code,
|
|
182
|
-
'timestamp': str(timestamp),
|
|
183
|
-
}, ensure_ascii=False)
|
|
184
|
-
mqtt_client.publish(topic, payload, retain=True)
|
|
185
|
-
|
|
186
|
-
ts = time.strftime('%H:%M:%S')
|
|
187
|
-
print("[%s] Published %d tags" % (ts, len(results)))
|
|
188
|
-
|
|
189
|
-
time.sleep(POLL_INTERVAL)
|
|
190
|
-
|
|
191
|
-
except Exception as e:
|
|
192
|
-
print("\n[!] Fatal error: %s" % str(e))
|
|
193
|
-
print(" 1. Is MQTT broker running? ")
|
|
194
|
-
print(" 2. Is OPC server reachable?")
|
|
195
|
-
print(" 3. Run as Administrator if DCOM access is needed.")
|
|
196
|
-
sys.exit(1)
|
|
197
|
-
|
|
198
|
-
finally:
|
|
199
|
-
if opc:
|
|
200
|
-
try:
|
|
201
|
-
opc.close()
|
|
202
|
-
except:
|
|
203
|
-
pass
|
|
204
|
-
print("[-] OPC DA disconnected")
|
|
205
|
-
if mqtt_client:
|
|
206
|
-
mqtt_client.loop_stop()
|
|
207
|
-
mqtt_client.disconnect()
|
|
208
|
-
print("[-] MQTT disconnected")
|
|
209
|
-
|
|
210
|
-
print("[*] Bridge stopped.")
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if __name__ == "__main__":
|
|
214
|
-
run_bridge()
|
package/patch-debug.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const file = '/usr/src/node-red/node_modules/node-dcom/dcom/rpc/security/ntlmauthentication.js';
|
|
3
|
-
let code = fs.readFileSync(file, 'utf8');
|
|
4
|
-
code = code.replace(
|
|
5
|
-
'let target = null;',
|
|
6
|
-
'let target = null;\n console.log("[NTLM-DBG] domain=" + info.domain + " user=" + this.credentials.username);'
|
|
7
|
-
);
|
|
8
|
-
code = code.replace(
|
|
9
|
-
"if (target == '') {",
|
|
10
|
-
"console.log('[NTLM-DBG] target=' + target);\n if (target == '') {"
|
|
11
|
-
);
|
|
12
|
-
fs.writeFileSync(file, code);
|
|
13
|
-
console.log('Patched.');
|