@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.
@@ -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
- rootNodes.forEach((ln, index) => {
559
- console.log(`\n${index + 1}. ${ln.name} (${ln.reference})`);
560
-
561
- // Выводим ВСЕ датасеты
562
- if (ln.dataSets && ln.dataSets.length > 0) {
563
- console.log(` Datasets (${ln.dataSets.length}):`);
564
- ln.dataSets.forEach((ds, idx) => {
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 (ln.reports && ln.reports.length > 0) {
573
- console.log(` Reports (${ln.reports.length}):`);
574
- ln.reports.forEach((report, idx) => {
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
- console.log(`\nDataSet ${dsDetails.reference}:`);
605
- console.log(` Удаляемый: ${dsDetails.isDeletable}`);
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
- // Теперь можем быстро читать этот DataSet
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 diagnostics...');
33
- runDiagnostics().catch(err => logWithTime('Diagnostics error:', err));
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 runDiagnostics() {
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(`Browse completed in ${now() - browseStart} ms`);
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
- // Теперь ищем отчёт, который ссылается на этот DataSet
78
- for (const ln of dataModel) {
79
- if (!ln.reports || ln.reports.length === 0) continue;
80
-
81
- for (const report of ln.reports) {
82
- logWithTime(`Getting details for report ${report.reference}...`);
83
- try {
84
- const details = await client.browseDataModel(report.reference);
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
- // Если не нашли подходящий, возьмём любой отчёт с datasetRef
98
- if (!targetReport) {
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 || ln.reports.length === 0) continue;
101
- for (const report of ln.reports) {
93
+ if (!ln.reports) continue;
94
+ for (const rpt of ln.reports) {
102
95
  try {
103
- const details = await client.browseDataModel(report.reference);
104
- if (details.datasetRef) {
105
- targetReport = details;
106
- logWithTime(`Found any report with dataset: ${report.reference} (dataset: ${details.datasetRef})`);
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
- logWithTime(`Error getting details for report ${report.reference}: ${err.message}`);
105
+ // ignore
111
106
  }
112
107
  }
113
- if (targetReport) break;
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. Первичное чтение и кэширование DataSet (readDataSetModel)
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 ${targetReport.datasetRef}...`);
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, targetReport.datasetRef);
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. Запускаем цикл поллинга (10 итераций с интервалом 2 сек)
134
- logWithTime('Step 4: Starting polling loop (10 iterations, 2 sec interval)...');
135
- for (let i = 0; i < 10; i++) {
136
- logWithTime(`--- Poll iteration ${i+1} ---`);
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
- const pollStart = now();
139
- try {
140
- const pollResults = await client.pollDataSetValues([targetDataset.reference]);
141
- const pollEnd = now();
142
- logWithTime(`Poll completed in ${pollEnd - pollStart} ms`);
143
-
144
- if (pollResults && pollResults[0]) {
145
- const res = pollResults[0];
146
- if (res.isValid) {
147
- logWithTime(` Read time (µs): ${res.readTimeMicros}, Process time (µs): ${res.processTimeMicros}`);
148
- logWithTime(` Values count: ${res.count}`);
149
- // Выводим первые 3 значения для проверки
150
- const entries = Object.entries(res.values).slice(0, 3);
151
- entries.forEach(([ref, val]) => {
152
- logWithTime(` ${ref}: ${util.inspect(val, { depth: 2 })}`);
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(` Poll error: ${res.errorReason}`);
157
+ logWithTime(`[POLL #${++pollCount}] no results`);
156
158
  }
159
+ } catch (err) {
160
+ logWithTime(`[POLL #${++pollCount}] exception: ${err.message}`);
157
161
  }
158
- } catch (err) {
159
- logWithTime(`Poll exception: ${err.message}`);
162
+ await sleep(2000);
160
163
  }
164
+ })();
161
165
 
162
- await sleep(2000);
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('Diagnostics completed. Closing client...');
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 in diagnostics: ${err.stack}`);
202
+ logWithTime(`Fatal error: ${err.stack}`);
203
+ await client.close().catch(e => logWithTime(`Close error: ${e.message}`));
179
204
  }
180
205
  }
181
206
 
182
- // Подключаемся к устройству (без .catch, так как connect не возвращает Promise)
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.56",
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": "Amigo9090",
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/intrahouseio/ih-lib61850-node.git"
34
+ "url": "git+https://github.com/Amigo909090/ih-lib61850-node.git"
35
35
  },
36
- "homepage": "https://github.com/intrahouseio/ih-lib61850-node#readme",
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/intrahouseio/ih-lib61850-node/issues"
43
+ "url": "https://github.com/Amigo909090/ih-lib61850-node/issues"
44
44
  }
45
45
  }