@amigo9090/ih-libiec61850-node 1.0.56 → 1.0.58
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/builds/linux_arm/addon_iec61850.node +0 -0
- package/builds/linux_arm64/addon_iec61850.node +0 -0
- package/builds/linux_x64/addon_iec61850.node +0 -0
- package/builds/macos_arm64/addon_iec61850.node +0 -0
- package/builds/macos_x64/addon_iec61850.node +0 -0
- package/builds/windows_x64/addon_iec61850.node +0 -0
- package/examples/build.yaml +352 -0
- package/examples/build.yml +367 -0
- package/examples/index_iec61850_client2.js +23 -25
- package/examples/test2.js +100 -75
- package/examples/test3.js +34 -0
- package/package.json +5 -5
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Build and Publish
|
|
3
|
+
env:
|
|
4
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
branches: [main]
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
create-release:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout repository
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Setup Node.js
|
|
26
|
+
uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: '24'
|
|
29
|
+
|
|
30
|
+
- name: Get package version
|
|
31
|
+
id: package-version
|
|
32
|
+
run: |
|
|
33
|
+
echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
|
34
|
+
shell: bash
|
|
35
|
+
|
|
36
|
+
- name: Delete existing release
|
|
37
|
+
run: |
|
|
38
|
+
gh release delete v${{ steps.package-version.outputs.version }} --yes || true
|
|
39
|
+
git push origin :refs/tags/v${{ steps.package-version.outputs.version }} || true
|
|
40
|
+
env:
|
|
41
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
42
|
+
|
|
43
|
+
- name: Create Release
|
|
44
|
+
id: create_release
|
|
45
|
+
uses: softprops/action-gh-release@v2.3.2
|
|
46
|
+
env:
|
|
47
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
48
|
+
with:
|
|
49
|
+
tag_name: v${{ steps.package-version.outputs.version }}
|
|
50
|
+
name: Release v${{ steps.package-version.outputs.version }}
|
|
51
|
+
draft: false
|
|
52
|
+
prerelease: false
|
|
53
|
+
generate_release_notes: true
|
|
54
|
+
|
|
55
|
+
build-and-upload:
|
|
56
|
+
needs: create-release
|
|
57
|
+
runs-on: ${{ matrix.os }}
|
|
58
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
59
|
+
strategy:
|
|
60
|
+
matrix:
|
|
61
|
+
os:
|
|
62
|
+
- ubuntu-22.04
|
|
63
|
+
- windows-latest
|
|
64
|
+
- macos-latest
|
|
65
|
+
arch:
|
|
66
|
+
- x64
|
|
67
|
+
include:
|
|
68
|
+
- os: macos-latest
|
|
69
|
+
arch: arm64
|
|
70
|
+
- os: ubuntu-22.04
|
|
71
|
+
arch: arm64
|
|
72
|
+
- os: ubuntu-22.04
|
|
73
|
+
arch: arm
|
|
74
|
+
fail-fast: false
|
|
75
|
+
|
|
76
|
+
steps:
|
|
77
|
+
- name: Checkout repository
|
|
78
|
+
uses: actions/checkout@v4
|
|
79
|
+
|
|
80
|
+
- name: Setup Node.js
|
|
81
|
+
uses: actions/setup-node@v4
|
|
82
|
+
with:
|
|
83
|
+
node-version: '24'
|
|
84
|
+
|
|
85
|
+
- name: Setup Python
|
|
86
|
+
uses: actions/setup-python@v5
|
|
87
|
+
with:
|
|
88
|
+
python-version: '3.11'
|
|
89
|
+
|
|
90
|
+
- name: Install Python dependencies
|
|
91
|
+
run: |
|
|
92
|
+
python -m pip install --upgrade pip
|
|
93
|
+
pip install setuptools
|
|
94
|
+
shell: bash
|
|
95
|
+
|
|
96
|
+
- name: Install cross-compilers for Linux ARM
|
|
97
|
+
if: matrix.os == 'ubuntu-22.04' && (matrix.arch == 'arm' || matrix.arch == 'arm64')
|
|
98
|
+
run: |
|
|
99
|
+
sudo apt-get update
|
|
100
|
+
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
|
|
101
|
+
libc6-dev-armhf-cross
|
|
102
|
+
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
|
103
|
+
shell: bash
|
|
104
|
+
|
|
105
|
+
- name: Install dependencies
|
|
106
|
+
run: npm install
|
|
107
|
+
shell: bash
|
|
108
|
+
|
|
109
|
+
- name: Configure build for Unix
|
|
110
|
+
if: matrix.os != 'windows-latest'
|
|
111
|
+
run: |
|
|
112
|
+
if [ "${{ matrix.os }}" == "ubuntu-22.04" ] && [ "${{ matrix.arch }}" == "arm" ]; then
|
|
113
|
+
export CC=arm-linux-gnueabihf-gcc
|
|
114
|
+
export CXX=arm-linux-gnueabihf-g++
|
|
115
|
+
export LINK=arm-linux-gnueabihf-g++
|
|
116
|
+
npm run configure -- --arch=arm
|
|
117
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && [ "${{ matrix.arch }}" == "arm64" ]; then
|
|
118
|
+
export CC=aarch64-linux-gnu-gcc
|
|
119
|
+
export CXX=aarch64-linux-gnu-g++
|
|
120
|
+
export LINK=aarch64-linux-gnu-g++
|
|
121
|
+
npm run configure -- --arch=arm64
|
|
122
|
+
elif [ "${{ matrix.arch }}" != "x64" ]; then
|
|
123
|
+
npm run configure -- --arch=${{ matrix.arch }}
|
|
124
|
+
else
|
|
125
|
+
npm run configure
|
|
126
|
+
fi
|
|
127
|
+
shell: bash
|
|
128
|
+
|
|
129
|
+
- name: Configure build for Windows
|
|
130
|
+
if: matrix.os == 'windows-latest'
|
|
131
|
+
run: npm run configure
|
|
132
|
+
shell: pwsh
|
|
133
|
+
|
|
134
|
+
- name: Prebuild binaries for Node.js 24 (Unix)
|
|
135
|
+
if: matrix.os != 'windows-latest'
|
|
136
|
+
run: |
|
|
137
|
+
if [ "${{ matrix.os }}" == "macos-latest" ] && [ "${{ matrix.arch }}" == "x64" ]; then
|
|
138
|
+
arch -x86_64 npm run prebuild -- --target 24 --arch x64 --macos-min-version=11.0
|
|
139
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && [ "${{ matrix.arch }}" == "arm" ]; then
|
|
140
|
+
export CC=arm-linux-gnueabihf-gcc
|
|
141
|
+
export CXX=arm-linux-gnueabihf-g++
|
|
142
|
+
export LINK=arm-linux-gnueabihf-g++
|
|
143
|
+
npm run prebuild -- --target 24 --arch arm \
|
|
144
|
+
--cflags="-march=armv7-a -mfpu=vfp -mfloat-abi=hard"
|
|
145
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && [ "${{ matrix.arch }}" == "arm64" ]; then
|
|
146
|
+
export CC=aarch64-linux-gnu-gcc
|
|
147
|
+
export CXX=aarch64-linux-gnu-g++
|
|
148
|
+
export LINK=aarch64-linux-gnu-g++
|
|
149
|
+
npm run prebuild -- --target 24 --arch arm64
|
|
150
|
+
else
|
|
151
|
+
npm run prebuild -- --target 24 --arch ${{ matrix.arch }}
|
|
152
|
+
fi
|
|
153
|
+
shell: bash
|
|
154
|
+
|
|
155
|
+
- name: Prebuild binaries for Node.js 24 (Windows)
|
|
156
|
+
if: matrix.os == 'windows-latest'
|
|
157
|
+
run: npm run prebuild -- --target 24 --arch x64
|
|
158
|
+
shell: pwsh
|
|
159
|
+
|
|
160
|
+
- name: Get package version
|
|
161
|
+
id: package-version
|
|
162
|
+
run: |
|
|
163
|
+
echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
|
164
|
+
shell: bash
|
|
165
|
+
|
|
166
|
+
- name: Get prebuild file
|
|
167
|
+
id: get-prebuild
|
|
168
|
+
run: |
|
|
169
|
+
FILE=$(ls prebuilds/@amigo9090/ih-libiec61850-node-v${{ steps.package-version.outputs.version }}-node-v*.tar.gz 2>/dev/null | head -n 1 || echo "")
|
|
170
|
+
if [ -z "$FILE" ]; then
|
|
171
|
+
echo "ERROR: No prebuild tar.gz found!" >&2
|
|
172
|
+
exit 1
|
|
173
|
+
fi
|
|
174
|
+
echo "file=$FILE" >> $GITHUB_OUTPUT
|
|
175
|
+
echo "Found prebuild: $FILE"
|
|
176
|
+
shell: bash
|
|
177
|
+
|
|
178
|
+
- name: Upload prebuilt binaries to GitHub Releases
|
|
179
|
+
uses: softprops/action-gh-release@v2.3.2
|
|
180
|
+
env:
|
|
181
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
182
|
+
with:
|
|
183
|
+
tag_name: v${{ steps.package-version.outputs.version }}
|
|
184
|
+
files: ${{ steps.get-prebuild.outputs.file }}
|
|
185
|
+
|
|
186
|
+
- name: Upload artifacts
|
|
187
|
+
uses: actions/upload-artifact@v4
|
|
188
|
+
with:
|
|
189
|
+
name: addon_iec61850-${{ matrix.os }}-${{ matrix.arch }}
|
|
190
|
+
path: ${{ steps.get-prebuild.outputs.file }}
|
|
191
|
+
|
|
192
|
+
update-builds-and-publish:
|
|
193
|
+
needs: build-and-upload
|
|
194
|
+
runs-on: ubuntu-latest
|
|
195
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
196
|
+
steps:
|
|
197
|
+
- name: Checkout repository
|
|
198
|
+
uses: actions/checkout@v4
|
|
199
|
+
with:
|
|
200
|
+
fetch-depth: 0
|
|
201
|
+
|
|
202
|
+
- name: Setup Node.js
|
|
203
|
+
uses: actions/setup-node@v4
|
|
204
|
+
with:
|
|
205
|
+
node-version: '24'
|
|
206
|
+
registry-url: 'https://registry.npmjs.org'
|
|
207
|
+
|
|
208
|
+
- name: Install semver
|
|
209
|
+
run: npm install -g semver
|
|
210
|
+
shell: bash
|
|
211
|
+
|
|
212
|
+
- name: Verify npm authentication
|
|
213
|
+
run: npm whoami
|
|
214
|
+
env:
|
|
215
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
216
|
+
|
|
217
|
+
- name: Get package version
|
|
218
|
+
id: package-version
|
|
219
|
+
run: |
|
|
220
|
+
echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
|
221
|
+
shell: bash
|
|
222
|
+
|
|
223
|
+
- name: Download all artifacts
|
|
224
|
+
uses: actions/download-artifact@v4
|
|
225
|
+
with:
|
|
226
|
+
path: artifacts
|
|
227
|
+
|
|
228
|
+
- name: Debug downloaded artifacts
|
|
229
|
+
run: |
|
|
230
|
+
echo "=== Downloaded artifacts ==="
|
|
231
|
+
ls -la artifacts/ || echo "No artifacts dir"
|
|
232
|
+
find artifacts/ -name "*.tar.gz" | wc -l
|
|
233
|
+
find artifacts/ -name "*.tar.gz" || echo "No tar.gz found"
|
|
234
|
+
|
|
235
|
+
- name: Install jq
|
|
236
|
+
run: sudo apt-get update && sudo apt-get install -y jq
|
|
237
|
+
shell: bash
|
|
238
|
+
|
|
239
|
+
- name: Update builds folder
|
|
240
|
+
run: |
|
|
241
|
+
echo "=== Очищаем и обновляем папку builds ==="
|
|
242
|
+
rm -rf builds
|
|
243
|
+
mkdir -p builds
|
|
244
|
+
|
|
245
|
+
declare -A platform_map=(
|
|
246
|
+
["linux-arm"]="linux_arm"
|
|
247
|
+
["linux-arm64"]="linux_arm64"
|
|
248
|
+
["linux-x64"]="linux_x64"
|
|
249
|
+
["darwin-arm64"]="macos_arm64"
|
|
250
|
+
["darwin-x64"]="macos_x64"
|
|
251
|
+
["win32-x64"]="windows_x64"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
for artifact_dir in artifacts/addon_iec61850-*; do
|
|
255
|
+
if [ -d "$artifact_dir" ]; then
|
|
256
|
+
echo "Processing: $artifact_dir"
|
|
257
|
+
for tarball in "$artifact_dir"/*.tar.gz; do
|
|
258
|
+
if [ -f "$tarball" ]; then
|
|
259
|
+
filename=$(basename "$tarball")
|
|
260
|
+
echo "Tarball: $filename"
|
|
261
|
+
platform_arch=$(echo "$filename" | sed -n 's/.*-\(node-v[0-9]*\|napi\)-\(.*\)\.tar\.gz/\2/p')
|
|
262
|
+
echo "Parsed platform_arch: '$platform_arch'"
|
|
263
|
+
|
|
264
|
+
if [[ -n "${platform_map[$platform_arch]}" ]]; then
|
|
265
|
+
target_dir="builds/${platform_map[$platform_arch]}"
|
|
266
|
+
mkdir -p "$target_dir"
|
|
267
|
+
echo "Extracting to $target_dir"
|
|
268
|
+
tar -xzf "$tarball" -C "$target_dir" --strip-components=1
|
|
269
|
+
echo "After extract: $(ls -la $target_dir)"
|
|
270
|
+
|
|
271
|
+
if [ -f "$target_dir/Release/addon_iec61850.node" ]; then
|
|
272
|
+
mv "$target_dir/Release/addon_iec61850.node" "$target_dir/"
|
|
273
|
+
rm -rf "$target_dir/Release"
|
|
274
|
+
else
|
|
275
|
+
mv "$target_dir/addon.node" "$target_dir/addon_iec61850.node" 2>/dev/null || true
|
|
276
|
+
fi
|
|
277
|
+
echo "Final $target_dir: $(ls -la $target_dir/*.node 2>/dev/null || echo 'No .node')"
|
|
278
|
+
else
|
|
279
|
+
echo "Пропускаем неизвестную платформу: $platform_arch"
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
done
|
|
283
|
+
fi
|
|
284
|
+
done
|
|
285
|
+
|
|
286
|
+
echo "=== Final builds contents ==="
|
|
287
|
+
find builds/ -type f -name "*.node" -ls || echo "No .node files found"
|
|
288
|
+
|
|
289
|
+
- name: Copy iec61850.dll for Windows
|
|
290
|
+
run: |
|
|
291
|
+
mkdir -p builds/windows_x64
|
|
292
|
+
cp lib/build/iec61850.dll builds/windows_x64/iec61850.dll || \
|
|
293
|
+
echo "Warning: iec61850.dll not found in lib/build/"
|
|
294
|
+
|
|
295
|
+
- name: Verify builds folder
|
|
296
|
+
run: |
|
|
297
|
+
for dir in linux_arm linux_arm64 linux_x64 macos_arm64 macos_x64 windows_x64; do
|
|
298
|
+
if [ ! -f "builds/$dir/addon_iec61850.node" ]; then
|
|
299
|
+
echo "ОШИБКА: Отсутствует addon_iec61850.node в builds/$dir"
|
|
300
|
+
exit 1
|
|
301
|
+
fi
|
|
302
|
+
done
|
|
303
|
+
if [ ! -f "builds/windows_x64/iec61850.dll" ]; then
|
|
304
|
+
echo "ОШИБКА: Отсутствует iec61850.dll в builds/windows_x64"
|
|
305
|
+
exit 1
|
|
306
|
+
fi
|
|
307
|
+
echo "All builds verified successfully"
|
|
308
|
+
|
|
309
|
+
- name: Commit and push updated builds
|
|
310
|
+
run: |
|
|
311
|
+
git config --global user.name "GitHub Actions"
|
|
312
|
+
git config --global user.email "actions@github.com"
|
|
313
|
+
|
|
314
|
+
git add builds/
|
|
315
|
+
if git diff --staged --quiet; then
|
|
316
|
+
echo "No changes in builds/ — skipping commit"
|
|
317
|
+
else
|
|
318
|
+
git commit -m "Update builds for release v${{ steps.package-version.outputs.version }}"
|
|
319
|
+
git push origin main
|
|
320
|
+
echo "Pushed updated builds"
|
|
321
|
+
fi
|
|
322
|
+
|
|
323
|
+
- name: Publish to npm
|
|
324
|
+
env:
|
|
325
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
326
|
+
run: |
|
|
327
|
+
LATEST_VERSION=$(npm view @amigo9090/ih-libiec61850-node version 2>/dev/null || echo "0.0.0")
|
|
328
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
329
|
+
|
|
330
|
+
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
|
|
331
|
+
NEW_VERSION=$(npx semver -i patch $LATEST_VERSION)
|
|
332
|
+
npm version $NEW_VERSION --no-git-tag-version
|
|
333
|
+
git add package.json package-lock.json
|
|
334
|
+
git commit -m "Bump version to $NEW_VERSION"
|
|
335
|
+
git push origin main
|
|
336
|
+
else
|
|
337
|
+
NEW_VERSION=$CURRENT_VERSION
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
jq 'del(.scripts) | del(.devDependencies)' package.json > package_npm.json
|
|
341
|
+
mv package_npm.json package.json
|
|
342
|
+
|
|
343
|
+
if npm view @amigo9090/ih-libiec61850-node@$NEW_VERSION version > /dev/null 2>&1; then
|
|
344
|
+
echo "Version $NEW_VERSION already exists in npm. Skipping publish."
|
|
345
|
+
else
|
|
346
|
+
npm publish --access public
|
|
347
|
+
echo "Published @amigo9090/ih-libiec61850-node@$NEW_VERSION"
|
|
348
|
+
fi
|
|
349
|
+
|
|
350
|
+
git tag v$NEW_VERSION
|
|
351
|
+
git push origin v$NEW_VERSION
|
|
352
|
+
git checkout -- package.json
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
name: Build and Publish
|
|
2
|
+
env:
|
|
3
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
branches: [main]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
create-release:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout repository
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Setup Node.js
|
|
25
|
+
uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: '24'
|
|
28
|
+
|
|
29
|
+
- name: Get package version
|
|
30
|
+
id: package-version
|
|
31
|
+
run: |
|
|
32
|
+
echo "version=$(node -p "require('./package.json').version")" \
|
|
33
|
+
>> $GITHUB_OUTPUT
|
|
34
|
+
shell: bash
|
|
35
|
+
|
|
36
|
+
- name: Delete existing release
|
|
37
|
+
run: |
|
|
38
|
+
gh release delete v${{ steps.package-version.outputs.version }} \
|
|
39
|
+
--yes || true
|
|
40
|
+
git push origin :refs/tags/v${{ steps.package-version.outputs.version }} \
|
|
41
|
+
|| true
|
|
42
|
+
env:
|
|
43
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
44
|
+
|
|
45
|
+
- name: Create Release
|
|
46
|
+
id: create_release
|
|
47
|
+
uses: softprops/action-gh-release@v2.3.2
|
|
48
|
+
env:
|
|
49
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
50
|
+
with:
|
|
51
|
+
tag_name: v${{ steps.package-version.outputs.version }}
|
|
52
|
+
name: Release v${{ steps.package-version.outputs.version }}
|
|
53
|
+
draft: false
|
|
54
|
+
prerelease: false
|
|
55
|
+
generate_release_notes: true
|
|
56
|
+
|
|
57
|
+
build-and-upload:
|
|
58
|
+
needs: create-release
|
|
59
|
+
runs-on: ${{ matrix.os }}
|
|
60
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
61
|
+
strategy:
|
|
62
|
+
matrix:
|
|
63
|
+
os:
|
|
64
|
+
- ubuntu-22.04
|
|
65
|
+
- windows-latest
|
|
66
|
+
- macos-latest
|
|
67
|
+
arch:
|
|
68
|
+
- x64
|
|
69
|
+
include:
|
|
70
|
+
- os: macos-latest
|
|
71
|
+
arch: arm64
|
|
72
|
+
- os: ubuntu-22.04
|
|
73
|
+
arch: arm64
|
|
74
|
+
- os: ubuntu-22.04
|
|
75
|
+
arch: arm
|
|
76
|
+
fail-fast: false
|
|
77
|
+
|
|
78
|
+
steps:
|
|
79
|
+
- name: Checkout repository
|
|
80
|
+
uses: actions/checkout@v4
|
|
81
|
+
|
|
82
|
+
- name: Setup Node.js
|
|
83
|
+
uses: actions/setup-node@v4
|
|
84
|
+
with:
|
|
85
|
+
node-version: '24'
|
|
86
|
+
|
|
87
|
+
- name: Setup Python
|
|
88
|
+
uses: actions/setup-python@v5
|
|
89
|
+
with:
|
|
90
|
+
python-version: '3.11'
|
|
91
|
+
|
|
92
|
+
- name: Install Python dependencies
|
|
93
|
+
run: |
|
|
94
|
+
python -m pip install --upgrade pip
|
|
95
|
+
pip install setuptools
|
|
96
|
+
shell: bash
|
|
97
|
+
|
|
98
|
+
- name: Install cross-compilers for Linux ARM
|
|
99
|
+
if: matrix.os == 'ubuntu-22.04' && (matrix.arch == 'arm' || matrix.arch == 'arm64')
|
|
100
|
+
run: |
|
|
101
|
+
sudo apt-get update
|
|
102
|
+
sudo apt-get install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf \
|
|
103
|
+
libc6-dev-armhf-cross
|
|
104
|
+
sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
|
105
|
+
shell: bash
|
|
106
|
+
|
|
107
|
+
- name: Install dependencies
|
|
108
|
+
run: npm install
|
|
109
|
+
shell: bash
|
|
110
|
+
|
|
111
|
+
- name: Configure build for Unix
|
|
112
|
+
if: matrix.os != 'windows-latest'
|
|
113
|
+
run: |
|
|
114
|
+
if [ "${{ matrix.os }}" == "ubuntu-22.04" ] && \
|
|
115
|
+
[ "${{ matrix.arch }}" == "arm" ]; then
|
|
116
|
+
export CC=arm-linux-gnueabihf-gcc
|
|
117
|
+
export CXX=arm-linux-gnueabihf-g++
|
|
118
|
+
export LINK=arm-linux-gnueabihf-g++
|
|
119
|
+
npm run configure -- --arch=arm
|
|
120
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && \
|
|
121
|
+
[ "${{ matrix.arch }}" == "arm64" ]; then
|
|
122
|
+
export CC=aarch64-linux-gnu-gcc
|
|
123
|
+
export CXX=aarch64-linux-gnu-g++
|
|
124
|
+
export LINK=aarch64-linux-gnu-g++
|
|
125
|
+
npm run configure -- --arch=arm64
|
|
126
|
+
elif [ "${{ matrix.arch }}" != "x64" ]; then
|
|
127
|
+
npm run configure -- --arch=${{ matrix.arch }}
|
|
128
|
+
else
|
|
129
|
+
npm run configure
|
|
130
|
+
fi
|
|
131
|
+
shell: bash
|
|
132
|
+
|
|
133
|
+
- name: Configure build for Windows
|
|
134
|
+
if: matrix.os == 'windows-latest'
|
|
135
|
+
run: npm run configure
|
|
136
|
+
shell: pwsh
|
|
137
|
+
|
|
138
|
+
- name: Prebuild binaries for Node.js 24 (Unix)
|
|
139
|
+
if: matrix.os != 'windows-latest'
|
|
140
|
+
run: |
|
|
141
|
+
if [ "${{ matrix.os }}" == "macos-latest" ] && \
|
|
142
|
+
[ "${{ matrix.arch }}" == "x64" ]; then
|
|
143
|
+
arch -x86_64 npm run prebuild -- --target 24 --arch x64 \
|
|
144
|
+
--macos-min-version=11.0
|
|
145
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && \
|
|
146
|
+
[ "${{ matrix.arch }}" == "arm" ]; then
|
|
147
|
+
export CC=arm-linux-gnueabihf-gcc
|
|
148
|
+
export CXX=arm-linux-gnueabihf-g++
|
|
149
|
+
export LINK=arm-linux-gnueabihf-g++
|
|
150
|
+
npm run prebuild -- --target 24 --arch arm \
|
|
151
|
+
--cflags="-march=armv7-a -mfpu=vfp -mfloat-abi=hard"
|
|
152
|
+
elif [ "${{ matrix.os }}" == "ubuntu-22.04" ] && \
|
|
153
|
+
[ "${{ matrix.arch }}" == "arm64" ]; then
|
|
154
|
+
export CC=aarch64-linux-gnu-gcc
|
|
155
|
+
export CXX=aarch64-linux-gnu-g++
|
|
156
|
+
export LINK=aarch64-linux-gnu-g++
|
|
157
|
+
npm run prebuild -- --target 24 --arch arm64
|
|
158
|
+
else
|
|
159
|
+
npm run prebuild -- --target 24 --arch ${{ matrix.arch }}
|
|
160
|
+
fi
|
|
161
|
+
shell: bash
|
|
162
|
+
|
|
163
|
+
- name: Prebuild binaries for Node.js 24 (Windows)
|
|
164
|
+
if: matrix.os == 'windows-latest'
|
|
165
|
+
run: npm run prebuild -- --target 24 --arch x64
|
|
166
|
+
shell: pwsh
|
|
167
|
+
|
|
168
|
+
- name: Get package version
|
|
169
|
+
id: package-version
|
|
170
|
+
run: |
|
|
171
|
+
echo "version=$(node -p "require('./package.json').version")" \
|
|
172
|
+
>> $GITHUB_OUTPUT
|
|
173
|
+
shell: bash
|
|
174
|
+
|
|
175
|
+
- name: Get prebuild file
|
|
176
|
+
id: get-prebuild
|
|
177
|
+
run: |
|
|
178
|
+
FILE=$(ls prebuilds/@amigo9090/ih-libiec61850-node-v${{ steps.package-version.outputs.version }}-node-v*.tar.gz 2>/dev/null | head -n 1 || echo "")
|
|
179
|
+
if [ -z "$FILE" ]; then
|
|
180
|
+
echo "ERROR: No prebuild tar.gz found!" >&2
|
|
181
|
+
exit 1
|
|
182
|
+
fi
|
|
183
|
+
echo "file=$FILE" >> $GITHUB_OUTPUT
|
|
184
|
+
echo "Found prebuild: $FILE"
|
|
185
|
+
shell: bash
|
|
186
|
+
|
|
187
|
+
- name: Upload prebuilt binaries to GitHub Releases
|
|
188
|
+
uses: softprops/action-gh-release@v2.3.2
|
|
189
|
+
env:
|
|
190
|
+
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
191
|
+
with:
|
|
192
|
+
tag_name: v${{ steps.package-version.outputs.version }}
|
|
193
|
+
files: ${{ steps.get-prebuild.outputs.file }}
|
|
194
|
+
|
|
195
|
+
- name: Upload artifacts
|
|
196
|
+
uses: actions/upload-artifact@v4
|
|
197
|
+
with:
|
|
198
|
+
name: addon_iec61850-${{ matrix.os }}-${{ matrix.arch }}
|
|
199
|
+
path: ${{ steps.get-prebuild.outputs.file }}
|
|
200
|
+
|
|
201
|
+
update-builds-and-publish:
|
|
202
|
+
needs: build-and-upload
|
|
203
|
+
runs-on: ubuntu-latest
|
|
204
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
205
|
+
steps:
|
|
206
|
+
- name: Checkout repository
|
|
207
|
+
uses: actions/checkout@v4
|
|
208
|
+
with:
|
|
209
|
+
fetch-depth: 0
|
|
210
|
+
|
|
211
|
+
- name: Setup Node.js
|
|
212
|
+
uses: actions/setup-node@v4
|
|
213
|
+
with:
|
|
214
|
+
node-version: '24'
|
|
215
|
+
registry-url: 'https://registry.npmjs.org'
|
|
216
|
+
|
|
217
|
+
- name: Install semver
|
|
218
|
+
run: npm install -g semver
|
|
219
|
+
shell: bash
|
|
220
|
+
|
|
221
|
+
- name: Verify npm authentication
|
|
222
|
+
run: npm whoami
|
|
223
|
+
env:
|
|
224
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
225
|
+
|
|
226
|
+
- name: Get package version
|
|
227
|
+
id: package-version
|
|
228
|
+
run: |
|
|
229
|
+
echo "version=$(node -p "require('./package.json').version")" \
|
|
230
|
+
>> $GITHUB_OUTPUT
|
|
231
|
+
shell: bash
|
|
232
|
+
|
|
233
|
+
- name: Download all artifacts
|
|
234
|
+
uses: actions/download-artifact@v4
|
|
235
|
+
with:
|
|
236
|
+
path: artifacts
|
|
237
|
+
|
|
238
|
+
- name: Debug downloaded artifacts
|
|
239
|
+
run: |
|
|
240
|
+
echo "=== Downloaded artifacts ==="
|
|
241
|
+
ls -la artifacts/ || echo "No artifacts dir"
|
|
242
|
+
find artifacts/ -name "*.tar.gz" | wc -l
|
|
243
|
+
find artifacts/ -name "*.tar.gz" || echo "No tar.gz found"
|
|
244
|
+
|
|
245
|
+
- name: Install jq
|
|
246
|
+
run: sudo apt-get update && sudo apt-get install -y jq
|
|
247
|
+
shell: bash
|
|
248
|
+
|
|
249
|
+
- name: Update builds folder
|
|
250
|
+
run: |
|
|
251
|
+
echo "=== Очищаем и обновляем папку builds ==="
|
|
252
|
+
rm -rf builds
|
|
253
|
+
mkdir -p builds
|
|
254
|
+
|
|
255
|
+
declare -A platform_map=(
|
|
256
|
+
["linux-arm"]="linux_arm"
|
|
257
|
+
["linux-arm64"]="linux_arm64"
|
|
258
|
+
["linux-x64"]="linux_x64"
|
|
259
|
+
["darwin-arm64"]="macos_arm64"
|
|
260
|
+
["darwin-x64"]="macos_x64"
|
|
261
|
+
["win32-x64"]="windows_x64"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
for artifact_dir in artifacts/addon_iec61850-*; do
|
|
265
|
+
if [ -d "$artifact_dir" ]; then
|
|
266
|
+
echo "Processing: $artifact_dir"
|
|
267
|
+
for tarball in "$artifact_dir"/*.tar.gz; do
|
|
268
|
+
if [ -f "$tarball" ]; then
|
|
269
|
+
filename=$(basename "$tarball")
|
|
270
|
+
echo "Tarball: $filename"
|
|
271
|
+
platform_arch=$(echo "$filename" | sed -n \
|
|
272
|
+
's/.*-\(node-v[0-9]*\|napi\)-\(.*\)\.tar\.gz/\2/p')
|
|
273
|
+
echo "Parsed platform_arch: '$platform_arch'"
|
|
274
|
+
|
|
275
|
+
if [[ -n "${platform_map[$platform_arch]}" ]]; then
|
|
276
|
+
target_dir="builds/${platform_map[$platform_arch]}"
|
|
277
|
+
mkdir -p "$target_dir"
|
|
278
|
+
echo "Extracting to $target_dir"
|
|
279
|
+
tar -xzf "$tarball" -C "$target_dir" --strip-components=1
|
|
280
|
+
echo "After extract: $(ls -la $target_dir)"
|
|
281
|
+
|
|
282
|
+
if [ -f "$target_dir/Release/addon_iec61850.node" ]; then
|
|
283
|
+
mv "$target_dir/Release/addon_iec61850.node" "$target_dir/"
|
|
284
|
+
rm -rf "$target_dir/Release"
|
|
285
|
+
else
|
|
286
|
+
mv "$target_dir/addon.node" \
|
|
287
|
+
"$target_dir/addon_iec61850.node" 2>/dev/null || true
|
|
288
|
+
fi
|
|
289
|
+
echo "Final $target_dir: $(ls -la $target_dir/*.node 2>/dev/null || echo 'No .node')"
|
|
290
|
+
else
|
|
291
|
+
echo "Пропускаем неизвестную платформу: $platform_arch"
|
|
292
|
+
fi
|
|
293
|
+
fi
|
|
294
|
+
done
|
|
295
|
+
fi
|
|
296
|
+
done
|
|
297
|
+
|
|
298
|
+
echo "=== Final builds contents ==="
|
|
299
|
+
find builds/ -type f -name "*.node" -ls || echo "No .node files found"
|
|
300
|
+
|
|
301
|
+
- name: Copy iec61850.dll for Windows
|
|
302
|
+
run: |
|
|
303
|
+
mkdir -p builds/windows_x64
|
|
304
|
+
cp lib/build/iec61850.dll builds/windows_x64/iec61850.dll || \
|
|
305
|
+
echo "Warning: iec61850.dll not found in lib/build/"
|
|
306
|
+
|
|
307
|
+
- name: Verify builds folder
|
|
308
|
+
run: |
|
|
309
|
+
for dir in linux_arm linux_arm64 linux_x64 macos_arm64 macos_x64 windows_x64; do
|
|
310
|
+
if [ ! -f "builds/$dir/addon_iec61850.node" ]; then
|
|
311
|
+
echo "ОШИБКА: Отсутствует addon_iec61850.node в builds/$dir"
|
|
312
|
+
exit 1
|
|
313
|
+
fi
|
|
314
|
+
done
|
|
315
|
+
if [ ! -f "builds/windows_x64/iec61850.dll" ]; then
|
|
316
|
+
echo "ОШИБКА: Отсутствует iec61850.dll в builds/windows_x64"
|
|
317
|
+
exit 1
|
|
318
|
+
fi
|
|
319
|
+
echo "All builds verified successfully"
|
|
320
|
+
|
|
321
|
+
- name: Commit and push updated builds
|
|
322
|
+
run: |
|
|
323
|
+
git config --global user.name "GitHub Actions"
|
|
324
|
+
git config --global user.email "actions@github.com"
|
|
325
|
+
|
|
326
|
+
git add builds/
|
|
327
|
+
if git diff --staged --quiet; then
|
|
328
|
+
echo "No changes in builds/ — skipping commit"
|
|
329
|
+
else
|
|
330
|
+
git commit -m "Update builds for release v${{ steps.package-version.outputs.version }}"
|
|
331
|
+
git push origin main
|
|
332
|
+
echo "Pushed updated builds"
|
|
333
|
+
fi
|
|
334
|
+
|
|
335
|
+
- name: Publish to npm
|
|
336
|
+
env:
|
|
337
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
338
|
+
run: |
|
|
339
|
+
LATEST_VERSION=$(npm view @amigo9090/ih-libiec61850-node version \
|
|
340
|
+
2>/dev/null || echo "0.0.0")
|
|
341
|
+
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
|
342
|
+
|
|
343
|
+
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
|
|
344
|
+
NEW_VERSION=$(npx semver -i patch $LATEST_VERSION)
|
|
345
|
+
npm version $NEW_VERSION --no-git-tag-version
|
|
346
|
+
git add package.json package-lock.json
|
|
347
|
+
git commit -m "Bump version to $NEW_VERSION"
|
|
348
|
+
git push origin main
|
|
349
|
+
else
|
|
350
|
+
NEW_VERSION=$CURRENT_VERSION
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
jq 'del(.scripts) | del(.devDependencies)' package.json \
|
|
354
|
+
> package_npm.json
|
|
355
|
+
mv package_npm.json package.json
|
|
356
|
+
|
|
357
|
+
if npm view @amigo9090/ih-libiec61850-node@$NEW_VERSION version \
|
|
358
|
+
> /dev/null 2>&1; then
|
|
359
|
+
echo "Version $NEW_VERSION already exists in npm. Skipping publish."
|
|
360
|
+
else
|
|
361
|
+
npm publish --access public
|
|
362
|
+
echo "Published @amigo9090/ih-libiec61850-node@$NEW_VERSION"
|
|
363
|
+
fi
|
|
364
|
+
|
|
365
|
+
git tag v$NEW_VERSION
|
|
366
|
+
git push origin v$NEW_VERSION
|
|
367
|
+
git checkout -- package.json
|
|
@@ -552,33 +552,36 @@ async function handleConnectionOpened2() {
|
|
|
552
552
|
async function exploreModel() {
|
|
553
553
|
try {
|
|
554
554
|
console.log('\n=== 1. Получение корневых узлов ===');
|
|
555
|
-
const rootNodes = await client.browseDataModel();
|
|
556
|
-
|
|
555
|
+
const rootNodes = await client.browseDataModel(); // теперь только name, reference, type
|
|
556
|
+
|
|
557
557
|
console.log('\nНайдено Logical Nodes:');
|
|
558
|
-
|
|
559
|
-
console.log(`\n${
|
|
560
|
-
|
|
561
|
-
//
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
558
|
+
for (const ln of rootNodes) {
|
|
559
|
+
console.log(`\n${ln.name} (${ln.reference})`);
|
|
560
|
+
|
|
561
|
+
// Получаем детальную информацию о логическом узле
|
|
562
|
+
const lnDetails = await client.browseDataModel(ln.reference);
|
|
563
|
+
|
|
564
|
+
// Выводим DataSets
|
|
565
|
+
if (lnDetails.dataSets && lnDetails.dataSets.length > 0) {
|
|
566
|
+
console.log(` Datasets (${lnDetails.dataSets.length}):`);
|
|
567
|
+
lnDetails.dataSets.forEach((ds, idx) => {
|
|
565
568
|
console.log(` ${idx + 1}. ${ds.name}: ${ds.reference}`);
|
|
566
569
|
});
|
|
567
570
|
} else {
|
|
568
571
|
console.log(` Datasets: 0`);
|
|
569
572
|
}
|
|
570
|
-
|
|
571
|
-
// Выводим
|
|
572
|
-
if (
|
|
573
|
-
console.log(` Reports (${
|
|
574
|
-
|
|
573
|
+
|
|
574
|
+
// Выводим Reports
|
|
575
|
+
if (lnDetails.reports && lnDetails.reports.length > 0) {
|
|
576
|
+
console.log(` Reports (${lnDetails.reports.length}):`);
|
|
577
|
+
lnDetails.reports.forEach((report, idx) => {
|
|
575
578
|
const typeDesc = report.type === 'RP' ? 'Unbuffered' : 'Buffered';
|
|
576
579
|
console.log(` ${idx + 1}. ${report.name} (${report.type} - ${typeDesc}): ${report.reference}`);
|
|
577
580
|
});
|
|
578
581
|
} else {
|
|
579
582
|
console.log(` Reports: 0`);
|
|
580
583
|
}
|
|
581
|
-
}
|
|
584
|
+
}
|
|
582
585
|
|
|
583
586
|
// Выбираем LLN0 для дальнейшего исследования
|
|
584
587
|
const lln0 = rootNodes.find(ln => ln.name === 'LLN0');
|
|
@@ -595,23 +598,18 @@ async function exploreModel() {
|
|
|
595
598
|
console.log(`${index + 1}. ${doObj.name} (${doObj.cdc || 'Unknown'}) - ${doObj.reference}`);
|
|
596
599
|
});
|
|
597
600
|
|
|
601
|
+
// Выбираем первый DataSet для кэширования
|
|
598
602
|
// Выбираем первый DataSet для кэширования
|
|
599
603
|
if (lln0Details.dataSets.length > 0) {
|
|
600
604
|
const firstDataSet = lln0Details.dataSets[0];
|
|
601
605
|
console.log(`\n=== 3. Кэшируем DataSet ${firstDataSet.reference} ===`);
|
|
602
|
-
const dsDetails = await client.browseDataModel(firstDataSet.reference);
|
|
603
606
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
console.log(` Членов: ${dsDetails.memberCount}`);
|
|
607
|
-
console.log('\n Все члены:');
|
|
608
|
-
dsDetails.members.forEach((member, index) => {
|
|
609
|
-
console.log(` ${index + 1}. ${member.reference}`);
|
|
610
|
-
});
|
|
607
|
+
// ✅ ПРАВИЛЬНО: вызываем readDataSetModel для заполнения кэша структур
|
|
608
|
+
await client.readDataSetModel([firstDataSet.reference]);
|
|
611
609
|
|
|
612
|
-
// Теперь
|
|
610
|
+
// Теперь можно быстро читать этот DataSet
|
|
613
611
|
console.log('\n=== 4. Быстрое чтение DataSet ===');
|
|
614
|
-
const pollResults = await client.pollDataSetValues([firstDataSet.reference]);
|
|
612
|
+
const pollResults = await client.pollDataSetValues([firstDataSet.reference]);
|
|
615
613
|
|
|
616
614
|
console.log('\nPoll results:');
|
|
617
615
|
pollResults.forEach((result, idx) => {
|
package/examples/test2.js
CHANGED
|
@@ -29,8 +29,8 @@ const client = new MmsClient((event, data) => {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
if (event === 'conn' && data.event === 'opened') {
|
|
32
|
-
logWithTime('Connection opened, starting
|
|
33
|
-
|
|
32
|
+
logWithTime('Connection opened, starting concurrent tasks...');
|
|
33
|
+
runConcurrentTasks().catch(err => logWithTime('Error in concurrent tasks:', err));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
if (event === 'data' && data.type === 'error') {
|
|
@@ -44,29 +44,29 @@ const client = new MmsClient((event, data) => {
|
|
|
44
44
|
|
|
45
45
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
46
46
|
|
|
47
|
-
async function
|
|
47
|
+
async function runConcurrentTasks() {
|
|
48
48
|
try {
|
|
49
|
-
// 1. Получаем модель данных
|
|
50
|
-
logWithTime('Step 1: Browsing data model...');
|
|
49
|
+
// 1. Получаем модель данных (один раз для поиска ресурсов)
|
|
50
|
+
logWithTime('Step 1: Browsing data model to find dataset and report...');
|
|
51
51
|
const browseStart = now();
|
|
52
52
|
const dataModel = await client.browseDataModel();
|
|
53
|
-
logWithTime(`
|
|
53
|
+
logWithTime(`Initial browse completed in ${now() - browseStart} ms`);
|
|
54
54
|
|
|
55
|
-
//
|
|
56
|
-
logWithTime('Data model structure (first 2 nodes):',
|
|
57
|
-
util.inspect(dataModel.slice(0, 2), { depth: 4, colors: true }));
|
|
58
|
-
|
|
59
|
-
// 2. Ищем подходящие DataSet и отчеты
|
|
55
|
+
// 2. Ищем подходящие DataSet и отчет
|
|
60
56
|
let targetDataset = null;
|
|
61
57
|
let targetReport = null;
|
|
62
58
|
|
|
63
|
-
// Сначала ищем DataSet (берём первый)
|
|
64
59
|
for (const ln of dataModel) {
|
|
65
|
-
if (ln.dataSets && ln.dataSets.length > 0) {
|
|
60
|
+
if (ln.dataSets && ln.dataSets.length > 0 && !targetDataset) {
|
|
66
61
|
targetDataset = ln.dataSets[0];
|
|
67
62
|
logWithTime(`Found dataset: ${targetDataset.reference}`);
|
|
68
|
-
break;
|
|
69
63
|
}
|
|
64
|
+
if (ln.reports && ln.reports.length > 0 && !targetReport) {
|
|
65
|
+
// Берем первый отчет (позже уточним, ссылается ли он на наш dataset)
|
|
66
|
+
targetReport = ln.reports[0];
|
|
67
|
+
logWithTime(`Found potential report: ${targetReport.reference}`);
|
|
68
|
+
}
|
|
69
|
+
if (targetDataset && targetReport) break;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (!targetDataset) {
|
|
@@ -74,95 +74,119 @@ async function runDiagnostics() {
|
|
|
74
74
|
return;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
logWithTime(`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (details.datasetRef === targetDataset.reference) {
|
|
86
|
-
targetReport = details;
|
|
87
|
-
logWithTime(`Found matching report: ${report.reference} (dataset: ${details.datasetRef})`);
|
|
88
|
-
break;
|
|
89
|
-
}
|
|
90
|
-
} catch (err) {
|
|
91
|
-
logWithTime(`Error getting details for report ${report.reference}: ${err.message}`);
|
|
92
|
-
}
|
|
77
|
+
// Уточняем детали отчета (чтобы получить datasetRef)
|
|
78
|
+
let reportDetails = null;
|
|
79
|
+
if (targetReport) {
|
|
80
|
+
try {
|
|
81
|
+
reportDetails = await client.browseDataModel(targetReport.reference);
|
|
82
|
+
logWithTime(`Report details: datasetRef = ${reportDetails.datasetRef || 'none'}`);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
logWithTime(`Failed to get report details: ${err.message}`);
|
|
93
85
|
}
|
|
94
|
-
if (targetReport) break;
|
|
95
86
|
}
|
|
96
87
|
|
|
97
|
-
// Если не
|
|
98
|
-
if (!
|
|
88
|
+
// Если отчет не ссылается на наш dataset, ищем другой
|
|
89
|
+
if (!reportDetails || reportDetails.datasetRef !== targetDataset.reference) {
|
|
90
|
+
logWithTime('Initial report does not match dataset, searching for matching report...');
|
|
91
|
+
let found = false;
|
|
99
92
|
for (const ln of dataModel) {
|
|
100
|
-
if (!ln.reports
|
|
101
|
-
for (const
|
|
93
|
+
if (!ln.reports) continue;
|
|
94
|
+
for (const rpt of ln.reports) {
|
|
102
95
|
try {
|
|
103
|
-
const details = await client.browseDataModel(
|
|
104
|
-
if (details.datasetRef) {
|
|
105
|
-
targetReport =
|
|
106
|
-
|
|
96
|
+
const details = await client.browseDataModel(rpt.reference);
|
|
97
|
+
if (details.datasetRef === targetDataset.reference) {
|
|
98
|
+
targetReport = rpt;
|
|
99
|
+
reportDetails = details;
|
|
100
|
+
found = true;
|
|
101
|
+
logWithTime(`Found matching report: ${targetReport.reference} (dataset: ${details.datasetRef})`);
|
|
107
102
|
break;
|
|
108
103
|
}
|
|
109
104
|
} catch (err) {
|
|
110
|
-
|
|
105
|
+
// ignore
|
|
111
106
|
}
|
|
112
107
|
}
|
|
113
|
-
if (
|
|
108
|
+
if (found) break;
|
|
109
|
+
}
|
|
110
|
+
if (!found) {
|
|
111
|
+
logWithTime('No report matching the dataset found, will continue without reporting.');
|
|
112
|
+
targetReport = null;
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
// 3.
|
|
116
|
+
// 3. Кэшируем DataSet (readDataSetModel)
|
|
118
117
|
logWithTime(`Step 2: Caching dataset ${targetDataset.reference}...`);
|
|
119
118
|
const cacheStart = now();
|
|
120
119
|
await client.readDataSetModel([targetDataset.reference]);
|
|
121
120
|
logWithTime(`Caching completed in ${now() - cacheStart} ms`);
|
|
122
121
|
|
|
123
|
-
// 4. Включаем
|
|
124
|
-
if (targetReport) {
|
|
125
|
-
logWithTime(`Step 3: Enabling report ${targetReport.reference} with dataset ${
|
|
122
|
+
// 4. Включаем отчет, если найден
|
|
123
|
+
if (targetReport && reportDetails && reportDetails.datasetRef) {
|
|
124
|
+
logWithTime(`Step 3: Enabling report ${targetReport.reference} with dataset ${reportDetails.datasetRef}...`);
|
|
126
125
|
const enableStart = now();
|
|
127
|
-
await client.enableReporting(targetReport.reference,
|
|
126
|
+
await client.enableReporting(targetReport.reference, reportDetails.datasetRef);
|
|
128
127
|
logWithTime(`Reporting enabled in ${now() - enableStart} ms`);
|
|
129
128
|
} else {
|
|
130
129
|
logWithTime('No suitable report found, skipping report enabling.');
|
|
131
130
|
}
|
|
132
131
|
|
|
133
|
-
// 5. Запускаем
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
// 5. Запускаем параллельные задачи:
|
|
133
|
+
// - Поллинг каждые 2 секунды
|
|
134
|
+
// - Сканирование модели каждые 5 секунд
|
|
135
|
+
// - Основной цикл на 30 секунд
|
|
136
|
+
logWithTime('Step 4: Starting concurrent tasks (polling every 2s, browsing every 5s) for 30 seconds...');
|
|
137
137
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
logWithTime(`
|
|
153
|
-
}
|
|
138
|
+
let stop = false;
|
|
139
|
+
let pollCount = 0;
|
|
140
|
+
let browseCount = 0;
|
|
141
|
+
|
|
142
|
+
// Задача поллинга
|
|
143
|
+
const pollTask = (async () => {
|
|
144
|
+
while (!stop) {
|
|
145
|
+
const start = now();
|
|
146
|
+
try {
|
|
147
|
+
const results = await client.pollDataSetValues([targetDataset.reference]);
|
|
148
|
+
const duration = now() - start;
|
|
149
|
+
if (results && results[0]) {
|
|
150
|
+
const res = results[0];
|
|
151
|
+
if (res.isValid) {
|
|
152
|
+
logWithTime(`[POLL #${++pollCount}] duration=${duration}ms, readTime=${res.readTimeMicros}µs, processTime=${res.processTimeMicros}µs, values=${res.count}`);
|
|
153
|
+
} else {
|
|
154
|
+
logWithTime(`[POLL #${++pollCount}] ERROR: ${res.errorReason}`);
|
|
155
|
+
}
|
|
154
156
|
} else {
|
|
155
|
-
logWithTime(`
|
|
157
|
+
logWithTime(`[POLL #${++pollCount}] no results`);
|
|
156
158
|
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
logWithTime(`[POLL #${++pollCount}] exception: ${err.message}`);
|
|
157
161
|
}
|
|
158
|
-
|
|
159
|
-
logWithTime(`Poll exception: ${err.message}`);
|
|
162
|
+
await sleep(2000);
|
|
160
163
|
}
|
|
164
|
+
})();
|
|
161
165
|
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
// Задача сканирования модели
|
|
167
|
+
const browseTask = (async () => {
|
|
168
|
+
while (!stop) {
|
|
169
|
+
const start = now();
|
|
170
|
+
try {
|
|
171
|
+
await client.browseDataModel();
|
|
172
|
+
const duration = now() - start;
|
|
173
|
+
logWithTime(`[BROWSE #${++browseCount}] completed in ${duration}ms`);
|
|
174
|
+
} catch (err) {
|
|
175
|
+
logWithTime(`[BROWSE #${++browseCount}] error: ${err.message}`);
|
|
176
|
+
}
|
|
177
|
+
await sleep(5000);
|
|
178
|
+
}
|
|
179
|
+
})();
|
|
180
|
+
|
|
181
|
+
// Ждём 60 секунд
|
|
182
|
+
await sleep(60000);
|
|
183
|
+
stop = true;
|
|
184
|
+
|
|
185
|
+
// Дожидаемся завершения задач (с таймаутом)
|
|
186
|
+
await Promise.race([pollTask, browseTask]);
|
|
187
|
+
logWithTime('Concurrent tasks stopped.');
|
|
164
188
|
|
|
165
|
-
// 6. Отключаем
|
|
189
|
+
// 6. Отключаем отчет, если был включен
|
|
166
190
|
if (targetReport) {
|
|
167
191
|
logWithTime('Step 5: Disabling report...');
|
|
168
192
|
const disableStart = now();
|
|
@@ -170,16 +194,17 @@ async function runDiagnostics() {
|
|
|
170
194
|
logWithTime(`Report disabled in ${now() - disableStart} ms`);
|
|
171
195
|
}
|
|
172
196
|
|
|
173
|
-
logWithTime('
|
|
197
|
+
logWithTime('All tasks completed. Closing client...');
|
|
174
198
|
await client.close();
|
|
175
199
|
logWithTime('Client closed.');
|
|
176
200
|
|
|
177
201
|
} catch (err) {
|
|
178
|
-
logWithTime(`Fatal error
|
|
202
|
+
logWithTime(`Fatal error: ${err.stack}`);
|
|
203
|
+
await client.close().catch(e => logWithTime(`Close error: ${e.message}`));
|
|
179
204
|
}
|
|
180
205
|
}
|
|
181
206
|
|
|
182
|
-
//
|
|
207
|
+
// Подключение
|
|
183
208
|
logWithTime('Starting client...');
|
|
184
209
|
try {
|
|
185
210
|
client.connect({
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const { MmsClient } = require('../build/Release/addon_iec61850');
|
|
2
|
+
|
|
3
|
+
const client = new MmsClient((event, data) => {
|
|
4
|
+
// Обработчик событий – реагируем только на успешное открытие соединения
|
|
5
|
+
if (event === 'conn' && data.event === 'opened') {
|
|
6
|
+
console.log('Connected, browsing data model...');
|
|
7
|
+
browseModel();
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async function browseModel() {
|
|
14
|
+
try {
|
|
15
|
+
const model = await client.browseDataModel();
|
|
16
|
+
// Выводим первые 5 элементов модели для краткости (или весь объект)
|
|
17
|
+
console.log('Data model (first 5 nodes):');
|
|
18
|
+
console.log(JSON.stringify(model.slice(0, 5), null, 2));
|
|
19
|
+
// Если нужно всё: console.log(JSON.stringify(model, null, 2));
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error('Browse error:', err);
|
|
22
|
+
} finally {
|
|
23
|
+
await client.close();
|
|
24
|
+
console.log('Client closed.');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Подключение к серверу (при необходимости измените IP и порт)
|
|
29
|
+
client.connect({
|
|
30
|
+
ip: '192.168.0.106',
|
|
31
|
+
port: 102,
|
|
32
|
+
clientID: 'test_checker',
|
|
33
|
+
reconnectDelay: 2
|
|
34
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amigo9090/ih-libiec61850-node",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.58",
|
|
4
4
|
"description": "Node.js addon for IEC 61850 client (MMS, GOOSE) using libiec61850",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"addon",
|
|
9
9
|
"cross-platform"
|
|
10
10
|
],
|
|
11
|
-
"author": "
|
|
11
|
+
"author": "Amigo909090",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"files": [
|
|
14
14
|
"index.js",
|
|
@@ -31,15 +31,15 @@
|
|
|
31
31
|
],
|
|
32
32
|
"repository": {
|
|
33
33
|
"type": "git",
|
|
34
|
-
"url": "git+https://github.com/
|
|
34
|
+
"url": "git+https://github.com/Amigo909090/ih-lib61850-node.git"
|
|
35
35
|
},
|
|
36
|
-
"homepage": "https://github.com/
|
|
36
|
+
"homepage": "https://github.com/Amigo909090/ih-lib61850-node#readme",
|
|
37
37
|
"directories": {
|
|
38
38
|
"example": "examples",
|
|
39
39
|
"lib": "lib"
|
|
40
40
|
},
|
|
41
41
|
"gypfile": true,
|
|
42
42
|
"bugs": {
|
|
43
|
-
"url": "https://github.com/
|
|
43
|
+
"url": "https://github.com/Amigo909090/ih-lib61850-node/issues"
|
|
44
44
|
}
|
|
45
45
|
}
|