Compare commits

...
127 Commits
Author SHA1 Message Date
fengzeroz 71d93753f5 Merge pull request #2312 from fengzeroz/v2.9
version: 2.9.5
2024-11-11 17:07:30 +08:00
fengzero 639c55ea97 version: 2.9.5 2024-11-11 09:05:34 +00:00
fengzeroz 5b7724bdfe Merge pull request #2308 from fengzeroz/v2.9
conn buf size: 8192
2024-11-11 16:30:50 +08:00
fengzero a420e91048 conn buf size: 8192 2024-11-11 08:29:21 +00:00
fengzeroz 1a5a8e0b8a Merge pull request #2283 from fengzeroz/v2.9
mqtt port limit
2024-11-04 16:58:01 +08:00
fengzero 206c3055ed mqtt port limit 2024-11-04 08:53:04 +00:00
fengzeroz cc32019de9 Merge pull request #2272 from hxy7yx/v2.9-2
[2.9]fix(write):correct write value verification
2024-11-01 11:39:39 +08:00
fengzeroz 919a24f264 Merge pull request #2276 from fengzeroz/v2.9
V2.9
2024-11-01 11:36:58 +08:00
fengzero 9d0ee222d0 update_im: not check subscribe 2024-11-01 03:35:53 +00:00
fengzero bd49739b39 Revert "cyclic reporting does not detect change"
This reverts commit 2d230366a1.
2024-11-01 03:35:14 +00:00
hxy7yx 0e87862532 fix(write):correct write value verification 2024-11-01 11:22:38 +08:00
fengzeroz f7a5604047 Merge pull request #2259 from fengzeroz/v2.9
version: 2.9.4
2024-10-21 14:02:18 +08:00
fengzero 69ca20eb37 version: 2.9.4 2024-10-21 05:59:20 +00:00
fengzeroz ca444a71c1 Merge pull request #2245 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-09-26 14:28:14 +08:00
fengzero 2d230366a1 cyclic reporting does not detect change 2024-09-26 06:27:41 +00:00
fengzeroz 0789deb82a Merge pull request #2222 from hxy7yx/v2.9-1
[2.9]fix(read paginate):handle only_write tags
2024-09-19 10:46:14 +08:00
fengzeroz 12c8046301 Merge pull request #2225 from fengzeroz/v2.9
Revert "cyclic reporting does not detect change"
2024-09-19 10:15:29 +08:00
fengzero ccf61815d0 Revert "cyclic reporting does not detect change"
This reverts commit 99309d2695.
2024-09-19 02:10:44 +00:00
hxy7yx 9bf877a8e7 fix(read paginate):handle only_write tags 2024-09-18 16:31:09 +08:00
fengzeroz 3b98edebe3 Merge pull request #2215 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-09-14 10:23:05 +08:00
fengzero 99309d2695 cyclic reporting does not detect change 2024-09-14 02:22:06 +00:00
fengzeroz 2e1444573c Merge pull request #2205 from fengzeroz/v2.9
ci: clang-format
2024-09-09 11:08:27 +08:00
fengzero 367e0a9842 ci: clang-format 2024-09-09 02:58:41 +00:00
fengzeroz 7ae3aa6fca Merge pull request #2193 from fengzeroz/v2.9
version: 2.9.3
2024-08-28 14:23:29 +08:00
fengzero 7305df4117 version: 2.9.3 2024-08-28 06:22:25 +00:00
fengzeroz 7d96187cf9 Merge pull request #2189 from ZhouBox/v2.9
[v2.9]add api about doing with basic data type
2024-08-22 16:46:31 +08:00
xiang.zhou 10acec6836 add api about doing with basic data type 2024-08-21 18:11:48 +08:00
fengzeroz 0ab902edd9 Merge pull request #2185 from hxy7yx/v2.9-1
[v2.9]chore(mqtt): add reason for connection & disconnection
2024-08-20 16:19:37 +08:00
hxy7yx 3398c2ff69 chore(mqtt): add reason for connection & disconnection 2024-08-20 14:44:04 +08:00
fengzeroz c7b9381252 Merge pull request #2182 from fengzeroz/v2.9
Revert "cyclic reporting does not detect change"
2024-08-16 10:05:57 +08:00
fengzero 18da977187 Revert "cyclic reporting does not detect change"
This reverts commit 109257c928.
2024-08-16 02:04:49 +00:00
fengzeroz b5b3a9a0bc Merge pull request #2181 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-08-15 15:10:36 +08:00
fengzero 109257c928 cyclic reporting does not detect change 2024-08-15 07:09:55 +00:00
fengzeroz cd59eccf89 Merge pull request #2175 from hxy7yx/v2.9-1
[v2.9] guard against empty mqtt subscription topic
2024-08-15 10:02:57 +08:00
hxy7yx 2b9daee95c guard against empty mqtt subscription topic 2024-08-14 14:44:01 +08:00
fengzeroz f8d92f22e3 Merge pull request #2172 from eeff/v2.9
Pick to v2.9 feat(mqtt): remove mqtt cache db when node deleted
2024-08-07 10:11:01 +08:00
eeff f3e39e8325 feat(mqtt): remove mqtt cache db when node deleted 2024-08-01 15:59:05 +08:00
fengzeroz 93effef50a Merge pull request #2170 from fengzeroz/v2.9
version: 2.9.2
2024-07-30 15:03:14 +08:00
fengzero c7fd967d89 version: 2.9.2 2024-07-30 07:02:39 +00:00
fengzeroz 3fd7670ff1 Merge pull request #2169 from hxy7yx/v2.9-2
[v2.9]feat(modbus tcp):configure optional message header verification
2024-07-30 15:01:43 +08:00
hxy7yx b64f323fcc feat(modbus tcp):configure optional message header verification 2024-07-29 14:38:01 +08:00
fengzeroz beb19a14dc Merge pull request #2152 from hxy7yx/v2.9-1
[v2.9]feat:core subscription supports filtering error tags
2024-07-29 14:30:22 +08:00
hxy7yx 67c32c6f15 feat:core subscription supports filtering error messages 2024-07-26 14:55:53 +08:00
fengzeroz 4d952e2ea0 Merge pull request #2162 from ZhouBox/v2.9
[v2.9]feat(rest):add api about configure status
2024-07-24 13:59:09 +08:00
xiang.zhou bb3b17faf2 feat(rest):add api about configure status 2024-07-24 11:38:30 +08:00
fengzeroz 4b0ee30be8 Merge pull request #2156 from hxy7yx/v2.9-2
[v2.9]fix(modbus):reconnect when recv error messages
2024-07-24 10:23:41 +08:00
hxy7yx f3cfadd3e8 fix(modbus):reconnect when recv error messages 2024-07-23 16:49:36 +08:00
hxy7yx 6ff4ad52d8 feat:core subscription supports filtering error messages 2024-07-23 15:53:09 +08:00
fengzeroz d39aa057bd Merge pull request #2146 from fengzeroz/v2.9
Revert "cyclic reporting does not detect change"
2024-07-18 10:15:04 +08:00
fengzero 55c2a05d03 Revert "cyclic reporting does not detect change"
This reverts commit 458af374bb.
2024-07-18 02:14:28 +00:00
fengzeroz d07735be93 Merge pull request #2143 from hxy7yx/v2.9-1
refactor(read paginate): optimize efficiency without filtering errors
2024-07-18 10:11:56 +08:00
hxy7yx 1db02f1573 refactor(read paginate): optimize efficiency without filtering errors 2024-07-15 14:55:09 +08:00
fengzeroz 707029bee2 Merge pull request #2140 from fengzeroz/v2.9
cyclic reporting does not detect change
2024-07-15 10:20:57 +08:00
fengzero 458af374bb cyclic reporting does not detect change 2024-07-15 02:20:25 +00:00
fengzeroz 09da1cdab6 Merge pull request #2138 from fengzeroz/v2.9
version: 2.9.1
2024-07-12 09:43:05 +08:00
fengzero 35849a00a9 version: 2.9.1 2024-07-12 01:42:11 +00:00
fengzeroz 305cb7449a Merge pull request #2134 from eeff/v2.9
Pick to v2.9 fix(core): set metric to init value when reset
2024-07-10 10:08:23 +08:00
eeff 9467bdaa36 fix(core): set metric to init value when reset 2024-07-10 10:01:02 +08:00
fengzeroz 79dde6ecf4 Merge pull request #2129 from eeff/v2.9
Pick to v2.9 fix(core): event loop check stop flag
2024-07-04 16:17:48 +08:00
eeff d71f240ec7 fix(core): event loop check stop flag 2024-07-04 16:15:19 +08:00
fengzeroz 47af1617a8 Merge pull request #2126 from fengzeroz/v2.9
version: 2.9.0
2024-07-01 11:18:16 +08:00
fengzero 4b54f98177 version: 2.9.0 2024-07-01 03:17:32 +00:00
fengzeroz ad3ad077b2 Merge pull request #2121 from eeff/v2.9
Pick to v2.9 chore: add error code `NEU_ERR_BODY_TOO_BIG`
2024-07-01 09:56:45 +08:00
eeff a50d3416ee chore: add error code NEU_ERR_BODY_TOO_BIG 2024-06-27 00:17:35 +08:00
fengzeroz fbe538ed91 Merge pull request #2113 from ZhouBox/v2.9
[v2.9]add notice log about node,group,sub
2024-06-25 14:18:43 +08:00
xiang.zhou 0f8d70d024 add notice log about node,group,sub 2024-06-18 16:59:55 +08:00
fengzeroz 7a534bc95e Merge pull request #2110 from fengzeroz/v2.9
version: 2.9.0-beta3
2024-06-18 15:58:37 +08:00
fengzero bf094f2731 version: 2.9.0-beta3 2024-06-18 07:47:25 +00:00
fengzeroz 9e99a662ba Merge pull request #2107 from hxy7yx/v2.9-2
[v2.9]rename precision when read floating-tag
2024-06-18 13:59:02 +08:00
hxy7yx 9e4ba7e51d rename precision when read floating-tag 2024-06-18 13:49:35 +08:00
fengzeroz c3a198270d Merge pull request #2104 from fengzeroz/v2.9
version: 2.9.0-beta2
2024-06-14 15:45:24 +08:00
fengzero 202dc73e25 version: 2.9.0-beta2 2024-06-14 07:42:23 +00:00
fengzeroz db8a95d99e Merge pull request #2100 from hxy7yx/v2.9-2
[v2.9]fix(test read): stop group timer while testing
2024-06-14 15:28:01 +08:00
fengzeroz c3e85e8f45 Merge pull request #2102 from hxy7yx/v2.9-1
[v2.9]fix(manager): exit after sending uninit msg failed
2024-06-14 15:27:40 +08:00
hxy7yx 921c2d6c57 fix(manager): exit even if send uninit msg failed 2024-06-14 15:03:22 +08:00
hxy7yx ab7f39b63f fix(test read): stop group timer while testing 2024-06-14 11:18:04 +08:00
fengzeroz 49f4cccc2a Merge pull request #2091 from ZhouBox/v2.9
[v2.9]display optimization for float and double types when setting bias
2024-06-14 09:52:08 +08:00
fengzeroz 9a6c7c427a Merge pull request #2093 from eeff/v2.9
Pick to v2.9 feat(core): add `interval` field to struct neu_plugin_group
2024-06-14 09:51:40 +08:00
fengzeroz 9226da5f60 Merge pull request #2098 from eeff/eeff/fix
Pick to v2.9 fix(core): read_report_group add tag bias
2024-06-14 09:51:21 +08:00
eeff a13bb136c4 fix(core): read_report_group add tag bias 2024-06-13 15:17:03 +08:00
eeff 0ac53e159f feat(core): add interval field to struct neu_plugin_group 2024-06-13 15:00:46 +08:00
xiang.zhou cf10ec0ad9 display optimization for float and double types when setting bias 2024-06-13 13:59:47 +08:00
fengzeroz 0ad6f4fe56 Merge pull request #2090 from hxy7yx/v2.9-1
fix(write): write *.0
2024-06-13 13:45:48 +08:00
hxy7yx d96413b83c fix(write): write *.0 2024-06-13 10:55:37 +08:00
fengzeroz 3fb0388dfa Merge pull request #2083 from gc87/jwt-exp-v2.9
[v2.9]fix(jwt): replacing expired tokens
2024-06-11 16:16:00 +08:00
gc87 3799af3569 fix(jwt): replacing expired tokens 2024-06-11 14:53:27 +08:00
fengzeroz 9dde3e8b84 Merge pull request #2079 from ZhouBox/v2.9
[v2.9]async queue:add api about length
2024-06-07 15:43:15 +08:00
fengzeroz a803228ded Merge pull request #2081 from fengzeroz/v2.9
2.9.0-beta1
2024-06-07 15:42:56 +08:00
fengzero bf4f176f39 2.9.0-beta1 2024-06-07 07:42:09 +00:00
xiang.zhou 1c7a91394f async queue:add api about length 2024-06-07 15:24:22 +08:00
fengzeroz dc07471634 Merge pull request #2077 from hxy7yx/v2.9-1
[v2.9]ft(modbus):test read tag
2024-06-07 14:58:32 +08:00
hxy7yx 5f4fed39a1 ft(modbus):test read tag 2024-06-07 14:48:33 +08:00
fengzeroz 7f66db88c9 Merge pull request #2074 from hxy7yx/v2.9-1
[v2.9]feat(core & modbus tcp): test read tag
2024-06-07 10:10:54 +08:00
hxy7yx 4a0835cf40 feat(core & modbus tcp): test read tag 2024-06-06 17:25:48 +08:00
fengzeroz 830d670358 Merge pull request #2073 from fengzeroz/v2.9
set node start if loading node state is ready
2024-06-05 14:50:44 +08:00
fengzero b6cefdb5fa fix init msg state init 2024-06-05 06:36:32 +00:00
fengzero c00d085d85 start node if node state is ready 2024-06-05 06:29:30 +00:00
fengzeroz 1a972f57f4 Merge pull request #2068 from eeff/v2.9
Pick to v2.9 feat(mqtt): schema client-id and write req/resp topic default value
2024-06-05 10:43:33 +08:00
eeff fcbbacfd31 feat(mqtt): schema client-id and write req/resp topic default value 2024-06-05 10:41:06 +08:00
fengzeroz 9f291833f1 Merge pull request #2062 from hxy7yx/v2.9-3
[v2.9]read(filter): name(name || desc)
2024-06-04 15:55:19 +08:00
hxy7yx 76b6df700d read(filter): name(name || desc) 2024-06-04 15:43:03 +08:00
fengzeroz b9c2739abb Merge pull request #2059 from hxy7yx/v2.9-3
[v2.9]feat(read):support pagination and filter(error) when reading tags
2024-06-04 09:51:15 +08:00
hxy7yx 301c92bee7 feat(read):support pagination and filter(error) when reading tags 2024-06-03 18:07:39 +08:00
fengzeroz 05f21357b7 Merge pull request #2051 from hxy7yx/v2.9-3
[v2.9]fix: memory leak
2024-05-31 15:12:40 +08:00
hxy7yx eab24cf1b5 fix: memory leak 2024-05-31 14:43:18 +08:00
fengzeroz 8d72fc9e31 Merge pull request #2047 from fengzeroz/v2.9
fix(update): update error when value is error
2024-05-30 11:20:11 +08:00
fengzero bd36224fba fix(update): update error when value is error 2024-05-30 03:11:47 +00:00
fengzeroz 3f884cf6ba Merge pull request #2040 from hxy7yx/v2.9-2
[v2.9]check and handle NaN for float and double in read and report operations
2024-05-29 17:29:31 +08:00
hxy7yx df2f6b74e5 check and handle NaN for float and double in read and report operations 2024-05-29 16:56:08 +08:00
fengzeroz bc4a23688b Merge pull request #2032 from hxy7yx/v2.9-2
[v2.9]metric: reset send&recv bytes when restart node
2024-05-29 14:48:26 +08:00
fengzeroz d29996506a Merge pull request #2036 from eeff/v2.9
Pick to v2.9 fix: update trans_data metric only when plugin is started
2024-05-29 14:47:18 +08:00
eeff 34f071a8ee fix(mqtt): update trans_data metric only when plugin is started 2024-05-29 14:38:30 +08:00
eeff a3557cd0af fix(ekuiper): update trans_data metric only when plugin is started 2024-05-29 14:38:30 +08:00
hxy7yx 31ece9eecc metric: reset send&recv bytes when restart node 2024-05-29 13:34:53 +08:00
fengzeroz 0512edbb52 Merge pull request #2009 from gc87/scan-tags-v2.9
[v2.9]feat: add scan tags reqest & response
2024-05-24 09:48:28 +08:00
fengzeroz 87acec1ede Merge pull request #2020 from ZhouBox/v2.9
[v2.9]display optimization for float and double types
2024-05-24 09:47:21 +08:00
xiang.zhou 144a925932 display optimization for float and double types 2024-05-23 16:47:15 +08:00
gc87 ba07160fc5 feat: add scan tags api 2024-05-20 18:00:56 +08:00
gc87 8927be9f81 feat: add scan tags reqest & response 2024-05-20 17:02:53 +08:00
fengzeroz c08e3b314a Merge pull request #2005 from eeff/v2.9
Pick to v2.9 feat(aws-iot): remove config default value
2024-05-17 15:58:49 +08:00
eeff abbe8a8847 feat(aws-iot): remove config default value 2024-05-17 15:55:07 +08:00
fengzeroz de4a53635c Merge pull request #2001 from ZhouBox/v2.9
[v2.9]driver:change log level
2024-05-17 14:59:57 +08:00
xiang.zhou cb997d9cf6 driver:change log level 2024-05-17 14:33:10 +08:00
fengzeroz af900bb0d4 Merge pull request #2000 from ZhouBox/v2.9
[v2.9]ft(plugin):update version
2024-05-17 14:00:14 +08:00
xiang.zhou 050cf5aafe ft(plugin):update version 2024-05-17 12:05:43 +08:00
fengzeroz 4f1f49de0f Merge pull request #1998 from fengzeroz/v2.9
branch v2.9
2024-05-17 11:10:14 +08:00
fengzero 22339ee248 branch v2.9 2024-05-17 03:05:54 +00:00
73 changed files with 3972 additions and 634 deletions
+5 -39
View File
@@ -18,7 +18,7 @@ jobs:
submodules: recursive
- name: Run clang-format style check for C/C++ programs.
uses: DoozyX/clang-format-lint-action@v0.12
uses: DoozyX/clang-format-lint-action@v0.18
with:
source: 'src plugins include tests'
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h'
@@ -41,7 +41,7 @@ jobs:
ut:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-main
container: ghcr.io/neugates/build:x86_64-v2.9
steps:
- uses: actions/checkout@v4
@@ -60,25 +60,9 @@ jobs:
cd build
ctest --output-on-failure
- name: create cov report
run: |
sudo apt-get update
sudo apt-get -y install lcov
mkdir -p cov_report
./create_cov_report.sh ut
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
verbose: true
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./cov_report/
files: ./cov_report/cov-ut.info
pft:
runs-on: ubuntu-20.04
container: ghcr.io/neugates/build:x86_64-main
container: ghcr.io/neugates/build:x86_64-v2.9
strategy:
matrix:
plugin: [core, ekuiper, modbus, mqtt, azure, metrics]
@@ -90,9 +74,7 @@ jobs:
- name: setup dependencies
run: |
if [ "${{ matrix.plugin }}" = "mqtt" ] || [ "${{ matrix.plugin }}" = "azure" ]; then
sudo apt-get install -y mosquitto
fi
sudo apt-get install -y mosquitto
pip install -U pytest requests prometheus-client gmqtt pynng sniffio
sudo apt-get install -y socat
@@ -122,20 +104,4 @@ jobs:
pytest -s -v tests/ft/app/"test_azure.py"
else
pytest -s -v tests/ft/metrics/"test_metrics.py"
fi
- name: create cov report
run: |
sudo apt-get update
sudo apt-get -y install lcov
mkdir -p cov_report
./create_cov_report.sh ${{ matrix.plugin }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
verbose: true
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
directory: ./cov_report/
files: ./cov_report/cov-${{ matrix.plugin }}.info
fi
+4 -4
View File
@@ -8,9 +8,9 @@ on:
- published
env:
VERSION: 2.7.0
VERSION: 2.9.5
UI_VERSION: 2.6.1
BRANCH: main
BRANCH: v2.9
jobs:
cross-build:
@@ -21,7 +21,7 @@ jobs:
- [aarch64-linux-gnu, aarch64, arm64]
- [arm-linux-gnueabihf, armv4, armhf]
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-main
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.9
steps:
- uses: actions/checkout@v4
@@ -64,7 +64,7 @@ jobs:
matrix:
arch:
- [x86_64-linux-gnu, x86_64, amd64]
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-main
container: ghcr.io/neugates/build:${{ matrix.arch[1] }}-v2.9
steps:
- uses: actions/checkout@v4
+2 -1
View File
@@ -114,7 +114,7 @@ target_include_directories(neuron-base
PRIVATE include/neuron src)
target_link_libraries(neuron-base libssl.a libcrypto.a)
target_link_libraries(neuron-base nng libzlog.so jansson jwt
${CMAKE_THREAD_LIBS_INIT})
${CMAKE_THREAD_LIBS_INIT} -lm)
add_dependencies(neuron-base neuron-version)
# dependency imposed by nng
@@ -147,6 +147,7 @@ set(NEURON_SOURCES
plugins/restful/group_config_handle.c
plugins/restful/plugin_handle.c
plugins/restful/version_handle.c
plugins/restful/scan_handle.c
plugins/restful/rest.c
plugins/restful/user.c)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX aarch64-linux-gnu)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.9/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX arm-linux-gnueabi)
set(CMAKE_SYSTEM_PROCESSOR armv5tejl)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.9/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX arm-linux-gnueabihf)
set(CMAKE_SYSTEM_PROCESSOR armv7l)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.9/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+1 -1
View File
@@ -1,7 +1,7 @@
set(CMAKE_SYSTEM_NAME Linux)
set(COMPILER_PREFIX x86_64-linux-gnu)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(LIBRARY_DIR /home/neuron/main/libs)
set(LIBRARY_DIR /home/neuron/v2.9/libs)
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
+7
View File
@@ -65,6 +65,13 @@ typedef struct adapter_callbacks {
void (*update_im)(neu_adapter_t *adapter, const char *group,
const char *tag, neu_dvalue_t value,
neu_tag_meta_t *metas, int n_meta);
void (*scan_tags_response)(neu_adapter_t *adapter, void *r,
int error, void *tags, neu_type_e type,
bool is_array);
void (*test_read_tag_response)(neu_adapter_t *adapter, void *r,
neu_json_type_e t, neu_type_e type,
neu_json_value_u value,
int64_t error);
} driver;
};
} adapter_callbacks_t;
+20 -19
View File
@@ -85,25 +85,26 @@ bool neu_mqtt_client_is_open(neu_mqtt_client_t *client);
bool neu_mqtt_client_is_connected(neu_mqtt_client_t *client);
size_t neu_mqtt_client_get_cached_msgs_num(neu_mqtt_client_t *client);
int neu_mqtt_client_set_addr(neu_mqtt_client_t *client, const char *host,
uint16_t port);
int neu_mqtt_client_set_id(neu_mqtt_client_t *client, const char *id);
int neu_mqtt_client_set_will_msg(neu_mqtt_client_t *client, const char *topic,
uint8_t *msg, uint32_t len, bool retain,
uint8_t qos);
int neu_mqtt_client_set_user(neu_mqtt_client_t *client, const char *username,
const char *password);
int neu_mqtt_client_set_connect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_disconnect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
const char *ca, const char *cert, const char *key,
const char *keypass);
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
size_t mem_size_bytes, size_t db_size_bytes);
int neu_mqtt_client_set_addr(neu_mqtt_client_t *client, const char *host,
uint16_t port);
int neu_mqtt_client_set_id(neu_mqtt_client_t *client, const char *id);
int neu_mqtt_client_set_will_msg(neu_mqtt_client_t *client, const char *topic,
uint8_t *msg, uint32_t len, bool retain,
uint8_t qos);
int neu_mqtt_client_set_user(neu_mqtt_client_t *client, const char *username,
const char *password);
int neu_mqtt_client_set_connect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_disconnect_cb(neu_mqtt_client_t * client,
neu_mqtt_client_connection_cb_t cb,
void * data);
int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
const char *ca, const char *cert, const char *key,
const char *keypass);
void neu_mqtt_client_remove_cache_db(neu_mqtt_client_t *client);
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
size_t mem_size_bytes, size_t db_size_bytes);
// default to NEU_MQTT_CACHE_SYNC_INTERVAL_DEFAULT if not set
int neu_mqtt_client_set_cache_sync_interval(neu_mqtt_client_t *client,
uint32_t interval);
+3 -2
View File
@@ -23,8 +23,8 @@
#include <stdbool.h>
#define NEU_VERSION_MAJOR 2
#define NEU_VERSION_MINOR 7
#define NEU_VERSION_FIX 0
#define NEU_VERSION_MINOR 9
#define NEU_VERSION_FIX 5
#define NEU_GET_VERSION_MAJOR(V) ((0xffff0000 & V) >> 16)
#define NEU_GET_VERSION_MINOR(V) ((0x0000ff00 & V) >> 8)
@@ -94,6 +94,7 @@
extern int default_log_level;
extern bool disable_jwt;
extern char host_port[32];
extern char g_status[32];
typedef enum neu_plugin_kind {
NEU_PLUGIN_KIND_STATIC = 0,
+22 -19
View File
@@ -47,6 +47,7 @@ typedef enum {
NEU_ERR_COMMAND_EXECUTION_FAILED = 1014,
NEU_ERR_IP_ADDRESS_INVALID = 1015,
NEU_ERR_IP_ADDRESS_IN_USE = 1016,
NEU_ERR_BODY_TOO_BIG = 1017,
NEU_ERR_NODE_EXIST = 2002,
NEU_ERR_NODE_NOT_EXIST = 2003,
@@ -118,25 +119,27 @@ typedef enum {
NEU_ERR_TEMPLATE_NAME_TOO_LONG = 2502,
// common error codes for plugins
NEU_ERR_PLUGIN_READ_FAILURE = 3000,
NEU_ERR_PLUGIN_WRITE_FAILURE = 3001,
NEU_ERR_PLUGIN_DISCONNECTED = 3002,
NEU_ERR_PLUGIN_TAG_NOT_ALLOW_READ = 3003,
NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE = 3004,
NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH = 3007,
NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED = 3008,
NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE = 3009,
NEU_ERR_PLUGIN_NOT_RUNNING = 3010,
NEU_ERR_PLUGIN_TAG_NOT_READY = 3011,
NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER = 3012,
NEU_ERR_PLUGIN_NAME_TOO_LONG = 3013,
NEU_ERR_PLUGIN_NOT_FOUND = 3014,
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE = 3015,
NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE = 3016,
NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS = 3017,
NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC = 3018,
NEU_ERR_PLUGIN_TYPE_NOT_SUPPORT = 3019,
NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE = 3020,
NEU_ERR_PLUGIN_READ_FAILURE = 3000,
NEU_ERR_PLUGIN_WRITE_FAILURE = 3001,
NEU_ERR_PLUGIN_DISCONNECTED = 3002,
NEU_ERR_PLUGIN_TAG_NOT_ALLOW_READ = 3003,
NEU_ERR_PLUGIN_TAG_NOT_ALLOW_WRITE = 3004,
NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH = 3007,
NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED = 3008,
NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE = 3009,
NEU_ERR_PLUGIN_NOT_RUNNING = 3010,
NEU_ERR_PLUGIN_TAG_NOT_READY = 3011,
NEU_ERR_PLUGIN_PACKET_OUT_OF_ORDER = 3012,
NEU_ERR_PLUGIN_NAME_TOO_LONG = 3013,
NEU_ERR_PLUGIN_NOT_FOUND = 3014,
NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE = 3015,
NEU_ERR_PLUGIN_NOT_SUPPORT_TEMPLATE = 3016,
NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS = 3017,
NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC = 3018,
NEU_ERR_PLUGIN_TYPE_NOT_SUPPORT = 3019,
NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE = 3020,
NEU_ERR_PLUGIN_NOT_SUPPORT_SCAN_TAGS = 3021,
NEU_ERR_PLUGIN_NOT_SUPPORT_TEST_READ_TAG = 3022,
NEU_ERR_MQTT_FAILURE = 4000,
NEU_ERR_MQTT_NO_CERTFILESET = 4001,
+1
View File
@@ -68,6 +68,7 @@ typedef struct neu_json_elem {
enum neu_json_type t;
union neu_json_value v;
uint8_t precision;
double bias;
} neu_json_elem_t;
#define NEU_JSON_ELEM_SIZE(elems) sizeof(elems) / sizeof(neu_json_elem_t)
+63
View File
@@ -53,6 +53,7 @@ typedef struct {
uint8_t precision;
int n_meta;
neu_json_tag_meta_t *metas;
neu_datatag_t datatag;
} neu_json_read_resp_tag_t;
typedef struct {
@@ -62,6 +63,30 @@ typedef struct {
int neu_json_encode_read_resp(void *json_object, void *param);
int neu_json_encode_read_resp1(void *json_object, void *param);
int neu_json_encode_read_paginate_resp(void *json_object, void *param);
typedef struct {
int64_t error;
char * name;
enum neu_json_type t;
union neu_json_value value;
uint8_t precision;
int n_meta;
neu_json_tag_meta_t *metas;
neu_datatag_t datatag;
} neu_json_read_paginate_resp_tag_t;
typedef struct {
unsigned int current_page;
unsigned int page_size;
unsigned int total;
} neu_json_read_meta_resp_t;
typedef struct {
neu_json_read_meta_resp_t meta;
int n_tag;
neu_json_read_paginate_resp_tag_t *tags;
} neu_json_read_paginate_resp_t;
typedef struct {
char * group;
@@ -134,10 +159,48 @@ typedef struct {
int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result);
void neu_json_decode_read_req_free(neu_json_read_req_t *req);
typedef struct {
char *group;
char *node;
char *name;
char *desc;
bool sync;
int current_page;
int page_size;
bool is_error;
} neu_json_read_paginate_req_t;
int neu_json_decode_read_paginate_req(char * buf,
neu_json_read_paginate_req_t **result);
void neu_json_decode_read_paginate_req_free(neu_json_read_paginate_req_t *req);
int neu_json_encode_read_periodic_resp(void *json_object, void *param);
void neu_json_metas_to_json(neu_tag_meta_t *metas, int n_meta,
neu_json_read_resp_tag_t *json_tag);
void neu_json_metas_to_json_paginate(
neu_tag_meta_t *metas, int n_meta,
neu_json_read_paginate_resp_tag_t *json_tag);
typedef struct {
char * driver;
char * group;
char * tag;
char * address;
neu_attribute_e attribute;
neu_type_e type;
uint8_t precision;
double decimal;
double bias;
neu_datatag_addr_option_u option;
} neu_json_test_read_tag_req_t;
int neu_json_decode_test_read_tag_req(char * buf,
neu_json_test_read_tag_req_t **result);
void neu_json_decode_test_read_tag_req_free(neu_json_test_read_tag_req_t *req);
int neu_json_encode_test_read_tag_resp(void *json_object, void *param);
#ifdef __cplusplus
}
+51
View File
@@ -0,0 +1,51 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#ifndef _NEU_JSON_API_NEU_JSON_SCAN_H_
#define _NEU_JSON_API_NEU_JSON_SCAN_H_
#include "json/json.h"
#include "tag.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
char *node;
char *id;
} neu_json_scan_tags_req_t;
int neu_json_decode_scan_tags_req(char *buf, neu_json_scan_tags_req_t **result);
void neu_json_decode_scan_tags_req_free(neu_json_scan_tags_req_t *req);
int neu_json_encode_scan_tags_resp(void *json_object, void *param);
#ifdef __cplusplus
}
#endif
#endif
+3 -2
View File
@@ -248,6 +248,7 @@ typedef struct {
const char * name; // NOTE: should points to string literal
const char * help; // NOTE: should points to string literal
neu_metric_type_e type; //
uint64_t init; //
uint64_t value; //
neu_rolling_counter_t *rcnt; //
UT_hash_handle hh; // ordered by name
@@ -489,7 +490,7 @@ static inline void neu_node_metrics_reset(neu_node_metrics_t *node_metrics)
HASH_LOOP(hh, node_metrics->entries, entry)
{
if (!neu_metric_type_no_reset(entry->type)) {
entry->value = 0;
entry->value = entry->init;
if (neu_metric_type_is_rolling_counter(entry->type)) {
neu_rolling_counter_reset(entry->rcnt);
}
@@ -502,7 +503,7 @@ static inline void neu_node_metrics_reset(neu_node_metrics_t *node_metrics)
HASH_LOOP(hh, g->entries, entry)
{
if (!neu_metric_type_no_reset(entry->type)) {
entry->value = 0;
entry->value = entry->init;
if (neu_metric_type_is_rolling_counter(entry->type)) {
neu_rolling_counter_reset(entry->rcnt);
}
+268 -11
View File
@@ -30,8 +30,10 @@ extern "C" {
#include "json/neu_json_rw.h"
#include "define.h"
#include "errcodes.h"
#include "tag.h"
#include "type.h"
#include <math.h>
typedef struct {
neu_node_running_state_e running;
@@ -44,6 +46,10 @@ typedef enum neu_reqresp_type {
NEU_REQ_READ_GROUP,
NEU_RESP_READ_GROUP,
NEU_REQ_READ_GROUP_PAGINATE,
NEU_RESP_READ_GROUP_PAGINATE,
NEU_REQ_TEST_READ_TAG,
NEU_RESP_TEST_READ_TAG,
NEU_REQ_WRITE_TAG,
NEU_REQ_WRITE_TAGS,
NEU_REQ_WRITE_GTAGS,
@@ -114,16 +120,22 @@ typedef enum neu_reqresp_type {
NEU_REQ_PRGFILE_PROCESS,
NEU_RESP_PRGFILE_PROCESS,
NEU_REQ_SCAN_TAGS,
NEU_RESP_SCAN_TAGS,
} neu_reqresp_type_e;
static const char *neu_reqresp_type_string_t[] = {
[NEU_RESP_ERROR] = "NEU_RESP_ERROR",
[NEU_REQ_READ_GROUP] = "NEU_REQ_READ_GROUP",
[NEU_RESP_READ_GROUP] = "NEU_RESP_READ_GROUP",
[NEU_REQ_WRITE_TAG] = "NEU_REQ_WRITE_TAG",
[NEU_REQ_WRITE_TAGS] = "NEU_REQ_WRITE_TAGS",
[NEU_REQ_WRITE_GTAGS] = "NEU_REQ_WRITE_GTAGS",
[NEU_REQ_READ_GROUP] = "NEU_REQ_READ_GROUP",
[NEU_RESP_READ_GROUP] = "NEU_RESP_READ_GROUP",
[NEU_REQ_READ_GROUP_PAGINATE] = "NEU_REQ_READ_GROUP_PAGINATE",
[NEU_RESP_READ_GROUP_PAGINATE] = "NEU_RESP_READ_GROUP_PAGINATE",
[NEU_REQ_TEST_READ_TAG] = "NEU_REQ_TEST_READ_TAG",
[NEU_RESP_TEST_READ_TAG] = "NEU_RESP_TEST_READ_TAG",
[NEU_REQ_WRITE_TAG] = "NEU_REQ_WRITE_TAG",
[NEU_REQ_WRITE_TAGS] = "NEU_REQ_WRITE_TAGS",
[NEU_REQ_WRITE_GTAGS] = "NEU_REQ_WRITE_GTAGS",
[NEU_REQ_SUBSCRIBE_GROUP] = "NEU_REQ_SUBSCRIBE_GROUP",
[NEU_REQ_UNSUBSCRIBE_GROUP] = "NEU_REQ_UNSUBSCRIBE_GROUP",
@@ -189,6 +201,9 @@ static const char *neu_reqresp_type_string_t[] = {
[NEU_REQ_PRGFILE_UPLOAD] = "NEU_REQ_PRGFILE_UPLOAD",
[NEU_REQ_PRGFILE_PROCESS] = "NEU_REQ_PRGFILE_PROCESS",
[NEU_RESP_PRGFILE_PROCESS] = "NEU_RESP_PRGFILE_PROCESS",
[NEU_REQ_SCAN_TAGS] = "NEU_REQ_SCAN_TAGS",
[NEU_RESP_SCAN_TAGS] = "NEU_RESP_SCAN_TAGS",
};
inline static const char *neu_reqresp_type_string(neu_reqresp_type_e type)
@@ -612,6 +627,26 @@ static inline void neu_req_read_group_fini(neu_req_read_group_t *req)
free(req->desc);
}
typedef struct neu_req_read_group_paginate {
char *driver;
char *group;
char *name;
char *desc;
bool sync;
int current_page;
int page_size;
bool is_error;
} neu_req_read_group_paginate_t;
static inline void
neu_req_read_group_paginate_fini(neu_req_read_group_paginate_t *req)
{
free(req->driver);
free(req->group);
free(req->name);
free(req->desc);
}
typedef struct neu_req_write_tag {
char * driver;
char * group;
@@ -635,6 +670,7 @@ typedef struct neu_resp_tag_value_meta {
char tag[NEU_TAG_NAME_LEN];
neu_dvalue_t value;
neu_tag_meta_t metas[NEU_TAG_META_SIZE];
neu_datatag_t datatag;
} neu_resp_tag_value_meta_t;
static inline UT_icd *neu_resp_tag_value_meta_icd()
@@ -694,6 +730,31 @@ typedef struct {
UT_array *tags; // neu_resp_tag_value_meta_t
} neu_resp_read_group_t;
typedef struct neu_resp_tag_value_meta_paginate {
char tag[NEU_TAG_NAME_LEN];
neu_dvalue_t value;
neu_tag_meta_t metas[NEU_TAG_META_SIZE];
neu_datatag_t datatag;
} neu_resp_tag_value_meta_paginate_t;
static inline UT_icd *neu_resp_tag_value_meta_paginate_icd()
{
static UT_icd icd = { sizeof(neu_resp_tag_value_meta_paginate_t), NULL,
NULL, NULL };
return &icd;
}
typedef struct {
char *driver;
char *group;
int current_page;
int page_size;
bool is_error;
int total_count; // tags count without pagination
UT_array *tags; // neu_resp_tag_value_meta_paginate_t
} neu_resp_read_group_paginate_t;
static inline void neu_resp_read_free(neu_resp_read_group_t *resp)
{
utarray_foreach(resp->tags, neu_resp_tag_value_meta_t *, tag_value)
@@ -707,6 +768,20 @@ static inline void neu_resp_read_free(neu_resp_read_group_t *resp)
utarray_free(resp->tags);
}
static inline void
neu_resp_read_paginate_free(neu_resp_read_group_paginate_t *resp)
{
utarray_foreach(resp->tags, neu_resp_tag_value_meta_t *, tag_value)
{
if (tag_value->value.type == NEU_TYPE_PTR) {
free(tag_value->value.value.ptr.ptr);
}
}
free(resp->driver);
free(resp->group);
utarray_free(resp->tags);
}
typedef struct {
uint16_t index;
pthread_mutex_t mtx;
@@ -799,6 +874,8 @@ static inline void neu_tag_value_to_json(neu_resp_tag_value_meta_t *tag_value,
}
neu_json_metas_to_json(tag_value->metas, NEU_TAG_META_SIZE, tag_json);
tag_json->datatag.bias = tag_value->datatag.bias;
switch (tag_value->value.type) {
case NEU_TYPE_ERROR:
tag_json->t = NEU_JSON_INT;
@@ -841,14 +918,150 @@ static inline void neu_tag_value_to_json(neu_resp_tag_value_meta_t *tag_value,
tag_json->value.val_int = tag_value->value.value.u64;
break;
case NEU_TYPE_FLOAT:
tag_json->t = NEU_JSON_FLOAT;
tag_json->value.val_float = tag_value->value.value.f32;
tag_json->precision = tag_value->value.precision;
if (isnan(tag_value->value.value.f32)) {
tag_json->t = NEU_JSON_FLOAT;
tag_json->value.val_float = tag_value->value.value.f32;
tag_json->error = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
} else {
tag_json->t = NEU_JSON_FLOAT;
tag_json->value.val_float = tag_value->value.value.f32;
tag_json->precision = tag_value->value.precision;
}
break;
case NEU_TYPE_DOUBLE:
tag_json->t = NEU_JSON_DOUBLE;
tag_json->value.val_double = tag_value->value.value.d64;
tag_json->precision = tag_value->value.precision;
if (isnan(tag_value->value.value.d64)) {
tag_json->t = NEU_JSON_DOUBLE;
tag_json->value.val_double = tag_value->value.value.d64;
tag_json->error = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
} else {
tag_json->t = NEU_JSON_DOUBLE;
tag_json->value.val_double = tag_value->value.value.d64;
tag_json->precision = tag_value->value.precision;
}
break;
case NEU_TYPE_BOOL:
tag_json->t = NEU_JSON_BOOL;
tag_json->value.val_bool = tag_value->value.value.boolean;
break;
case NEU_TYPE_BIT:
tag_json->t = NEU_JSON_BIT;
tag_json->value.val_bit = tag_value->value.value.u8;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_TIME:
case NEU_TYPE_DATA_AND_TIME:
tag_json->t = NEU_JSON_STR;
tag_json->value.val_str = tag_value->value.value.str;
break;
case NEU_TYPE_PTR:
tag_json->t = NEU_JSON_STR;
tag_json->value.val_str = (char *) tag_value->value.value.ptr.ptr;
break;
case NEU_TYPE_BYTES:
tag_json->t = NEU_JSON_BYTES;
tag_json->value.val_bytes.length = tag_value->value.value.bytes.length;
tag_json->value.val_bytes.bytes = tag_value->value.value.bytes.bytes;
break;
default:
break;
}
}
static inline void
neu_tag_value_to_json_paginate(neu_resp_tag_value_meta_paginate_t *tag_value,
neu_json_read_paginate_resp_tag_t * tag_json)
{
tag_json->name = tag_value->tag;
tag_json->error = 0;
tag_json->datatag.name = strdup(tag_value->datatag.name);
tag_json->datatag.address = strdup(tag_value->datatag.address);
tag_json->datatag.attribute = tag_value->datatag.attribute;
tag_json->datatag.type = tag_value->datatag.type;
tag_json->datatag.precision = tag_value->datatag.precision;
tag_json->datatag.decimal = tag_value->datatag.decimal;
tag_json->datatag.bias = tag_value->datatag.bias;
tag_json->datatag.description = strdup(tag_value->datatag.description);
tag_json->datatag.option = tag_value->datatag.option;
memcpy(tag_json->datatag.meta, tag_value->datatag.meta,
NEU_TAG_META_LENGTH);
for (int k = 0; k < NEU_TAG_META_SIZE; k++) {
if (strlen(tag_value->metas[k].name) > 0) {
tag_json->n_meta++;
} else {
break;
}
}
if (tag_json->n_meta > 0) {
tag_json->metas = (neu_json_tag_meta_t *) calloc(
tag_json->n_meta, sizeof(neu_json_tag_meta_t));
}
neu_json_metas_to_json_paginate(tag_value->metas, NEU_TAG_META_SIZE,
tag_json);
switch (tag_value->value.type) {
case NEU_TYPE_ERROR:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.i32;
tag_json->error = tag_value->value.value.i32;
break;
case NEU_TYPE_UINT8:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.u8;
break;
case NEU_TYPE_INT8:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.i8;
break;
case NEU_TYPE_INT16:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.i16;
break;
case NEU_TYPE_INT32:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.i32;
break;
case NEU_TYPE_INT64:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.i64;
break;
case NEU_TYPE_WORD:
case NEU_TYPE_UINT16:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.u16;
break;
case NEU_TYPE_DWORD:
case NEU_TYPE_UINT32:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.u32;
break;
case NEU_TYPE_LWORD:
case NEU_TYPE_UINT64:
tag_json->t = NEU_JSON_INT;
tag_json->value.val_int = tag_value->value.value.u64;
break;
case NEU_TYPE_FLOAT:
if (isnan(tag_value->value.value.f32)) {
tag_json->t = NEU_JSON_FLOAT;
tag_json->value.val_float = tag_value->value.value.f32;
tag_json->error = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
} else {
tag_json->t = NEU_JSON_FLOAT;
tag_json->value.val_float = tag_value->value.value.f32;
tag_json->precision = tag_value->value.precision;
}
break;
case NEU_TYPE_DOUBLE:
if (isnan(tag_value->value.value.d64)) {
tag_json->t = NEU_JSON_DOUBLE;
tag_json->value.val_double = tag_value->value.value.d64;
tag_json->error = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
} else {
tag_json->t = NEU_JSON_DOUBLE;
tag_json->value.val_double = tag_value->value.value.d64;
tag_json->precision = tag_value->value.precision;
}
break;
case NEU_TYPE_BOOL:
tag_json->t = NEU_JSON_BOOL;
@@ -923,6 +1136,50 @@ typedef struct {
char reason[256];
} neu_resp_prgfile_process_t;
typedef struct neu_req_scan_tags {
char driver[NEU_NODE_NAME_LEN];
char id[NEU_TAG_ADDRESS_LEN];
} neu_req_scan_tags_t;
typedef struct {
char name[NEU_TAG_NAME_LEN];
char id[5 + 1 + NEU_TAG_ADDRESS_LEN]; // ns + ! + address
uint8_t type;
} neu_scan_tag_t;
typedef struct {
UT_array * scan_tags;
int32_t error;
neu_type_e type;
bool is_array;
} neu_resp_scan_tags_t;
typedef struct {
char name[NEU_TAG_NAME_LEN];
char id[5 + 1 + NEU_TAG_ADDRESS_LEN];
neu_type_e type;
} neu_scan_tag_attribute_t;
typedef struct neu_req_test_rea_tag {
char driver[NEU_NODE_NAME_LEN];
char group[NEU_GROUP_NAME_LEN];
char tag[NEU_TAG_NAME_LEN];
char address[NEU_TAG_ADDRESS_LEN];
neu_attribute_e attribute;
neu_type_e type;
uint8_t precision;
double decimal;
double bias;
neu_datatag_addr_option_u option;
} neu_req_test_read_tag_t;
typedef struct {
neu_type_e type;
neu_json_type_e t;
neu_json_value_u value;
int64_t error;
} neu_resp_test_read_tag_t;
#ifdef __cplusplus
}
#endif
+4
View File
@@ -69,6 +69,7 @@ struct neu_plugin_group {
void * user_data;
neu_plugin_group_free group_free;
uint32_t interval;
};
typedef int (*neu_plugin_tag_validator_t)(const neu_datatag_t *tag);
@@ -108,6 +109,9 @@ typedef struct neu_plugin_intf_funs {
neu_datatag_t *tags,
int n_tag); // create tags by API
int (*del_tags)(neu_plugin_t *plugin, int n_tag);
int (*scan_tags)(neu_plugin_t *plugin, void *req, char *id);
int (*test_read_tag)(neu_plugin_t *plugin, void *req,
neu_datatag_t tag);
} driver;
};
+238 -131
View File
@@ -474,6 +474,238 @@ static inline void neu_value16_set_bit(neu_value16_u *value, uint8_t index,
}
}
static inline uint16_t neu_get_u16(uint8_t *bytes)
{
uint16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline void neu_set_u16(uint8_t *bytes, uint16_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
}
static inline int16_t neu_get_i16(uint8_t *bytes)
{
int16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline void neu_set_i16(uint8_t *bytes, int16_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
}
static inline uint32_t neu_get_u32(uint8_t *bytes)
{
uint32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline void neu_set_u32(uint8_t *bytes, uint32_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
}
static inline int32_t neu_get_i32(uint8_t *bytes)
{
int32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline void neu_set_i32(uint8_t *bytes, int32_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
}
static inline float neu_get_f32(uint8_t *bytes)
{
float ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline void neu_set_f32(uint8_t *bytes, float val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
}
static inline uint64_t neu_get_u64(uint8_t *bytes)
{
uint64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline void neu_set_u64(uint8_t *bytes, uint64_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
bytes[4] = t[4];
bytes[5] = t[5];
bytes[6] = t[6];
bytes[7] = t[7];
}
static inline int64_t neu_get_i64(uint8_t *bytes)
{
int64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline void neu_set_i64(uint8_t *bytes, int64_t val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
bytes[4] = t[4];
bytes[5] = t[5];
bytes[6] = t[6];
bytes[7] = t[7];
}
static inline double neu_get_f64(uint8_t *bytes)
{
double ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline void neu_set_f64(uint8_t *bytes, double val)
{
uint8_t *t = NULL;
t = (uint8_t *) &val;
bytes[0] = t[0];
bytes[1] = t[1];
bytes[2] = t[2];
bytes[3] = t[3];
bytes[4] = t[4];
bytes[5] = t[5];
bytes[6] = t[6];
bytes[7] = t[7];
}
static inline void neu_ntohs24_p(uint8_t *value)
{
uint8_t t = 0;
@@ -513,7 +745,8 @@ static inline uint64_t neu_ntohll(uint64_t u)
static inline void neu_ntonll_p(uint64_t *pu)
{
*pu = neu_htonll(*pu);
uint64_t ret = neu_htonll(neu_get_u64((uint8_t *) pu));
neu_set_u64((uint8_t *) pu, ret);
}
static inline void neu_htonll_p(uint64_t *pu)
@@ -523,7 +756,8 @@ static inline void neu_htonll_p(uint64_t *pu)
static inline void neu_ntohl_p(uint32_t *pu)
{
*pu = ntohl(*pu);
uint32_t ret = ntohl(neu_get_u32((uint8_t *) pu));
neu_set_u32((uint8_t *) pu, ret);
}
static inline void neu_htonl_p(uint32_t *pu)
@@ -533,7 +767,8 @@ static inline void neu_htonl_p(uint32_t *pu)
static inline void neu_ntohs_p(uint16_t *pu)
{
*pu = ntohs(*pu);
uint16_t ret = ntohs(neu_get_u16((uint8_t *) pu));
neu_set_u16((uint8_t *) pu, ret);
}
static inline void neu_htons_p(uint16_t *pu)
@@ -541,134 +776,6 @@ static inline void neu_htons_p(uint16_t *pu)
neu_ntohs_p(pu);
}
static inline uint16_t neu_get_u16(uint8_t *bytes)
{
uint16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline int16_t neu_get_i16(uint8_t *bytes)
{
int16_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
return ret;
}
static inline uint32_t neu_get_u32(uint8_t *bytes)
{
uint32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline int32_t neu_get_i32(uint8_t *bytes)
{
int32_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline float neu_get_f32(uint8_t *bytes)
{
float ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
return ret;
}
static inline uint64_t neu_get_u64(uint8_t *bytes)
{
uint64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline int64_t neu_get_i64(uint8_t *bytes)
{
int64_t ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
static inline double neu_get_f64(uint8_t *bytes)
{
double ret = 0;
uint8_t *t = NULL;
t = (uint8_t *) &ret;
t[0] = bytes[0];
t[1] = bytes[1];
t[2] = bytes[2];
t[3] = bytes[3];
t[4] = bytes[4];
t[5] = bytes[5];
t[6] = bytes[6];
t[7] = bytes[7];
return ret;
}
#ifdef __cplusplus
}
#endif
+2
View File
@@ -87,4 +87,6 @@ void neu_async_queue_remove(neu_async_queue_t *q, neu_async_queue_filter filter,
*/
void neu_async_queue_clean(neu_async_queue_t *q);
int neu_async_queue_len(neu_async_queue_t *q);
#endif
+20
View File
@@ -0,0 +1,20 @@
import jwt # pip install pyjwt
import time
with open("neuron.key", "r") as f:
private_key = f.read()
current_time = int(time.time())
two_years = 60 * 60 * 24 * 365 * 2
header = {"alg": "RS256", "typ": "JWT"}
payload = {
"aud": "neuron",
"bodyEncode": 0,
"exp": current_time + two_years,
"iat": current_time,
"iss": "neuron",
}
token = jwt.encode(payload, private_key, algorithm="RS256", headers=header).decode(
"utf-8"
)
print(f"Bearer {token}")
+2 -1
View File
@@ -3,5 +3,6 @@
"port": 7000,
"disable_auth": 0,
"syslog_host": "",
"syslog_port": 541
"syslog_port": 541,
"sub_filter_error": 0
}
+7 -3
View File
@@ -322,9 +322,13 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
case NEU_REQRESP_TRANS_DATA: {
neu_reqresp_trans_data_t *trans_data = data;
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1, NULL);
if (plugin->started) {
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1,
NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1,
NULL);
}
if (disconnected) {
plog_debug(plugin, "not connected");
+19
View File
@@ -67,6 +67,25 @@
]
}
},
"check_header": {
"name": "Check Header",
"name_zh": "校验报文头",
"attribute": "required",
"type": "map",
"default": 0,
"valid": {
"map": [
{
"key": "False",
"value": 0
},
{
"key": "True",
"value": 1
}
]
}
},
"max_retries": {
"name": "Maximum Retry Times",
"name_zh": "最大重试次数",
+280 -8
View File
@@ -37,6 +37,9 @@ struct modbus_write_tags_data {
static void plugin_group_free(neu_plugin_group_t *pgp);
static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
uint16_t response_size);
static int process_protocol_buf_test(neu_plugin_t *plugin, void *req,
modbus_point_t *point,
uint16_t response_size);
void modbus_conn_connected(void *data, int fd)
{
@@ -125,10 +128,10 @@ int modbus_stack_read_retry(neu_plugin_t *plugin, struct modbus_group_data *gd,
struct timespec t4 = { 0 };
nanosleep(&t3, &t4);
plog_notice(plugin, "Resend read req. Times:%hu", j + 1);
int ret = modbus_stack_read(plugin->stack, gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].area,
gd->cmd_sort->cmd[i].start_address,
gd->cmd_sort->cmd[i].n_register, response_size);
int ret = modbus_stack_read(
plugin->stack, gd->cmd_sort->cmd[i].slave_id, gd->cmd_sort->cmd[i].area,
gd->cmd_sort->cmd[i].start_address, gd->cmd_sort->cmd[i].n_register,
response_size, false);
return ret;
}
@@ -175,7 +178,7 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
int ret_r = modbus_stack_read(
plugin->stack, gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].area, gd->cmd_sort->cmd[i].start_address,
gd->cmd_sort->cmd[i].n_register, &response_size);
gd->cmd_sort->cmd[i].n_register, &response_size, false);
if (ret_r > 0) {
ret_buf = process_protocol_buf(
plugin, gd->cmd_sort->cmd[i].slave_id, response_size);
@@ -203,6 +206,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
"modbus message error, skip, %hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = NEU_METRIC_LAST_RTT_MS_MAX;
neu_conn_disconnect(plugin->conn);
} else if (ret_buf == -2) {
modbus_value_handle(
plugin, gd->cmd_sort->cmd[i].slave_id, 0,
@@ -213,8 +218,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
"%hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = neu_time_ms() - read_tms;
}
rtt = neu_time_ms() - read_tms;
break;
}
} else {
@@ -243,6 +248,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
plog_error(plugin, "modbus message error, skip, %hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = NEU_METRIC_LAST_RTT_MS_MAX;
neu_conn_disconnect(plugin->conn);
} else if (ret_buf == -2) {
modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id,
0, NULL, NEU_ERR_PLUGIN_READ_FAILURE);
@@ -250,8 +257,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
"modbus device response error, skip, %hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = neu_time_ms() - read_tms;
}
rtt = neu_time_ms() - read_tms;
}
} else {
for (uint16_t j = 0; j < plugin->max_retries; j++) {
@@ -272,6 +279,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
"modbus message error, skip, %hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = NEU_METRIC_LAST_RTT_MS_MAX;
neu_conn_disconnect(plugin->conn);
} else if (ret_buf == -2) {
modbus_value_handle(
plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL,
@@ -281,8 +290,8 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group,
"%hhu!%hu",
gd->cmd_sort->cmd[i].slave_id,
gd->cmd_sort->cmd[i].start_address);
rtt = neu_time_ms() - read_tms;
}
rtt = neu_time_ms() - read_tms;
break;
} else if (ret_buf == 0) {
modbus_value_handle(
@@ -453,6 +462,195 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
return 0;
}
int modbus_value_handle_test(neu_plugin_t *plugin, void *req,
modbus_point_t *point, uint16_t n_byte,
uint8_t *bytes)
{
(void) req;
neu_json_value_u jvalue = { 0 };
neu_json_type_e jtype;
switch (point->area) {
case MODBUS_AREA_HOLD_REGISTER:
case MODBUS_AREA_INPUT_REGISTER:
if (n_byte >= point->n_register * 2) {
jvalue.val_bytes.bytes =
(uint8_t *) malloc(point->n_register * 2 + 1);
memcpy(jvalue.val_bytes.bytes, bytes, point->n_register * 2);
jvalue.val_bytes.length = point->n_register * 2;
}
break;
case MODBUS_AREA_COIL:
case MODBUS_AREA_INPUT: {
neu_value8_u u8 = { .value = bytes[0] };
jvalue.val_bit = neu_value8_get_bit(u8, 0);
} break;
}
switch (point->type) {
case NEU_TYPE_UINT16: {
jtype = NEU_JSON_INT;
uint16_t tmp_val16;
memcpy(&tmp_val16, jvalue.val_bytes.bytes, sizeof(uint16_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = ntohs(tmp_val16);
break;
}
case NEU_TYPE_INT16: {
jtype = NEU_JSON_INT;
int16_t tmp_val16;
memcpy(&tmp_val16, jvalue.val_bytes.bytes, sizeof(int16_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = (int16_t) ntohs(tmp_val16);
break;
}
case NEU_TYPE_FLOAT: {
uint32_t tmp_valf;
memcpy(&tmp_valf, jvalue.val_bytes.bytes, sizeof(uint32_t));
free(jvalue.val_bytes.bytes);
jtype = NEU_JSON_FLOAT;
jvalue.val_int = ntohl(tmp_valf);
break;
}
case NEU_TYPE_INT32: {
jtype = NEU_JSON_INT;
int32_t tmp_val32;
memcpy(&tmp_val32, jvalue.val_bytes.bytes, sizeof(int32_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = (int32_t) ntohl(tmp_val32);
break;
}
case NEU_TYPE_UINT32: {
jtype = NEU_JSON_INT;
uint32_t tmp_val32;
memcpy(&tmp_val32, jvalue.val_bytes.bytes, sizeof(uint32_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = ntohl(tmp_val32);
break;
}
case NEU_TYPE_DOUBLE: {
uint64_t tmp_vald;
memcpy(&tmp_vald, jvalue.val_bytes.bytes, sizeof(uint64_t));
free(jvalue.val_bytes.bytes);
jtype = NEU_JSON_DOUBLE;
jvalue.val_int = neu_ntohll(tmp_vald);
break;
}
case NEU_TYPE_INT64: {
jtype = NEU_JSON_INT;
int64_t tmp_val64;
memcpy(&tmp_val64, jvalue.val_bytes.bytes, sizeof(int64_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = (int64_t) neu_ntohll(tmp_val64);
break;
}
case NEU_TYPE_UINT64: {
jtype = NEU_JSON_INT;
uint64_t tmp_val64;
memcpy(&tmp_val64, jvalue.val_bytes.bytes, sizeof(uint64_t));
free(jvalue.val_bytes.bytes);
jvalue.val_int = neu_ntohll(tmp_val64);
break;
}
case NEU_TYPE_BIT: {
switch (point->area) {
case MODBUS_AREA_HOLD_REGISTER:
case MODBUS_AREA_INPUT_REGISTER: {
jtype = NEU_JSON_BIT;
neu_value16_u v16 = { 0 };
v16.value = htons(*(uint16_t *) jvalue.val_bytes.bytes);
free(jvalue.val_bytes.bytes);
jvalue.val_bit = neu_value16_get_bit(v16, point->option.bit.bit);
break;
}
case MODBUS_AREA_COIL:
case MODBUS_AREA_INPUT:
jtype = NEU_JSON_INT;
break;
}
break;
}
case NEU_TYPE_STRING: {
jtype = NEU_JSON_STR;
size_t str_length = point->n_register * 2;
jvalue.val_str = (char *) jvalue.val_bytes.bytes;
jvalue.val_str[str_length] = '\0';
switch (point->option.string.type) {
case NEU_DATATAG_STRING_TYPE_H:
break;
case NEU_DATATAG_STRING_TYPE_L:
neu_datatag_string_ltoh(jvalue.val_str, str_length);
break;
case NEU_DATATAG_STRING_TYPE_D:
break;
case NEU_DATATAG_STRING_TYPE_E:
break;
}
if (!neu_datatag_string_is_utf8(jvalue.val_str, str_length)) {
jvalue.val_str[0] = '?';
jvalue.val_str[1] = 0;
}
break;
}
default:
break;
}
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, jtype, point->type, jvalue,
NEU_ERR_SUCCESS);
return 0;
}
int modbus_test_read_tag(neu_plugin_t *plugin, void *req, neu_datatag_t tag)
{
modbus_point_t point = { 0 };
neu_json_value_u error_value;
error_value.val_int = 0;
int err = modbus_tag_to_point(&tag, &point);
if (err != NEU_ERR_SUCCESS) {
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR,
error_value, err);
return 0;
}
uint16_t response_size = 0;
int ret = modbus_stack_read(plugin->stack, point.slave_id, point.area,
point.start_address, point.n_register,
&response_size, true);
if (ret <= 0) {
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR,
error_value, NEU_ERR_PLUGIN_READ_FAILURE);
return 0;
}
ret = process_protocol_buf_test(plugin, req, &point, response_size);
if (ret == 0) {
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR,
error_value, NEU_ERR_PLUGIN_DEVICE_NOT_RESPONSE);
return 0;
} else if (ret == -1) {
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR,
error_value, NEU_ERR_PLUGIN_PROTOCOL_DECODE_FAILURE);
return 0;
} else if (ret == -2) {
plugin->common.adapter_callbacks->driver.test_read_tag_response(
plugin->common.adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR,
error_value, NEU_ERR_PLUGIN_READ_FAILURE);
return 0;
}
return 0;
}
int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value, bool response)
{
@@ -713,4 +911,78 @@ static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
}
free(recv_buf);
return ret;
}
static int process_protocol_buf_test(neu_plugin_t *plugin, void *req,
modbus_point_t *point,
uint16_t response_size)
{
uint8_t * recv_buf = calloc(response_size, 1);
neu_protocol_unpack_buf_t pbuf = { 0 };
ssize_t ret = 0;
if (plugin->protocol == MODBUS_PROTOCOL_TCP) {
if (plugin->is_server) {
ret = neu_conn_tcp_server_recv(plugin->conn, plugin->client_fd,
recv_buf,
sizeof(struct modbus_header));
} else {
ret = neu_conn_recv(plugin->conn, recv_buf,
sizeof(struct modbus_header));
}
if (ret == 0 || ret == -1) {
free(recv_buf);
return 0;
}
if (ret == sizeof(struct modbus_header)) {
struct modbus_header *header = (struct modbus_header *) recv_buf;
int ret1 = 0;
if (htons(header->len) >
response_size - sizeof(struct modbus_header)) {
free(recv_buf);
return -1;
}
plog_recv_protocol(plugin, recv_buf, ret);
if (plugin->is_server) {
ret1 = neu_conn_tcp_server_recv(
plugin->conn, plugin->client_fd,
recv_buf + sizeof(struct modbus_header),
htons(header->len));
} else {
ret1 = neu_conn_recv(plugin->conn,
recv_buf + sizeof(struct modbus_header),
htons(header->len));
}
if (ret1 != htons(header->len)) {
free(recv_buf);
return -1;
}
ret += ret1;
} else {
free(recv_buf);
return -1;
}
if (ret > 0) {
if (ret < 512) {
plog_recv_protocol(plugin, recv_buf, ret);
}
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
int ret_s = modbus_stack_recv_test(plugin, req, point, &pbuf);
if (ret_s == MODBUS_DEVICE_ERR) {
ret = ret_s;
} else {
if (ret != response_size) {
ret = -1;
} else {
ret = ret_s;
}
}
}
}
free(recv_buf);
return ret;
}
+5
View File
@@ -43,6 +43,7 @@ struct neu_plugin {
uint16_t interval;
uint16_t retry_interval;
uint16_t max_retries;
uint16_t check_header;
};
void modbus_conn_connected(void *data, int fd);
@@ -63,5 +64,9 @@ int modbus_write_tag(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags);
int modbus_write_resp(void *ctx, void *req, int error);
int modbus_test_read_tag(neu_plugin_t *plugin, void *req, neu_datatag_t tag);
int modbus_value_handle_test(neu_plugin_t *plugin, void *req,
modbus_point_t *point, uint16_t n_byte,
uint8_t *bytes);
#endif
+103 -2
View File
@@ -77,6 +77,12 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
if (ret <= 0) {
return -1;
}
neu_plugin_t *plugin = (neu_plugin_t *) stack->ctx;
if (plugin->check_header && header.seq + 1 != stack->read_seq &&
header.seq + 1 != stack->write_seq) {
return -1;
}
}
ret = modbus_code_unwrap(buf, &code);
@@ -177,9 +183,104 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
return neu_protocol_unpack_buf_used_size(buf);
}
int modbus_stack_recv_test(neu_plugin_t *plugin, void *req,
modbus_point_t * point,
neu_protocol_unpack_buf_t *buf)
{
struct modbus_header header = { 0 };
struct modbus_code code = { 0 };
int ret = 0;
if (plugin->stack->protocol == MODBUS_PROTOCOL_TCP) {
ret = modbus_header_unwrap(buf, &header);
if (ret < 0) {
plog_warn((neu_plugin_t *) plugin->stack->ctx,
"try modbus rtu driver");
}
if (ret <= 0) {
return -1;
}
}
ret = modbus_code_unwrap(buf, &code);
if (ret <= 0) {
return -1;
}
if (code.slave_id != point->slave_id) {
return -1;
}
switch (code.function) {
case MODBUS_READ_COIL:
case MODBUS_READ_INPUT:
case MODBUS_READ_HOLD_REG:
case MODBUS_READ_INPUT_REG: {
struct modbus_data data = { 0 };
uint8_t * bytes = NULL;
ret = modbus_data_unwrap(buf, &data);
if (ret <= 0) {
return -1;
}
if (data.n_byte == 0xff) {
bytes = neu_protocol_unpack_buf(buf,
header.len -
sizeof(struct modbus_code) -
sizeof(struct modbus_data));
if (bytes == NULL) {
return -1;
}
modbus_value_handle_test(plugin, req, point, data.n_byte, bytes);
} else {
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
if (bytes == NULL) {
return -1;
}
modbus_value_handle_test(plugin, req, point, data.n_byte, bytes);
}
break;
}
case MODBUS_WRITE_S_COIL:
case MODBUS_WRITE_M_HOLD_REG:
case MODBUS_WRITE_M_COIL: {
struct modbus_address address = { 0 };
ret = modbus_address_unwrap(buf, &address);
if (ret <= 0) {
return -1;
}
break;
}
case MODBUS_READ_COIL_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_READ_INPUT_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_READ_HOLD_REG_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_READ_INPUT_REG_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_WRITE_S_COIL_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_WRITE_S_HOLD_REG_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_WRITE_M_HOLD_REG_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_WRITE_M_COIL_ERR:
return MODBUS_DEVICE_ERR;
case MODBUS_WRITE_S_HOLD_REG:
break;
default:
return -1;
}
return neu_protocol_unpack_buf_used_size(buf);
}
int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
enum modbus_area area, uint16_t start_address,
uint16_t n_reg, uint16_t *response_size)
uint16_t n_reg, uint16_t *response_size, bool is_test)
{
static __thread uint8_t buf[16] = { 0 };
static __thread neu_protocol_pack_buf_t pbuf = { 0 };
@@ -229,7 +330,7 @@ int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
ret = stack->send_fn(stack->ctx, neu_protocol_pack_buf_used_size(&pbuf),
neu_protocol_pack_buf_get(&pbuf));
if (ret <= 0) {
if (ret <= 0 && !is_test) {
stack->value_fn(stack->ctx, 0, 0, NULL, NEU_ERR_PLUGIN_DISCONNECTED);
plog_warn((neu_plugin_t *) stack->ctx, "send read req fail, %hhu!%hu",
slave_id, start_address);
+5 -1
View File
@@ -24,6 +24,7 @@
#include <neuron.h>
#include "modbus.h"
#include "modbus_point.h"
typedef struct modbus_stack modbus_stack_t;
@@ -45,10 +46,13 @@ void modbus_stack_destroy(modbus_stack_t *stack);
int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
neu_protocol_unpack_buf_t *buf);
int modbus_stack_recv_test(neu_plugin_t *plugin, void *req,
modbus_point_t * point,
neu_protocol_unpack_buf_t *buf);
int modbus_stack_read(modbus_stack_t *stack, uint8_t slave_id,
enum modbus_area area, uint16_t start_address,
uint16_t n_reg, uint16_t *response_size);
uint16_t n_reg, uint16_t *response_size, bool is_test);
int modbus_stack_write(modbus_stack_t *stack, void *req, uint8_t slave_id,
enum modbus_area area, uint16_t start_address,
uint16_t n_reg, uint8_t *bytes, uint8_t n_byte,
+18
View File
@@ -43,6 +43,8 @@ static int driver_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group);
static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
neu_value_u value);
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags);
static int driver_test_read_tag(neu_plugin_t *plugin, void *req,
neu_datatag_t tag);
static const neu_plugin_intf_funs_t plugin_intf_funs = {
.open = driver_open,
@@ -59,6 +61,7 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
.driver.write_tag = driver_write,
.driver.tag_validator = driver_tag_validator,
.driver.write_tags = driver_write_tags,
.driver.test_read_tag = driver_test_read_tag,
.driver.add_tags = NULL,
.driver.load_tags = NULL,
.driver.del_tags = NULL,
@@ -158,6 +161,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
neu_json_elem_t max_retries = { .name = "max_retries", .t = NEU_JSON_INT };
neu_json_elem_t retry_interval = { .name = "retry_interval",
.t = NEU_JSON_INT };
neu_json_elem_t check_header = { .name = "check_header",
.t = NEU_JSON_INT };
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
&timeout, &interval);
@@ -186,10 +191,17 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
retry_interval.v.val_int = 0;
}
ret = neu_parse_param((char *) config, &err_param, 1, &check_header);
if (ret != 0) {
free(err_param);
check_header.v.val_int = 0;
}
param.log = plugin->common.log;
plugin->interval = interval.v.val_int;
plugin->max_retries = max_retries.v.val_int;
plugin->retry_interval = retry_interval.v.val_int;
plugin->check_header = check_header.v.val_int;
if (mode.v.val_int == 1) {
param.type = NEU_CONN_TCP_SERVER;
@@ -280,4 +292,10 @@ static int driver_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
static int driver_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
{
return modbus_write_tags(plugin, req, tags);
}
static int driver_test_read_tag(neu_plugin_t *plugin, void *req,
neu_datatag_t tag)
{
return modbus_test_read_tag(plugin, req, tag);
}
-3
View File
@@ -6,7 +6,6 @@
"description_zh": "MQTT 客户端 ID",
"type": "string",
"attribute": "required",
"default": "neuron_${random_str}",
"valid": {
"length": 255
}
@@ -60,7 +59,6 @@
"description_zh": "Neuron 向 AWS IoT Core 订阅的 MQTT 主题,用于接收点位写入请求。",
"attribute": "required",
"type": "string",
"default": "/neuron/${node-name}/write/req",
"valid": {
"length": 255
}
@@ -72,7 +70,6 @@
"description_zh": "Neuron 通过该 MQTT 主题将点位写入响应发布到 AWS IoT Core。",
"attribute": "required",
"type": "string",
"default": "/neuron/${node-name}/write/resp",
"valid": {
"length": 255
}
+7 -3
View File
@@ -331,9 +331,13 @@ static int azure_plugin_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
// error = handle_read_response(plugin, head->ctx, data);
break;
case NEU_REQRESP_TRANS_DATA: {
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1, NULL);
if (plugin->client && neu_mqtt_client_is_open(plugin->client)) {
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1,
NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1,
NULL);
}
error = azure_handle_trans_data(plugin, data);
break;
}
+246 -243
View File
@@ -1,244 +1,247 @@
{
"client-id": {
"name": "Client ID",
"name_zh": "客户端 ID",
"description": "MQTT client id",
"description_zh": "MQTT 客户端 ID",
"type": "string",
"attribute": "required",
"valid": {
"length": 255
}
},
"qos": {
"name": "QoS Level",
"name_zh": "QoS 等级",
"description": "MQTT QoS level for message delivery",
"description_zh": "MQTT 消息传输使用的服务质量等级",
"type": "map",
"attribute": "optional",
"default": 0,
"valid": {
"map": [
{
"key": "QoS 0",
"value": 0
},
{
"key": "QoS 1",
"value": 1
},
{
"key": "QoS 2",
"value": 2
}
]
}
},
"format": {
"name": "Upload Format",
"name_zh": "上报数据格式",
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
"attribute": "required",
"type": "map",
"default": 0,
"valid": {
"map": [
{
"key": "values-format",
"value": 0
},
{
"key": "tags-format",
"value": 1
}
]
}
},
"write-req-topic": {
"name": "Write Request Topic",
"name_zh": "写请求主题",
"description": "MQTT topic to receive write request messages.",
"description_zh": "接收点位写入请求的 MQTT 主题。",
"attribute": "required",
"type": "string",
"valid": {
"length": 255
}
},
"write-resp-topic": {
"name": "Write Response Topic",
"name_zh": "写响应主题",
"description": "MQTT topic to send write response messages.",
"description_zh": "发送点位写入响应的 MQTT 主题。",
"attribute": "required",
"type": "string",
"valid": {
"length": 255
}
},
"offline-cache": {
"name": "Offline Data Caching",
"name_zh": "离线缓存",
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"cache-mem-size": {
"name": "Cache Memory Size (MB)",
"name_zh": "缓存内存大小(MB)",
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 1024
}
},
"cache-disk-size": {
"name": "Cache Disk Size (MB)",
"name_zh": "缓存磁盘大小(MB)",
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 10240
}
},
"cache-sync-interval": {
"name": "Cache Sync Interval (MS)",
"name_zh": "缓存消息重传间隔(MS)",
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"default": 100,
"valid": {
"min": 10,
"max": 120000
}
},
"host": {
"name": "Broker Host",
"name_zh": "服务器地址",
"description": "MQTT broker host",
"description_zh": "MQTT 服务器地址",
"attribute": "required",
"type": "string",
"default": "broker.emqx.io",
"valid": {
"length": 255
}
},
"port": {
"name": "Broker Port",
"name_zh": "服务器端口",
"description": "MQTT broker port",
"description_zh": "MQTT 服务器端口",
"attribute": "required",
"type": "int",
"default": 1883,
"valid": {
"min": 1024,
"max": 65535
}
},
"username": {
"name": "Username",
"name_zh": "用户名",
"description": "MQTT user name",
"description_zh": "MQTT 用户名",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"password": {
"name": "Password",
"name_zh": "密码",
"description": "MQTT user password",
"description_zh": "MQTT 用户密码",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"ssl": {
"name": "SSL",
"name_zh": "SSL",
"description": "Enable SSL connection",
"description_zh": "是否启用 SSL 连接",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"ca": {
"name": "CA",
"name_zh": "CA 证书",
"description": "CA certificate which signs the server certificate",
"description_zh": "签发服务器证书的 CA 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"cert": {
"name": "Client Cert",
"name_zh": "客户端证书",
"description": "Client x509 certificate when using two way authentication",
"description_zh": "使用双向认证时,客户端的 x509 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"key": {
"name": "Client Private Key",
"name_zh": "客户端私钥",
"description": "Client private key when using two way authentication",
"description_zh": "使用双向认证时,客户端的私钥",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
}
}
"client-id": {
"name": "Client ID",
"name_zh": "客户端 ID",
"description": "MQTT client id",
"description_zh": "MQTT 客户端 ID",
"type": "string",
"attribute": "required",
"default": "neuron_${random_str}",
"valid": {
"length": 255
}
},
"qos": {
"name": "QoS Level",
"name_zh": "QoS 等级",
"description": "MQTT QoS level for message delivery",
"description_zh": "MQTT 消息传输使用的服务质量等级",
"type": "map",
"attribute": "optional",
"default": 0,
"valid": {
"map": [
{
"key": "QoS 0",
"value": 0
},
{
"key": "QoS 1",
"value": 1
},
{
"key": "QoS 2",
"value": 2
}
]
}
},
"format": {
"name": "Upload Format",
"name_zh": "上报数据格式",
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
"attribute": "required",
"type": "map",
"default": 0,
"valid": {
"map": [
{
"key": "values-format",
"value": 0
},
{
"key": "tags-format",
"value": 1
}
]
}
},
"write-req-topic": {
"name": "Write Request Topic",
"name_zh": "写请求主题",
"description": "MQTT topic to receive write request messages.",
"description_zh": "接收点位写入请求的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/req",
"valid": {
"length": 255
}
},
"write-resp-topic": {
"name": "Write Response Topic",
"name_zh": "写响应主题",
"description": "MQTT topic to send write response messages.",
"description_zh": "发送点位写入响应的 MQTT 主题。",
"attribute": "required",
"type": "string",
"default": "/neuron/${random_str}/write/resp",
"valid": {
"length": 255
}
},
"offline-cache": {
"name": "Offline Data Caching",
"name_zh": "离线缓存",
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"cache-mem-size": {
"name": "Cache Memory Size (MB)",
"name_zh": "缓存内存大小(MB)",
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 1024
}
},
"cache-disk-size": {
"name": "Cache Disk Size (MB)",
"name_zh": "缓存磁盘大小(MB)",
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"valid": {
"min": 1,
"max": 10240
}
},
"cache-sync-interval": {
"name": "Cache Sync Interval (MS)",
"name_zh": "缓存消息重传间隔(MS)",
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
"type": "int",
"attribute": "required",
"condition": {
"field": "offline-cache",
"value": true
},
"default": 100,
"valid": {
"min": 10,
"max": 120000
}
},
"host": {
"name": "Broker Host",
"name_zh": "服务器地址",
"description": "MQTT broker host",
"description_zh": "MQTT 服务器地址",
"attribute": "required",
"type": "string",
"default": "broker.emqx.io",
"valid": {
"length": 255
}
},
"port": {
"name": "Broker Port",
"name_zh": "服务器端口",
"description": "MQTT broker port",
"description_zh": "MQTT 服务器端口",
"attribute": "required",
"type": "int",
"default": 1883,
"valid": {
"min": 1,
"max": 65535
}
},
"username": {
"name": "Username",
"name_zh": "用户名",
"description": "MQTT user name",
"description_zh": "MQTT 用户名",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"password": {
"name": "Password",
"name_zh": "密码",
"description": "MQTT user password",
"description_zh": "MQTT 用户密码",
"attribute": "optional",
"type": "string",
"default": "",
"valid": {
"length": 255
}
},
"ssl": {
"name": "SSL",
"name_zh": "SSL",
"description": "Enable SSL connection",
"description_zh": "是否启用 SSL 连接",
"attribute": "optional",
"type": "bool",
"default": false,
"valid": {}
},
"ca": {
"name": "CA",
"name_zh": "CA 证书",
"description": "CA certificate which signs the server certificate",
"description_zh": "签发服务器证书的 CA 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"cert": {
"name": "Client Cert",
"name_zh": "客户端证书",
"description": "Client x509 certificate when using two way authentication",
"description_zh": "使用双向认证时,客户端的 x509 证书",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
},
"key": {
"name": "Client Private Key",
"name_zh": "客户端私钥",
"description": "Client private key when using two way authentication",
"description_zh": "使用双向认证时,客户端的私钥",
"attribute": "optional",
"type": "file",
"condition": {
"field": "ssl",
"value": true
},
"valid": {
"length": 81960
}
}
}
+17 -5
View File
@@ -374,9 +374,13 @@ int mqtt_plugin_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
error = handle_read_response(plugin, head->ctx, data);
break;
case NEU_REQRESP_TRANS_DATA: {
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1, NULL);
if (plugin->client && neu_mqtt_client_is_open(plugin->client)) {
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_5S, 1, NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_30S, 1,
NULL);
NEU_PLUGIN_UPDATE_METRIC(plugin, NEU_METRIC_TRANS_DATA_60S, 1,
NULL);
}
error = handle_trans_data(plugin, data);
break;
}
@@ -398,9 +402,17 @@ int mqtt_plugin_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
case NEU_REQ_UPDATE_NODE:
error = handle_update_driver(plugin, data);
break;
case NEU_REQRESP_NODE_DELETED:
error = handle_del_driver(plugin, data);
case NEU_REQRESP_NODE_DELETED: {
neu_reqresp_node_deleted_t *req = data;
if (0 != strcmp(plugin->common.name, req->node)) {
error = handle_del_driver(plugin, data);
} else {
if (plugin->client) {
neu_mqtt_client_remove_cache_db(plugin->client);
}
}
break;
}
default:
error = NEU_ERR_MQTT_FAILURE;
break;
+34
View File
@@ -33,6 +33,7 @@
#include "normal_handle.h"
#include "plugin_handle.h"
#include "rw_handle.h"
#include "scan_handle.h"
#include "utils/http.h"
#include "version_handle.h"
@@ -72,6 +73,12 @@ static struct neu_http_handler cors_handler[] = {
{
.url = "/api/v2/read",
},
{
.url = "/api/v2/read/paginate",
},
{
.url = "/api/v2/read/test",
},
{
.url = "/api/v2/write",
},
@@ -117,6 +124,9 @@ static struct neu_http_handler cors_handler[] = {
{
.url = "/api/v2/metrics",
},
{
.url = "/api/v2/scan/tags",
},
};
static struct neu_http_handler rest_handlers[] = {
@@ -259,6 +269,18 @@ static struct neu_http_handler rest_handlers[] = {
.url = "/api/v2/read",
.value.handler = handle_read,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/read/paginate",
.value.handler = handle_read_paginate,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/read/test",
.value.handler = handle_test_read_tag,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
@@ -379,6 +401,18 @@ static struct neu_http_handler rest_handlers[] = {
.url = "/api/v2/metrics",
.value.handler = handle_get_metric,
},
{
.method = NEU_HTTP_METHOD_POST,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/scan/tags",
.value.handler = handle_scan_tags,
},
{
.method = NEU_HTTP_METHOD_GET,
.type = NEU_HTTP_HANDLER_FUNCTION,
.url = "/api/v2/status",
.value.handler = handle_status,
},
};
void neu_rest_handler(const struct neu_http_handler **handlers, uint32_t *size)
+19
View File
@@ -328,3 +328,22 @@ void handle_get_plugin_schema(nng_aio *aio)
free(buf);
free(schema_path);
}
void handle_status(nng_aio *aio)
{
char *result = NULL;
NEU_VALIDATE_JWT(aio);
int ret = neu_asprintf(&result, "{\"status\":\"%s\"}", g_status);
if (ret < 0) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_EINTERNAL, {
neu_http_response(aio, error_code.error, result_error);
});
return;
}
neu_http_response(aio, 0, result);
free(result);
}
+1
View File
@@ -26,5 +26,6 @@ void handle_ping(nng_aio *aio);
void handle_login(nng_aio *aio);
void handle_password(nng_aio *aio);
void handle_get_plugin_schema(nng_aio *aio);
void handle_status(nng_aio *aio);
#endif
+12
View File
@@ -34,6 +34,7 @@
#include "plugin_handle.h"
#include "rest.h"
#include "rw_handle.h"
#include "scan_handle.h"
#include "utils/http.h"
#include "utils/log.h"
#include "utils/neu_jwt.h"
@@ -223,6 +224,17 @@ static int dashb_plugin_request(neu_plugin_t * plugin,
case NEU_RESP_READ_GROUP:
handle_read_resp(header->ctx, (neu_resp_read_group_t *) data);
break;
case NEU_RESP_READ_GROUP_PAGINATE:
handle_read_paginate_resp(header->ctx,
(neu_resp_read_group_paginate_t *) data);
break;
case NEU_RESP_TEST_READ_TAG:
handle_test_read_tag_resp(header->ctx,
(neu_resp_test_read_tag_t *) data);
break;
case NEU_RESP_SCAN_TAGS:
handle_scan_tags_resp(header->ctx, (neu_resp_scan_tags_t *) data);
break;
default:
nlog_fatal("recv unhandle msg: %s",
neu_reqresp_type_string(header->type));
+259
View File
@@ -80,6 +80,117 @@ void handle_read(nng_aio *aio)
})
}
void handle_read_paginate(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_read_paginate_req_t, neu_json_decode_read_paginate_req, {
int ret = 0;
neu_reqresp_head_t header = { 0 };
neu_req_read_group_paginate_t cmd = { 0 };
int err_type;
header.ctx = aio;
header.type = NEU_REQ_READ_GROUP_PAGINATE;
if (strlen(req->node) >= NEU_NODE_NAME_LEN) {
err_type = NEU_ERR_NODE_NAME_TOO_LONG;
goto error;
}
if (strlen(req->node) >= NEU_GROUP_NAME_LEN) {
err_type = NEU_ERR_GROUP_NAME_TOO_LONG;
goto error;
}
if (strlen(req->node) >= NEU_TAG_NAME_LEN) {
err_type = NEU_ERR_TAG_NAME_TOO_LONG;
goto error;
}
cmd.driver = req->node;
cmd.group = req->group;
cmd.name = req->name;
cmd.desc = req->desc;
cmd.sync = req->sync;
cmd.current_page = req->current_page;
cmd.page_size = req->page_size;
cmd.is_error = req->is_error;
req->node = NULL;
req->group = NULL;
ret = neu_plugin_op(plugin, header, &cmd);
if (ret != 0) {
neu_req_read_group_paginate_fini(&cmd);
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
goto success;
error:
NEU_JSON_RESPONSE_ERROR(
err_type, { neu_http_response(aio, err_type, result_error); });
success:;
})
}
void handle_test_read_tag(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_test_read_tag_req_t, neu_json_decode_test_read_tag_req, {
int ret = 0;
neu_reqresp_head_t header = { 0 };
neu_req_test_read_tag_t cmd = { 0 };
int err_type;
header.ctx = aio;
header.type = NEU_REQ_TEST_READ_TAG;
if (req->driver && strlen(req->driver) >= NEU_NODE_NAME_LEN) {
err_type = NEU_ERR_NODE_NAME_TOO_LONG;
goto error;
}
if (req->group && strlen(req->group) >= NEU_GROUP_NAME_LEN) {
err_type = NEU_ERR_GROUP_NAME_TOO_LONG;
goto error;
}
if (req->tag && strlen(req->tag) >= NEU_TAG_NAME_LEN) {
err_type = NEU_ERR_TAG_NAME_TOO_LONG;
goto error;
}
if (req->address && strlen(req->address) >= NEU_TAG_ADDRESS_LEN) {
err_type = NEU_ERR_TAG_ADDRESS_TOO_LONG;
goto error;
}
strcpy(cmd.driver, req->driver);
strcpy(cmd.group, req->group);
strcpy(cmd.tag, req->tag);
strcpy(cmd.address, req->address);
cmd.attribute = req->attribute;
cmd.type = req->type;
cmd.precision = req->precision;
cmd.decimal = req->decimal;
cmd.bias = req->bias;
ret = neu_plugin_op(plugin, header, &cmd);
if (ret != 0) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
goto success;
error:
NEU_JSON_RESPONSE_ERROR(
err_type, { neu_http_response(aio, err_type, result_error); });
success:;
})
}
void handle_write(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
@@ -384,3 +495,151 @@ void handle_read_resp(nng_aio *aio, neu_resp_read_group_t *resp)
free(api_res.tags);
free(result);
}
void handle_read_paginate_resp(nng_aio * aio,
neu_resp_read_group_paginate_t *resp)
{
neu_json_read_paginate_resp_t api_res = { 0 };
char * result = NULL;
unsigned int total_tags = resp->total_count;
if (resp->is_error) {
UT_array *filtered_tags;
utarray_new(filtered_tags, neu_resp_tag_value_meta_paginate_icd());
utarray_foreach(resp->tags, neu_resp_tag_value_meta_paginate_t *,
tag_value)
{
if (tag_value->value.type == NEU_TYPE_ERROR) {
neu_resp_tag_value_meta_paginate_t new_tag_value;
memcpy(&new_tag_value, tag_value,
sizeof(neu_resp_tag_value_meta_paginate_t));
new_tag_value.datatag.name = strdup(tag_value->datatag.name);
new_tag_value.datatag.address =
strdup(tag_value->datatag.address);
new_tag_value.datatag.description =
strdup(tag_value->datatag.description);
utarray_push_back(filtered_tags, &new_tag_value);
}
}
for (unsigned int i = 0; i < utarray_len(resp->tags); ++i) {
neu_resp_tag_value_meta_paginate_t *orig_tag_value;
orig_tag_value =
(neu_resp_tag_value_meta_paginate_t *) utarray_eltptr(
resp->tags, i);
if (orig_tag_value) {
free(orig_tag_value->datatag.name);
free(orig_tag_value->datatag.address);
free(orig_tag_value->datatag.description);
}
}
utarray_free(resp->tags);
resp->tags = filtered_tags;
total_tags = utarray_len(resp->tags);
if (resp->current_page > 0 && resp->page_size > 0) {
unsigned int start_index =
(resp->current_page - 1) * resp->page_size;
unsigned int end_index = start_index + resp->page_size;
if (start_index >= total_tags) {
api_res.n_tag = 0;
api_res.tags =
calloc(1, sizeof(neu_json_read_paginate_resp_tag_t));
} else {
if (end_index > total_tags) {
end_index = total_tags;
}
api_res.n_tag = end_index - start_index;
api_res.tags = calloc(
api_res.n_tag, sizeof(neu_json_read_paginate_resp_tag_t));
for (unsigned int i = start_index; i < end_index; i++) {
neu_resp_tag_value_meta_paginate_t *tag_value =
(neu_resp_tag_value_meta_paginate_t *) utarray_eltptr(
resp->tags, i);
neu_tag_value_to_json_paginate(
tag_value, &api_res.tags[i - start_index]);
}
}
} else {
api_res.n_tag = total_tags;
api_res.tags = calloc(api_res.n_tag,
sizeof(neu_json_read_paginate_resp_tag_t));
int index = 0;
utarray_foreach(resp->tags, neu_resp_tag_value_meta_paginate_t *,
tag_value)
{
neu_tag_value_to_json_paginate(tag_value,
&api_res.tags[index++]);
}
}
} else {
if (resp->current_page > 0 && resp->page_size > 0) {
api_res.n_tag = utarray_len(resp->tags);
api_res.tags = calloc(api_res.n_tag,
sizeof(neu_json_read_paginate_resp_tag_t));
int index = 0;
utarray_foreach(resp->tags, neu_resp_tag_value_meta_paginate_t *,
tag_value)
{
neu_tag_value_to_json_paginate(tag_value,
&api_res.tags[index++]);
}
} else {
api_res.n_tag = total_tags;
api_res.tags = calloc(api_res.n_tag,
sizeof(neu_json_read_paginate_resp_tag_t));
int index = 0;
utarray_foreach(resp->tags, neu_resp_tag_value_meta_paginate_t *,
tag_value)
{
neu_tag_value_to_json_paginate(tag_value,
&api_res.tags[index++]);
}
}
}
api_res.meta.current_page = resp->current_page;
api_res.meta.page_size = resp->page_size;
api_res.meta.total = total_tags;
neu_json_encode_by_fn(&api_res, neu_json_encode_read_paginate_resp,
&result);
for (unsigned int i = 0; i < utarray_len(resp->tags); ++i) {
neu_resp_tag_value_meta_paginate_t *final_tag_value;
final_tag_value = (neu_resp_tag_value_meta_paginate_t *) utarray_eltptr(
resp->tags, i);
if (final_tag_value) {
free(final_tag_value->datatag.name);
free(final_tag_value->datatag.address);
free(final_tag_value->datatag.description);
}
}
for (int i = 0; i < api_res.n_tag; i++) {
if (api_res.tags[i].n_meta > 0) {
free(api_res.tags[i].metas);
}
}
neu_http_ok(aio, result);
free(api_res.tags);
free(result);
}
void handle_test_read_tag_resp(nng_aio *aio, neu_resp_test_read_tag_t *resp)
{
char *result = NULL;
neu_json_encode_by_fn(resp, neu_json_encode_test_read_tag_resp, &result);
neu_http_ok(aio, result);
free(result);
}
+5
View File
@@ -27,9 +27,14 @@
void handle_rw_init();
void handle_rw_uninit();
void handle_read(nng_aio *aio);
void handle_read_paginate(nng_aio *aio);
void handle_test_read_tag(nng_aio *aio);
void handle_write(nng_aio *aio);
void handle_write_tags(nng_aio *aio);
void handle_write_gtags(nng_aio *aio);
void handle_read_resp(nng_aio *aio, neu_resp_read_group_t *resp);
void handle_read_paginate_resp(nng_aio * aio,
neu_resp_read_group_paginate_t *resp);
void handle_test_read_tag_resp(nng_aio *aio, neu_resp_test_read_tag_t *resp);
#endif
+68
View File
@@ -0,0 +1,68 @@
#include <stdlib.h>
#include "plugin.h"
#include "utils/log.h"
#include "json/neu_json_fn.h"
#include "json/neu_json_scan.h"
#include "handle.h"
#include "utils/http.h"
#include "scan_handle.h"
void handle_scan_tags(nng_aio *aio)
{
neu_plugin_t *plugin = neu_rest_get_plugin();
NEU_PROCESS_HTTP_REQUEST_VALIDATE_JWT(
aio, neu_json_scan_tags_req_t, neu_json_decode_scan_tags_req, {
neu_reqresp_head_t header = { 0 };
neu_req_scan_tags_t cmd = { 0 };
int err_type;
nng_http_req *nng_req = nng_aio_get_input(aio, 0);
nlog_notice("<%p> req %s %s", aio, nng_http_req_get_method(nng_req),
nng_http_req_get_uri(nng_req));
header.ctx = aio;
header.type = NEU_REQ_SCAN_TAGS;
if (NULL != req->node && NEU_NODE_NAME_LEN <= strlen(req->node)) {
err_type = NEU_ERR_NODE_NAME_TOO_LONG;
goto error;
}
if (NULL != req->id && NEU_TAG_ADDRESS_LEN <= strlen(req->id)) {
err_type = NEU_ERR_NODE_NAME_TOO_LONG;
goto error;
}
if (NULL != req->node) {
strcpy(cmd.driver, req->node);
}
if (NULL != req->id) {
strcpy(cmd.id, req->id);
}
if (0 != neu_plugin_op(plugin, header, &cmd)) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_IS_BUSY, {
neu_http_response(aio, NEU_ERR_IS_BUSY, result_error);
});
}
goto success;
error:
NEU_JSON_RESPONSE_ERROR(
err_type, { neu_http_response(aio, err_type, result_error); });
success:;
})
}
void handle_scan_tags_resp(nng_aio *aio, neu_resp_scan_tags_t *resp)
{
char *result = NULL;
neu_json_encode_by_fn(resp, neu_json_encode_scan_tags_resp, &result);
neu_http_ok(aio, result);
free(result);
}
+29
View File
@@ -0,0 +1,29 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#ifndef _NEU_SCAN_HANDLE_H_
#define _NEU_ACAN_HANDLE_H_
#include <nng/nng.h>
void handle_scan_tags(nng_aio *aio);
void handle_scan_tags_resp(nng_aio *aio, neu_resp_scan_tags_t *resp);
void handle_scan_tag(nng_aio *aio);
#endif
+69 -4
View File
@@ -444,6 +444,17 @@ static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
strcpy(pheader->receiver, cmd->driver);
break;
}
case NEU_REQ_READ_GROUP_PAGINATE: {
neu_req_read_group_paginate_t *cmd =
(neu_req_read_group_paginate_t *) data;
strcpy(pheader->receiver, cmd->driver);
break;
}
case NEU_REQ_TEST_READ_TAG: {
neu_req_test_read_tag_t *cmd = (neu_req_test_read_tag_t *) data;
strcpy(pheader->receiver, cmd->driver);
break;
}
case NEU_REQ_WRITE_TAG: {
neu_req_write_tag_t *cmd = (neu_req_write_tag_t *) data;
strcpy(pheader->receiver, cmd->driver);
@@ -523,6 +534,11 @@ static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
strcpy(pheader->receiver, header.sender);
break;
}
case NEU_REQ_SCAN_TAGS: {
neu_req_scan_tags_t *cmd = (neu_req_scan_tags_t *) data;
strcpy(pheader->receiver, cmd->driver);
break;
}
default:
break;
}
@@ -727,6 +743,30 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
break;
}
case NEU_RESP_READ_GROUP_PAGINATE:
adapter->module->intf_funs->request(
adapter->plugin, (neu_reqresp_head_t *) header, &header[1]);
neu_resp_read_paginate_free(
(neu_resp_read_group_paginate_t *) &header[1]);
neu_msg_free(msg);
break;
case NEU_REQ_READ_GROUP_PAGINATE: {
neu_resp_error_t error = { 0 };
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
neu_adapter_driver_read_group_paginate(
(neu_adapter_driver_t *) adapter, header);
} else {
neu_req_read_group_paginate_fini(
(neu_req_read_group_paginate_t *) &header[1]);
error.error = NEU_ERR_GROUP_NOT_ALLOW;
header->type = NEU_RESP_ERROR;
neu_msg_exchange(header);
reply(adapter, header, &error);
}
break;
}
case NEU_REQ_WRITE_TAG: {
neu_resp_error_t error = { 0 };
@@ -776,7 +816,7 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_NODE_SETTING: {
neu_req_node_setting_t *cmd = (neu_req_node_setting_t *) &header[1];
neu_resp_error_t error = { 0 };
nlog_notice("setting node:%s params:%s", cmd->node, cmd->setting);
error.error = neu_adapter_set_setting(adapter, cmd->setting);
if (error.error == NEU_ERR_SUCCESS) {
adapter_storage_setting(adapter->name, cmd->setting);
@@ -869,7 +909,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_ADD_GROUP: {
neu_req_add_group_t *cmd = (neu_req_add_group_t *) &header[1];
neu_resp_error_t error = { 0 };
nlog_notice("add group node:%s group:%s interval:%d", cmd->driver,
cmd->group, cmd->interval);
if (cmd->interval < NEU_GROUP_INTERVAL_LIMIT) {
error.error = NEU_ERR_GROUP_PARAMETER_INVALID;
} else {
@@ -894,7 +935,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_UPDATE_DRIVER_GROUP: {
neu_req_update_group_t *cmd = (neu_req_update_group_t *) &header[1];
neu_resp_update_group_t resp = { 0 };
nlog_notice("update group node:%s old_name:%s new_name:%s interval:%d",
header->receiver, cmd->group, cmd->new_name, cmd->interval);
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
resp.error = neu_adapter_driver_update_group(
(neu_adapter_driver_t *) adapter, cmd->group, cmd->new_name,
@@ -919,7 +961,7 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_DEL_GROUP: {
neu_req_del_group_t *cmd = (neu_req_del_group_t *) &header[1];
neu_resp_error_t error = { 0 };
nlog_notice("del group node:%s group:%s", cmd->driver, cmd->group);
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
error.error = neu_adapter_driver_del_group(
(neu_adapter_driver_t *) adapter, cmd->group);
@@ -975,6 +1017,8 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
if (adapter->module->type == NEU_NA_TYPE_DRIVER) {
for (int i = 0; i < cmd->n_tag; i++) {
nlog_notice("del tag node:%s group:%s tag:%s", cmd->driver,
cmd->group, cmd->tags[i]);
int ret = neu_adapter_driver_del_tag(
(neu_adapter_driver_t *) adapter, cmd->group, cmd->tags[i]);
if (0 == ret) {
@@ -1181,6 +1225,27 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
adapter->plugin, (neu_reqresp_head_t *) header, &header[1]);
break;
}
case NEU_REQ_SCAN_TAGS: {
neu_adapter_driver_scan_tags((neu_adapter_driver_t *) adapter, header);
break;
}
case NEU_RESP_SCAN_TAGS: {
adapter->module->intf_funs->request(
adapter->plugin, (neu_reqresp_head_t *) header, &header[1]);
neu_msg_free(msg);
break;
}
case NEU_REQ_TEST_READ_TAG: {
neu_adapter_driver_test_read_tag((neu_adapter_driver_t *) adapter,
header);
break;
}
case NEU_RESP_TEST_READ_TAG: {
adapter->module->intf_funs->request(
adapter->plugin, (neu_reqresp_head_t *) header, &header[1]);
neu_msg_free(msg);
break;
}
default:
nlog_warn("adapter: %s recv msg type error, type: %s", adapter->name,
neu_reqresp_type_string(header->type));
+95 -1
View File
@@ -29,6 +29,8 @@
#include "cache.h"
extern bool sub_filter_err;
typedef struct {
char group[NEU_GROUP_NAME_LEN];
char tag[NEU_TAG_NAME_LEN];
@@ -39,6 +41,7 @@ struct elem {
bool changed;
neu_dvalue_t value;
neu_dvalue_t value_old;
neu_tag_meta_t metas[NEU_TAG_META_SIZE];
@@ -142,8 +145,91 @@ void neu_driver_cache_update_change(neu_driver_cache_t *cache,
HASH_FIND(hh, cache->table, &key, sizeof(tkey_t), elem);
if (elem != NULL) {
elem->timestamp = timestamp;
if (elem->value.type != value.type) {
if (sub_filter_err && value.type == NEU_TYPE_ERROR) {
goto error_not_report;
}
if ((!sub_filter_err && elem->value.type != value.type) ||
(sub_filter_err && elem->value.type != value.type &&
elem->value.type != NEU_TYPE_ERROR)) {
elem->changed = true;
} else if (sub_filter_err && elem->value.type != value.type &&
elem->value.type == NEU_TYPE_ERROR) {
switch (value.type) {
case NEU_TYPE_INT8:
case NEU_TYPE_UINT8:
case NEU_TYPE_INT16:
case NEU_TYPE_UINT16:
case NEU_TYPE_INT32:
case NEU_TYPE_UINT32:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
case NEU_TYPE_BIT:
case NEU_TYPE_BOOL:
case NEU_TYPE_STRING:
case NEU_TYPE_TIME:
case NEU_TYPE_DATA_AND_TIME:
case NEU_TYPE_WORD:
case NEU_TYPE_DWORD:
case NEU_TYPE_LWORD:
if (memcmp(&elem->value_old.value, &value.value,
sizeof(value.value)) != 0) {
elem->changed = true;
}
break;
case NEU_TYPE_BYTES:
if (elem->value_old.value.bytes.length !=
value.value.bytes.length) {
elem->changed = true;
} else {
if (memcpy(elem->value_old.value.bytes.bytes,
value.value.bytes.bytes,
value.value.bytes.length) != 0) {
elem->changed = true;
}
}
break;
case NEU_TYPE_PTR: {
if (elem->value_old.value.ptr.length !=
value.value.ptr.length) {
elem->changed = true;
} else {
if (memcmp(elem->value_old.value.ptr.ptr,
value.value.ptr.ptr,
value.value.ptr.length) != 0) {
elem->changed = true;
}
}
break;
}
case NEU_TYPE_FLOAT:
if (elem->value_old.precision == 0) {
elem->changed =
elem->value_old.value.f32 != value.value.f32;
} else {
if (fabs(elem->value_old.value.f32 - value.value.f32) >
pow(0.1, elem->value_old.precision)) {
elem->changed = true;
}
}
break;
case NEU_TYPE_DOUBLE:
if (elem->value_old.precision == 0) {
elem->changed =
elem->value_old.value.d64 != value.value.d64;
} else {
if (fabs(elem->value_old.value.d64 - value.value.d64) >
pow(0.1, elem->value_old.precision)) {
elem->changed = true;
}
}
break;
case NEU_TYPE_ERROR:
break;
}
} else {
switch (value.type) {
case NEU_TYPE_INT8:
@@ -218,6 +304,14 @@ void neu_driver_cache_update_change(neu_driver_cache_t *cache,
}
}
if (sub_filter_err && value.type != NEU_TYPE_ERROR) {
elem->value_old.type = value.type;
elem->value_old.value = value.value;
elem->value_old.precision = value.precision;
}
error_not_report:
if (change) {
elem->changed = true;
}
+493 -31
View File
@@ -92,6 +92,10 @@ static void read_group(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
UT_array *tags, UT_array *tag_values);
static void read_group_paginate(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
UT_array *tags, UT_array *tag_values);
static void read_report_group(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
@@ -111,6 +115,33 @@ static inline void start_group_timer(neu_adapter_driver_t *driver,
group_t * grp);
static inline void stop_group_timer(neu_adapter_driver_t *driver, group_t *grp);
static void format_tag_value(neu_dvalue_t *value)
{
double scale = pow(10, 5);
int64_t integer_part = (int64_t) value->value.d64;
double decimal_part = value->value.d64 - integer_part;
decimal_part *= scale;
decimal_part = round(decimal_part);
char str[6] = { 0 };
snprintf(str, sizeof(str), "%05" PRId64 "", (int64_t) decimal_part);
int i = 0, flag = 0;
for (; i < 4; i++) {
if (str[i] == '0' && str[i + 1] == '0') {
flag = 1;
break;
} else if (str[i] == '9' && str[i + 1] == '9') {
flag = 2;
break;
}
}
if (flag != 0 && i != 0) {
decimal_part = round(decimal_part / pow(10, 5 - i));
value->value.d64 = (double) integer_part + decimal_part / pow(10, i);
} else {
value->value.d64 = (double) integer_part + decimal_part / scale;
}
}
static void write_response(neu_adapter_t *adapter, void *r, neu_error error)
{
neu_reqresp_head_t *req = (neu_reqresp_head_t *) r;
@@ -187,14 +218,8 @@ static void update_im(neu_adapter_t *adapter, const char *group,
{
neu_adapter_driver_t *driver = (neu_adapter_driver_t *) adapter;
if (tag == NULL || value.type == NEU_TYPE_ERROR) {
nlog_warn("update_im tag is null or value is error %d",
value.value.i32);
return;
}
UT_array *tags = neu_adapter_driver_get_ptag(driver, group, tag);
if (tags == NULL) {
if (tag == NULL) {
nlog_warn("update_im tag is null");
return;
}
@@ -202,10 +227,17 @@ static void update_im(neu_adapter_t *adapter, const char *group,
value, metas, n_meta, true);
driver->adapter.cb_funs.update_metric(&driver->adapter,
NEU_METRIC_TAG_READS_TOTAL, 1, NULL);
if (value.type == NEU_TYPE_ERROR) {
return;
}
UT_array *tags = neu_adapter_driver_get_ptag(driver, group, tag);
if (tags == NULL) {
return;
}
neu_datatag_t *first = utarray_front(tags);
if (first == NULL ||
!neu_tag_attribute_test(first, NEU_ATTRIBUTE_SUBSCRIBE)) {
if (first == NULL) {
utarray_free(tags);
nlog_debug("update immediately, driver: %s, "
"group: %s, tag: %s, type: %s, "
@@ -294,16 +326,52 @@ static void update(neu_adapter_t *adapter, const char *group, const char *tag,
update_with_meta(adapter, group, tag, value, NULL, 0);
}
static void scan_tags_response(neu_adapter_t *adapter, void *r, neu_error error,
void *tags, neu_type_e type, bool is_array)
{
neu_reqresp_head_t * req = (neu_reqresp_head_t *) r;
neu_resp_scan_tags_t value = {
.scan_tags = tags,
.error = error,
.type = type,
.is_array = is_array,
};
req->type = NEU_RESP_SCAN_TAGS;
nlog_notice("scan tags response <%p>", req->ctx);
adapter->cb_funs.response(adapter, req, &value);
}
static void test_read_tag_response(neu_adapter_t *adapter, void *r,
neu_json_type_e t, neu_type_e type,
neu_json_value_u value, int64_t error)
{
neu_reqresp_head_t * req = (neu_reqresp_head_t *) r;
neu_resp_test_read_tag_t dvalue = {
.t = t,
.type = type,
.value = value,
.error = error,
};
req->type = NEU_RESP_TEST_READ_TAG;
nlog_notice("test reading tag response <%p>", req->ctx);
adapter->cb_funs.response(adapter, req, &dvalue);
}
neu_adapter_driver_t *neu_adapter_driver_create()
{
neu_adapter_driver_t *driver = calloc(1, sizeof(neu_adapter_driver_t));
driver->cache = neu_driver_cache_new();
driver->driver_events = neu_event_new();
driver->adapter.cb_funs.driver.update = update;
driver->adapter.cb_funs.driver.write_response = write_response;
driver->adapter.cb_funs.driver.update_im = update_im;
driver->adapter.cb_funs.driver.update_with_meta = update_with_meta;
driver->cache = neu_driver_cache_new();
driver->driver_events = neu_event_new();
driver->adapter.cb_funs.driver.update = update;
driver->adapter.cb_funs.driver.write_response = write_response;
driver->adapter.cb_funs.driver.update_im = update_im;
driver->adapter.cb_funs.driver.update_with_meta = update_with_meta;
driver->adapter.cb_funs.driver.scan_tags_response = scan_tags_response;
driver->adapter.cb_funs.driver.test_read_tag_response =
test_read_tag_response;
return driver;
}
@@ -497,6 +565,115 @@ void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
driver->adapter.cb_funs.response(&driver->adapter, req, &resp);
}
void neu_adapter_driver_read_group_paginate(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req)
{
neu_req_read_group_paginate_t *cmd =
(neu_req_read_group_paginate_t *) &req[1];
group_t *g = find_group(driver, cmd->group);
if (g == NULL) {
neu_resp_error_t error = { .error = NEU_ERR_GROUP_NOT_EXIST };
req->type = NEU_RESP_ERROR;
neu_req_read_group_paginate_fini(cmd);
driver->adapter.cb_funs.response(&driver->adapter, req, &error);
return;
}
neu_resp_read_group_paginate_t resp = { 0 };
neu_group_t * group = g->group;
UT_array * tags;
if (cmd->is_error != true && cmd->current_page > 0 && cmd->page_size > 0) {
tags = neu_group_query_read_tag_paginate(
group, cmd->name, cmd->desc, cmd->current_page, cmd->page_size,
&resp.total_count);
} else {
tags = neu_group_query_read_tag(group, cmd->name, cmd->desc);
resp.total_count = utarray_len(tags);
}
utarray_new(resp.tags, neu_resp_tag_value_meta_paginate_icd());
if (driver->adapter.state != NEU_NODE_RUNNING_STATE_RUNNING) {
utarray_foreach(tags, neu_datatag_t *, tag)
{
neu_resp_tag_value_meta_paginate_t tag_value = { 0 };
strcpy(tag_value.tag, tag->name);
tag_value.value.type = NEU_TYPE_ERROR;
tag_value.value.value.i32 = NEU_ERR_PLUGIN_NOT_RUNNING;
tag_value.datatag.name = strdup(tag->name);
tag_value.datatag.address = strdup(tag->address);
tag_value.datatag.attribute = tag->attribute;
tag_value.datatag.type = tag->type;
tag_value.datatag.precision = tag->precision;
tag_value.datatag.decimal = tag->decimal;
tag_value.datatag.bias = tag->bias;
tag_value.datatag.description = strdup(tag->description);
tag_value.datatag.option = tag->option;
memcpy(tag_value.datatag.meta, tag->meta, NEU_TAG_META_LENGTH);
utarray_push_back(resp.tags, &tag_value);
}
} else if (cmd->sync) {
if (NULL == driver->adapter.module->intf_funs->driver.group_sync) {
// plugin does not support sync read
utarray_foreach(tags, neu_datatag_t *, tag)
{
neu_resp_tag_value_meta_paginate_t tag_value = { 0 };
strcpy(tag_value.tag, tag->name);
tag_value.value.type = NEU_TYPE_ERROR;
tag_value.value.value.i32 =
NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC;
tag_value.datatag.name = strdup(tag->name);
tag_value.datatag.address = strdup(tag->address);
tag_value.datatag.attribute = tag->attribute;
tag_value.datatag.type = tag->type;
tag_value.datatag.precision = tag->precision;
tag_value.datatag.decimal = tag->decimal;
tag_value.datatag.bias = tag->bias;
tag_value.datatag.description = strdup(tag->description);
tag_value.datatag.option = tag->option;
memcpy(tag_value.datatag.meta, tag->meta, NEU_TAG_META_LENGTH);
utarray_push_back(resp.tags, &tag_value);
}
} else {
// sync read to update cache
driver->adapter.module->intf_funs->driver.group_sync(
driver->adapter.plugin, &g->grp);
// fetch updated data from cache
read_group_paginate(
global_timestamp,
neu_group_get_interval(group) *
NEU_DRIVER_TAG_CACHE_EXPIRE_TIME,
neu_adapter_get_tag_cache_type(&driver->adapter), driver->cache,
cmd->group, tags, resp.tags);
}
} else {
read_group_paginate(global_timestamp,
neu_group_get_interval(group) *
NEU_DRIVER_TAG_CACHE_EXPIRE_TIME,
neu_adapter_get_tag_cache_type(&driver->adapter),
driver->cache, cmd->group, tags, resp.tags);
}
resp.driver = cmd->driver;
resp.group = cmd->group;
resp.current_page = cmd->current_page;
resp.page_size = cmd->page_size;
resp.is_error = cmd->is_error;
cmd->driver = NULL; // ownership moved
cmd->group = NULL; // ownership moved
utarray_free(tags);
neu_req_read_group_paginate_fini(cmd);
req->type = NEU_RESP_READ_GROUP_PAGINATE;
driver->adapter.cb_funs.response(&driver->adapter, req, &resp);
}
static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
neu_dvalue_t *value)
{
@@ -682,7 +859,8 @@ int check_value_decimal(neu_type_e write_type, double result, int64_t value_min,
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (result < value_min || result > value_max) {
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
} else if (almost_equal(ceil(result), result, EPSILON)) {
} else if (almost_equal(ceil(result), result, EPSILON) ||
almost_equal(floor(result), result, EPSILON)) {
return NEU_ERR_SUCCESS;
} else {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
@@ -732,7 +910,8 @@ int is_value_in_range(neu_type_e tag_type, int64_t value, double value_d,
case NEU_TYPE_UINT64:
if (write_type != NEU_TYPE_INT64 && write_type != NEU_TYPE_DOUBLE) {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
} else if (almost_equal(ceil(result), result, EPSILON)) {
} else if (almost_equal(ceil(result), result, EPSILON) ||
almost_equal(floor(result), result, EPSILON)) {
return NEU_ERR_SUCCESS;
} else {
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
@@ -1147,6 +1326,7 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
find->name = strdup(name);
find->group = neu_group_new(name, interval);
find->grp.group_name = strdup(name);
find->grp.interval = interval;
neu_group_split_static_tags(find->group, &find->static_tags,
&find->grp.tags);
@@ -1196,6 +1376,8 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
return NEU_ERR_GROUP_EXIST;
}
}
} else if (neu_group_get_interval(find->group) == interval) {
return 0; // no change
}
// stop the timer first to avoid race condition
@@ -1221,7 +1403,6 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
find->grp.group_name = new_name_cp2;
neu_adapter_metric_update_group_name((neu_adapter_t *) driver, name,
new_name);
find->timestamp = global_timestamp; // trigger group_change
HASH_ADD_STR(driver->groups, name, find);
} else {
free(new_name_cp1);
@@ -1230,6 +1411,8 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
}
}
find->timestamp = global_timestamp; // trigger group_change
find->grp.interval = interval;
neu_group_set_interval(find->group, interval);
// restore the timers
@@ -1822,6 +2005,7 @@ static void group_change(void *arg, int64_t timestamp, UT_array *static_tags,
neu_plugin_group_t grp = {
.group_name = strdup(group->name),
.interval = neu_group_get_interval(group->group),
.tags = NULL,
.group_free = NULL,
.user_data = NULL,
@@ -1918,7 +2102,7 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
if (neu_driver_cache_meta_get_changed(cache, group, tag->name,
&value, tag_value.metas,
NEU_TAG_META_SIZE) != 0) {
nlog_info("tag: %s not changed", tag->name);
nlog_debug("tag: %s not changed", tag->name);
continue;
}
} else {
@@ -1935,6 +2119,8 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
}
strcpy(tag_value.tag, tag->name);
tag_value.datatag.bias = tag->bias;
if (value.value.type == NEU_TYPE_ERROR) {
tag_value.value = value.value;
@@ -1942,6 +2128,14 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
continue;
}
if ((tag->type == NEU_TYPE_FLOAT && isnan(value.value.value.f32)) ||
(tag->type == NEU_TYPE_DOUBLE && isnan(value.value.value.d64))) {
tag_value.value.type = NEU_TYPE_ERROR;
tag_value.value.value.i32 = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
utarray_push_back(tag_values, &tag_value);
continue;
}
switch (tag->type) {
case NEU_TYPE_UINT16:
case NEU_TYPE_INT16:
@@ -2015,54 +2209,62 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
} else {
tag_value.value = value.value;
}
if (tag->decimal != 0) {
if (tag->decimal != 0 || tag->bias != 0) {
double decimal = tag->decimal != 0 ? tag->decimal : 1;
double bias = tag->bias;
tag_value.value.type = NEU_TYPE_DOUBLE;
switch (tag->type) {
case NEU_TYPE_INT8:
tag_value.value.value.d64 =
(double) tag_value.value.value.i8 * tag->decimal;
(double) tag_value.value.value.i8 * decimal + bias;
break;
case NEU_TYPE_UINT8:
tag_value.value.value.d64 =
(double) tag_value.value.value.u8 * tag->decimal;
(double) tag_value.value.value.u8 * decimal + bias;
break;
case NEU_TYPE_INT16:
tag_value.value.value.d64 =
(double) tag_value.value.value.i16 * tag->decimal;
(double) tag_value.value.value.i16 * decimal + bias;
break;
case NEU_TYPE_UINT16:
tag_value.value.value.d64 =
(double) tag_value.value.value.u16 * tag->decimal;
(double) tag_value.value.value.u16 * decimal + bias;
break;
case NEU_TYPE_INT32:
tag_value.value.value.d64 =
(double) tag_value.value.value.i32 * tag->decimal;
(double) tag_value.value.value.i32 * decimal + bias;
break;
case NEU_TYPE_UINT32:
tag_value.value.value.d64 =
(double) tag_value.value.value.u32 * tag->decimal;
(double) tag_value.value.value.u32 * decimal + bias;
break;
case NEU_TYPE_INT64:
tag_value.value.value.d64 =
(double) tag_value.value.value.i64 * tag->decimal;
(double) tag_value.value.value.i64 * decimal + bias;
break;
case NEU_TYPE_UINT64:
tag_value.value.value.d64 =
(double) tag_value.value.value.u64 * tag->decimal;
(double) tag_value.value.value.u64 * decimal + bias;
break;
case NEU_TYPE_FLOAT:
tag_value.value.value.d64 =
(double) tag_value.value.value.f32 * tag->decimal;
(double) tag_value.value.value.f32 * decimal + bias;
break;
case NEU_TYPE_DOUBLE:
tag_value.value.value.d64 =
(double) tag_value.value.value.d64 * tag->decimal;
(double) tag_value.value.value.d64 * decimal + bias;
break;
default:
tag_value.value.type = tag->type;
break;
}
}
if (tag->precision == 0 && tag->bias == 0 &&
tag->type == NEU_TYPE_DOUBLE) {
format_tag_value(&tag_value.value);
}
}
utarray_push_back(tag_values, &tag_value);
@@ -2081,6 +2283,8 @@ static void read_group(int64_t timestamp, int64_t timeout,
strcpy(tag_value.tag, tag->name);
tag_value.datatag.bias = tag->bias;
if (neu_driver_cache_meta_get(cache, group, tag->name, &value,
tag_value.metas,
NEU_TAG_META_SIZE) != 0) {
@@ -2220,6 +2424,190 @@ static void read_group(int64_t timestamp, int64_t timeout,
break;
}
}
if (tag->precision == 0 && tag->bias == 0 &&
tag->type == NEU_TYPE_DOUBLE) {
format_tag_value(&tag_value.value);
}
}
utarray_push_back(tag_values, &tag_value);
}
}
static void read_group_paginate(int64_t timestamp, int64_t timeout,
neu_tag_cache_type_e cache_type,
neu_driver_cache_t *cache, const char *group,
UT_array *tags, UT_array *tag_values)
{
utarray_foreach(tags, neu_datatag_t *, tag)
{
neu_resp_tag_value_meta_paginate_t tag_value = { 0 };
neu_driver_cache_value_t value = { 0 };
strcpy(tag_value.tag, tag->name);
tag_value.datatag.name = strdup(tag->name);
tag_value.datatag.address = strdup(tag->address);
tag_value.datatag.attribute = tag->attribute;
tag_value.datatag.type = tag->type;
tag_value.datatag.precision = tag->precision;
tag_value.datatag.decimal = tag->decimal;
tag_value.datatag.bias = tag->bias;
tag_value.datatag.description = strdup(tag->description);
tag_value.datatag.option = tag->option;
memcpy(tag_value.datatag.meta, tag->meta, NEU_TAG_META_LENGTH);
if (tag->attribute == NEU_ATTRIBUTE_WRITE) {
tag_value.value.type = NEU_TYPE_STRING;
tag_value.value.value.str[0] = 0;
utarray_push_back(tag_values, &tag_value);
continue;
}
if (neu_driver_cache_meta_get(cache, group, tag->name, &value,
tag_value.metas,
NEU_TAG_META_SIZE) != 0) {
tag_value.value.type = NEU_TYPE_ERROR;
tag_value.value.value.i32 = NEU_ERR_PLUGIN_TAG_NOT_READY;
utarray_push_back(tag_values, &tag_value);
continue;
}
if (value.value.type == NEU_TYPE_ERROR) {
tag_value.value = value.value;
utarray_push_back(tag_values, &tag_value);
continue;
}
switch (tag->type) {
case NEU_TYPE_UINT16:
case NEU_TYPE_INT16:
switch (tag->option.value16.endian) {
case NEU_DATATAG_ENDIAN_B16:
value.value.value.u16 = htons(value.value.value.u16);
break;
case NEU_DATATAG_ENDIAN_L16:
default:
break;
}
break;
case NEU_TYPE_FLOAT:
case NEU_TYPE_UINT32:
case NEU_TYPE_INT32:
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32: {
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
break;
}
case NEU_DATATAG_ENDIAN_BB32:
value.value.value.u32 = htonl(value.value.value.u32);
break;
case NEU_DATATAG_ENDIAN_BL32:
value.value.value.u32 = htonl(value.value.value.u32);
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
break;
case NEU_DATATAG_ENDIAN_LL32:
default:
break;
}
break;
case NEU_TYPE_DOUBLE:
case NEU_TYPE_INT64:
case NEU_TYPE_UINT64:
switch (tag->option.value64.endian) {
case NEU_DATATAG_ENDIAN_B64:
value.value.value.u64 = neu_htonll(value.value.value.u64);
break;
case NEU_DATATAG_ENDIAN_L64:
default:
break;
}
break;
default:
break;
}
if (cache_type != NEU_TAG_CACHE_TYPE_NEVER &&
!neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) &&
(timestamp - value.timestamp) > timeout) {
if (value.value.type == NEU_TYPE_PTR) {
free(value.value.value.ptr.ptr);
}
tag_value.value.type = NEU_TYPE_ERROR;
tag_value.value.value.i32 = NEU_ERR_PLUGIN_TAG_VALUE_EXPIRED;
} else {
if (value.value.type == NEU_TYPE_PTR) {
tag_value.value.type = NEU_TYPE_PTR;
tag_value.value.value.ptr.length = value.value.value.ptr.length;
tag_value.value.value.ptr.type = value.value.value.ptr.type;
tag_value.value.value.ptr.ptr = value.value.value.ptr.ptr;
} else {
tag_value.value = value.value;
}
if (tag->decimal != 0 || tag->bias != 0) {
tag_value.value.type = NEU_TYPE_DOUBLE;
double decimal = tag->decimal != 0 ? tag->decimal : 1;
double bias = tag->bias;
switch (tag->type) {
case NEU_TYPE_INT8:
tag_value.value.value.d64 =
(double) tag_value.value.value.i8 * decimal + bias;
break;
case NEU_TYPE_UINT8:
tag_value.value.value.d64 =
(double) tag_value.value.value.u8 * decimal + bias;
break;
case NEU_TYPE_INT16:
tag_value.value.value.d64 =
(double) tag_value.value.value.i16 * decimal + bias;
break;
case NEU_TYPE_UINT16:
tag_value.value.value.d64 =
(double) tag_value.value.value.u16 * decimal + bias;
break;
case NEU_TYPE_INT32:
tag_value.value.value.d64 =
(double) tag_value.value.value.i32 * decimal + bias;
break;
case NEU_TYPE_UINT32:
tag_value.value.value.d64 =
(double) tag_value.value.value.u32 * decimal + bias;
break;
case NEU_TYPE_INT64:
tag_value.value.value.d64 =
(double) tag_value.value.value.i64 * decimal + bias;
break;
case NEU_TYPE_UINT64:
tag_value.value.value.d64 =
(double) tag_value.value.value.u64 * decimal + bias;
break;
case NEU_TYPE_FLOAT:
tag_value.value.value.d64 =
(double) tag_value.value.value.f32 * decimal + bias;
break;
case NEU_TYPE_DOUBLE:
tag_value.value.value.d64 =
(double) tag_value.value.value.d64 * decimal + bias;
break;
default:
tag_value.value.type = tag->type;
break;
}
}
if (tag->precision == 0 && tag->bias == 0 &&
tag->type == NEU_TYPE_DOUBLE) {
format_tag_value(&tag_value.value);
}
}
utarray_push_back(tag_values, &tag_value);
}
@@ -2289,4 +2677,78 @@ void neu_adapter_driver_unsubscribe(neu_adapter_driver_t * driver,
}
}
pthread_mutex_unlock(&find->apps_mtx);
}
void neu_adapter_driver_scan_tags(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req)
{
if (driver->adapter.state != NEU_NODE_RUNNING_STATE_RUNNING) {
driver->adapter.cb_funs.driver.scan_tags_response(
&driver->adapter, req, NEU_ERR_PLUGIN_NOT_RUNNING, NULL,
NEU_TYPE_ERROR, false);
nlog_warn("%s not running", driver->adapter.name);
return;
}
if (driver->adapter.module->intf_funs->driver.scan_tags == NULL) {
driver->adapter.cb_funs.driver.scan_tags_response(
&driver->adapter, req, NEU_ERR_PLUGIN_NOT_SUPPORT_SCAN_TAGS, NULL,
NEU_TYPE_ERROR, false);
nlog_warn("%s not support scan tags", driver->adapter.name);
return;
}
neu_req_scan_tags_t *cmd = (neu_req_scan_tags_t *) &req[1];
driver->adapter.module->intf_funs->driver.scan_tags(driver->adapter.plugin,
req, cmd->id);
}
void neu_adapter_driver_test_read_tag(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req)
{
neu_json_value_u error_value;
error_value.val_int = 0;
if (driver->adapter.state != NEU_NODE_RUNNING_STATE_RUNNING) {
driver->adapter.cb_funs.driver.test_read_tag_response(
&driver->adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR, error_value,
NEU_ERR_PLUGIN_NOT_RUNNING);
nlog_warn("%s not running", driver->adapter.name);
return;
}
if (driver->adapter.module->intf_funs->driver.test_read_tag == NULL) {
driver->adapter.cb_funs.driver.test_read_tag_response(
&driver->adapter, req, NEU_JSON_INT, NEU_TYPE_ERROR, error_value,
NEU_ERR_PLUGIN_NOT_SUPPORT_TEST_READ_TAG);
nlog_warn("%s not support testing reading", driver->adapter.name);
return;
}
neu_req_test_read_tag_t *cmd = (neu_req_test_read_tag_t *) &req[1];
neu_datatag_t datatag;
datatag.name = cmd->tag;
datatag.address = cmd->address;
datatag.attribute = cmd->attribute;
datatag.type = cmd->type;
datatag.precision = cmd->precision;
datatag.decimal = cmd->decimal;
datatag.bias = cmd->bias;
datatag.option = cmd->option;
group_t *g = find_group(driver, cmd->group);
if (g != NULL && neu_group_tag_size(g->group) > 0) {
stop_group_timer(driver, g);
}
driver->adapter.module->intf_funs->driver.test_read_tag(
driver->adapter.plugin, req, datatag);
if (g != NULL && neu_group_tag_size(g->group) > 0) {
start_group_timer(driver, g);
}
}
+7
View File
@@ -33,6 +33,10 @@ void neu_adapter_driver_stop_group_timer(neu_adapter_driver_t *driver);
void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
void neu_adapter_driver_read_group_paginate(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
void neu_adapter_driver_test_read_tag(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
void neu_adapter_driver_write_tag(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
@@ -87,4 +91,7 @@ void neu_adapter_driver_subscribe(neu_adapter_driver_t *driver,
neu_req_subscribe_t * req);
void neu_adapter_driver_unsubscribe(neu_adapter_driver_t * driver,
neu_req_unsubscribe_t *req);
void neu_adapter_driver_scan_tags(neu_adapter_driver_t *driver,
neu_reqresp_head_t * req);
#endif
+29
View File
@@ -80,6 +80,7 @@ const char *usage_text =
" --plugin_dir <DIR> directory from which neuron loads plugin lib files\n"
" --syslog_host <HOST> syslog server host to which neuron will send logs\n"
" --syslog_port <PORT> syslog server port (default 541 if not provided)\n"
" --sub_filter_error The subscribe attribute only detects the last read value and does not report any error tags\n"
"\n";
// clang-format on
@@ -181,6 +182,19 @@ static inline int load_env(neu_cli_args_t *args, char **log_level_out,
}
}
char *sub_filter_e = getenv(NEU_ENV_SUB_FILTER_ERROR);
if (sub_filter_e != NULL) {
if (strcmp(sub_filter_e, "1") == 0) {
args->sub_filter_err = true;
} else if (strcmp(sub_filter_e, "0") == 0) {
args->sub_filter_err = false;
} else {
printf("neuron NEURON_SUB_FILTER_ERROR setting error!\n");
ret = -1;
break;
}
}
char *log_level = getenv(NEU_ENV_LOG_LEVEL);
if (log_level != NULL) {
if (*log_level_out != NULL) {
@@ -289,6 +303,7 @@ static inline int load_config_file(int argc, char *argv[],
{ .name = "port", .t = NEU_JSON_INT },
{ .name = "syslog_host", .t = NEU_JSON_STR },
{ .name = "syslog_port", .t = NEU_JSON_INT },
{ .name = "sub_filter_error", .t = NEU_JSON_INT },
};
resolve_config_file_path(argc, argv, long_options, opts, &config_file);
@@ -369,6 +384,16 @@ static inline int load_config_file(int argc, char *argv[],
break;
}
if (elems[5].v.val_int == 1) {
args->sub_filter_err = true;
} else if (elems[5].v.val_int == 0) {
args->sub_filter_err = false;
} else {
printf("config file %s sub_filter_error setting error!\n",
config_file);
break;
}
ret = 0;
} else {
printf("config file %s elems error! must had ip, port and "
@@ -424,6 +449,7 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
{ "stop", no_argument, NULL, 's' },
{ "syslog_host", required_argument, NULL, 'S' },
{ "syslog_port", required_argument, NULL, 'P' },
{ "sub_filter_error", no_argument, NULL, 'f' },
{ NULL, 0, NULL, 0 },
};
@@ -517,6 +543,9 @@ void neu_cli_args_init(neu_cli_args_t *args, int argc, char *argv[])
}
args->syslog_host = strdup(optarg);
break;
case 'f':
args->sub_filter_err = true;
break;
case '?':
default:
usage();
+2
View File
@@ -35,6 +35,7 @@
#define NEU_ENV_PLUGIN_DIR "NEURON_PLUGIN_DIR"
#define NEU_ENV_SYSLOG_HOST "NEURON_SYSLOG_HOST"
#define NEU_ENV_SYSLOG_PORT "NEURON_SYSLOG_PORT"
#define NEU_ENV_SUB_FILTER_ERROR "NEURON_SUB_FILTER_ERROR"
#define NEURON_CONFIG_FNAME "./config/neuron.json"
@@ -64,6 +65,7 @@ typedef struct {
int port;
char * syslog_host;
uint16_t syslog_port;
bool sub_filter_err;
} neu_cli_args_t;
/** Parse command line arguments.
+47
View File
@@ -209,6 +209,34 @@ filter_tags(tag_elem_t *tags,
return array;
}
static inline UT_array *filter_tags_by_page(
tag_elem_t *tags, bool (*predicate)(const neu_datatag_t *, void *data),
void *data, int current_page, int page_size, int *total_count)
{
tag_elem_t *el = NULL, *tmp = NULL;
UT_array * array = NULL;
int count = 0;
int start_index = (current_page - 1) * page_size;
int end_index = start_index + page_size;
utarray_new(array, neu_tag_get_icd());
HASH_ITER(hh, tags, el, tmp)
{
if (predicate(el->tag, data)) {
if (count >= start_index && count < end_index) {
utarray_push_back(array, el->tag);
}
count++;
}
}
if (total_count) {
*total_count = count;
}
return array;
}
static inline bool is_readable(const neu_datatag_t *tag, void *data)
{
(void) data;
@@ -275,6 +303,25 @@ UT_array *neu_group_query_read_tag(neu_group_t *group, const char *name,
return array;
}
UT_array *neu_group_query_read_tag_paginate(neu_group_t *group,
const char *name, const char *desc,
int current_page, int page_size,
int *total_count)
{
UT_array * array = NULL;
struct query q = {
.name = (char *) name,
.desc = (char *) desc,
};
pthread_mutex_lock(&group->mtx);
array = filter_tags_by_page(group->tags, match_query, &q, current_page,
page_size, total_count);
pthread_mutex_unlock(&group->mtx);
return array;
}
UT_array *neu_group_get_read_tag(neu_group_t *group)
{
UT_array *array = NULL;
+4
View File
@@ -43,6 +43,10 @@ UT_array * neu_group_query_tag(neu_group_t *group, const char *name);
UT_array * neu_group_get_read_tag(neu_group_t *group);
UT_array * neu_group_query_read_tag(neu_group_t *group, const char *name,
const char *desc);
UT_array * neu_group_query_read_tag_paginate(neu_group_t *group,
const char *name, const char *desc,
int current_page, int page_size,
int *total_count);
uint16_t neu_group_tag_size(const neu_group_t *group);
neu_datatag_t *neu_group_find_tag(neu_group_t *group, const char *tag);
void neu_group_split_static_tags(neu_group_t *group, UT_array **static_tags,
+1
View File
@@ -313,6 +313,7 @@ int neu_metric_entries_add(neu_metric_entry_t **entries, const char *name,
entry->value = init;
}
entry->init = init;
entry->name = name;
entry->type = type;
entry->help = help;
+7 -1
View File
@@ -34,6 +34,10 @@ extern "C" {
XX(NEU_RESP_ERROR, neu_resp_error_t) \
XX(NEU_REQ_READ_GROUP, neu_req_read_group_t) \
XX(NEU_RESP_READ_GROUP, neu_resp_read_group_t) \
XX(NEU_REQ_READ_GROUP_PAGINATE, neu_req_read_group_paginate_t) \
XX(NEU_RESP_READ_GROUP_PAGINATE, neu_resp_read_group_paginate_t) \
XX(NEU_REQ_TEST_READ_TAG, neu_req_test_read_tag_t) \
XX(NEU_RESP_TEST_READ_TAG, neu_resp_test_read_tag_t) \
XX(NEU_REQ_WRITE_TAG, neu_req_write_tag_t) \
XX(NEU_REQ_WRITE_TAGS, neu_req_write_tags_t) \
XX(NEU_REQ_WRITE_GTAGS, neu_req_write_gtags_t) \
@@ -93,7 +97,9 @@ extern "C" {
XX(NEU_REQ_UPDATE_LOG_LEVEL, neu_req_update_log_level_t) \
XX(NEU_REQ_PRGFILE_UPLOAD, neu_req_prgfile_upload_t) \
XX(NEU_REQ_PRGFILE_PROCESS, neu_req_prgfile_process_t) \
XX(NEU_RESP_PRGFILE_PROCESS, neu_resp_prgfile_process_t)
XX(NEU_RESP_PRGFILE_PROCESS, neu_resp_prgfile_process_t) \
XX(NEU_REQ_SCAN_TAGS, neu_req_scan_tags_t) \
XX(NEU_RESP_SCAN_TAGS, neu_resp_scan_tags_t)
static inline size_t neu_reqresp_size(neu_reqresp_type_e t)
{
+4 -2
View File
@@ -99,7 +99,7 @@ neu_conn_t *neu_conn_new(neu_conn_param_t *param, void *data,
conn->disconnected = disconnected;
conn->connected = connected;
conn->buf_size = 2048;
conn->buf_size = 8192;
conn->buf = calloc(conn->buf_size, 1);
conn->offset = 0;
conn->stop = false;
@@ -125,7 +125,9 @@ void neu_conn_stop(neu_conn_t *conn)
void neu_conn_start(neu_conn_t *conn)
{
pthread_mutex_lock(&conn->mtx);
conn->stop = false;
conn->state.recv_bytes = 0;
conn->state.send_bytes = 0;
conn->stop = false;
pthread_mutex_unlock(&conn->mtx);
}
+84 -20
View File
@@ -123,6 +123,7 @@ struct neu_mqtt_client_s {
neu_mqtt_client_connection_cb_t disconnect_cb;
void * disconnect_cb_data;
nng_mqtt_sqlite_option * sqlite_cfg;
char * db;
bool receiving;
nng_aio * recv_aio;
subscription_t * subscriptions;
@@ -541,8 +542,10 @@ static void connect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
neu_mqtt_client_t * client = arg;
neu_mqtt_client_connection_cb_t cb = NULL;
void * data = NULL;
int reason = 0;
log(notice, "mqtt client connected");
nng_pipe_get_int(p, NNG_OPT_MQTT_CONNECT_REASON, &reason);
log(notice, "mqtt client connected, reason: %d", reason);
nng_mtx_lock(client->mtx);
// start receiving
@@ -567,8 +570,11 @@ static void disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
subscription_t * sub = NULL;
neu_mqtt_client_connection_cb_t cb = NULL;
void * data = NULL;
int reason = 0;
nng_pipe_get_int(p, NNG_OPT_MQTT_DISCONNECT_REASON, &reason);
log(notice, "mqtt client disconnected, reason: %d", reason);
log(notice, "mqtt client disconnected");
nng_mtx_lock(client->mtx);
client->connected = false;
cb = client->disconnect_cb;
@@ -901,26 +907,10 @@ static inline nng_mqtt_sqlite_option *
alloc_sqlite_config(neu_mqtt_client_t *client)
{
int rv;
char * db = NULL;
nng_mqtt_sqlite_option *cfg = NULL;
const mqtt_buf client_id =
nng_mqtt_msg_get_connect_client_id(client->conn_msg);
if (NULL == client_id.buf || 0 == client_id.length) {
log(error, "nng_mqtt_msg_get_connect_client_id fail");
return NULL;
}
neu_asprintf(&db, "neuron-mqtt-client-%.*s.db", (unsigned) client_id.length,
(char *) client_id.buf);
if (NULL == db) {
log(error, "neu_asprintf nano-mqtt cilent db fail");
return NULL;
}
if ((rv = nng_mqtt_alloc_sqlite_opt(&cfg)) != 0) {
log(error, "nng_mqtt_alloc_sqlite_opt fail: %s", nng_strerror(rv));
free(db);
return NULL;
}
@@ -928,9 +918,7 @@ alloc_sqlite_config(neu_mqtt_client_t *client)
nng_mqtt_set_sqlite_flush_threshold(cfg, 256);
nng_mqtt_set_sqlite_max_rows(cfg, 256);
nng_mqtt_set_sqlite_db_dir(cfg, "persistence/");
nng_mqtt_sqlite_db_init(cfg, db, client->version);
free(db);
return cfg;
}
@@ -989,6 +977,7 @@ void neu_mqtt_client_free(neu_mqtt_client_t *client)
subscriptions_free(client->subscriptions);
tasks_free(client->task_free_list);
nng_msg_free(client->conn_msg);
free(client->db);
free(client->url);
free(client->host);
nng_mtx_free(client->mtx);
@@ -1213,6 +1202,76 @@ end:
return rv;
}
static void rand_str(char *dst, size_t len)
{
char alphabet[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (len-- > 1) {
size_t i = (double) rand() / RAND_MAX * ((sizeof alphabet) - 1);
*dst++ = alphabet[i];
}
*dst = '\0';
}
static int neu_mqtt_client_set_cache_db(neu_mqtt_client_t *client)
{
char str[8] = { 0 };
rand_str(str, sizeof(str));
char *db = NULL;
neu_asprintf(&db, "neuron-mqtt-client-%s.db", str);
if (NULL == db) {
log(error, "neu_asprintf nano-mqtt cilent db fail");
return NEU_ERR_EINTERNAL;
}
if (client->db && 0 == strcmp(client->db, db)) {
free(db);
return 0;
}
neu_mqtt_client_remove_cache_db(client);
free(client->db);
client->db = db;
if (client->sqlite_cfg) {
nng_mqtt_sqlite_db_init(client->sqlite_cfg, db, client->version);
}
log(notice, "set cache db %s", db);
return 0;
}
void neu_mqtt_client_remove_cache_db(neu_mqtt_client_t *client)
{
if (NULL == client->db) {
return;
}
const char *dir = "persistence";
int path_size = strlen(dir) + strlen(client->db) + 6;
char * path = calloc(path_size, 1);
if (NULL == path) {
return;
}
snprintf(path, path_size, "%s/%s", dir, client->db);
log(notice, "rm cache db %s", path);
remove(path);
snprintf(path, path_size, "%s/%s-shm", dir, client->db);
log(notice, "rm cache db %s", path);
remove(path);
snprintf(path, path_size, "%s/%s-wal", dir, client->db);
log(notice, "rm cache db %s", path);
remove(path);
free(path);
}
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
size_t mem_size_bytes, size_t db_size_bytes)
{
@@ -1227,6 +1286,7 @@ int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
if (client->sqlite_cfg) {
nng_mqtt_free_sqlite_opt(client->sqlite_cfg);
client->sqlite_cfg = NULL;
neu_mqtt_client_remove_cache_db(client);
}
goto end;
}
@@ -1240,6 +1300,10 @@ int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
}
}
if (0 != (rv = neu_mqtt_client_set_cache_db(client))) {
return rv;
}
// FIXME: until NanoSDK cache size limit feature out
// Assume that,
// 1. every upload message follows the below template
+57 -13
View File
@@ -128,6 +128,8 @@ neu_manager_t *neu_manager_create()
manager->timestamp_lev_manager = 0;
strncpy(g_status, "loading", sizeof(g_status));
neu_metrics_init();
start_static_adapter(manager, DEFAULT_DASHBOARD_PLUGIN_NAME);
@@ -156,13 +158,15 @@ neu_manager_t *neu_manager_create()
manager->timer_timestamp =
neu_event_add_timer(manager->events, timestamp_timer_param);
strncpy(g_status, "ready", sizeof(g_status));
nlog_notice("manager start");
return manager;
}
void neu_manager_destroy(neu_manager_t *manager)
{
neu_req_node_init_t uninit = { 0 };
neu_req_node_init_t uninit = { 0 };
int send_msg_success = 1;
UT_array *addrs = neu_node_manager_get_addrs_all(manager->node_manager);
@@ -176,15 +180,19 @@ void neu_manager_destroy(neu_manager_t *manager)
if (0 != neu_send_msg_to(manager->server_fd, addr, msg)) {
nlog_error("manager -> %s uninit msg send fail",
&addr->sun_path[1]);
send_msg_success = 0;
neu_msg_free(msg);
break;
}
}
utarray_free(addrs);
while (1) {
usleep(1000 * 100);
if (neu_node_manager_size(manager->node_manager) == 0) {
break;
if (send_msg_success) {
while (1) {
usleep(1000 * 100);
if (neu_node_manager_size(manager->node_manager) == 0) {
break;
}
}
}
@@ -236,7 +244,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
break;
}
if (init->state == NEU_NODE_RUNNING_STATE_RUNNING ||
if (init->state == NEU_NODE_RUNNING_STATE_READY ||
init->state == NEU_NODE_RUNNING_STATE_RUNNING ||
init->state == NEU_NODE_RUNNING_STATE_STOPPED) {
neu_adapter_t *adapter =
neu_node_manager_find(manager->node_manager, init->node);
@@ -699,8 +708,11 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
}
case NEU_REQ_ADD_NODE: {
neu_req_add_node_t *cmd = (neu_req_add_node_t *) &header[1];
int error = neu_manager_add_node(manager, cmd->node, cmd->plugin,
cmd->setting, false, false);
nlog_notice("add node name:%s plugin:%s", cmd->node, cmd->plugin);
int error =
neu_manager_add_node(manager, cmd->node, cmd->plugin, cmd->setting,
NEU_NODE_RUNNING_STATE_INIT, false);
neu_resp_error_t e = { .error = error };
if (error == NEU_ERR_SUCCESS) {
@@ -719,7 +731,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_UPDATE_NODE: {
neu_req_update_node_t *cmd = (neu_req_update_node_t *) &header[1];
neu_resp_error_t e = { 0 };
nlog_notice("update node name:%s new_name:%s", cmd->node,
cmd->new_name);
if (NULL == neu_node_manager_find(manager->node_manager, cmd->node)) {
e.error = NEU_ERR_NODE_NOT_EXIST;
} else if (NULL !=
@@ -743,7 +756,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_DEL_NODE: {
neu_req_del_node_t *cmd = (neu_req_del_node_t *) &header[1];
neu_resp_error_t error = { 0 };
neu_adapter_t * adapter =
nlog_notice("del node name:%s", cmd->node);
neu_adapter_t *adapter =
neu_node_manager_find(manager->node_manager, cmd->node);
bool single =
neu_node_manager_is_single(manager->node_manager, cmd->node);
@@ -787,10 +801,22 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
}
utarray_free(subscriptions);
}
neu_reqresp_node_deleted_t resp = { 0 };
strcpy(resp.node, header->receiver);
// notify MQTT about node removal
if (0 == strcmp(adapter->module->module_name, "MQTT")) {
msg = neu_msg_new(NEU_REQRESP_NODE_DELETED, NULL, &resp);
if (NULL != msg) {
neu_reqresp_head_t *hd = neu_msg_get_header(msg);
strcpy(hd->receiver, cmd->node);
strcpy(hd->sender, "manager");
reply(manager, hd, &resp);
}
}
header->type = NEU_REQ_NODE_UNINIT;
forward_msg(manager, header, header->receiver);
if (neu_adapter_get_type(adapter) == NEU_NA_TYPE_DRIVER) {
UT_array *apps = neu_subscribe_manager_find_by_driver(
manager->subscribe_manager, resp.node);
@@ -841,6 +867,10 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
neu_resp_error_t error = { 0 };
uint16_t app_port = 0;
nlog_notice("add sub app_name:%s driver_node:%s group:%s params:%s",
cmd->app, cmd->driver, cmd->group,
cmd->params != NULL ? cmd->params : "");
error.error = neu_manager_subscribe(manager, cmd->app, cmd->driver,
cmd->group, cmd->params, &app_port);
@@ -866,7 +896,9 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
for (uint16_t i = 0; i < cmd->n_group; ++i) {
neu_req_subscribe_group_info_t *info = &cmd->groups[i];
nlog_notice("add sub app_name:%s driver_node:%s group:%s params:%s",
cmd->app, info->driver, info->group,
info->params != NULL ? info->params : "");
error.error =
neu_manager_subscribe(manager, cmd->app, info->driver,
info->group, info->params, &info->port);
@@ -894,7 +926,9 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_UPDATE_SUBSCRIBE_GROUP: {
neu_req_subscribe_t *cmd = (neu_req_subscribe_t *) &header[1];
neu_resp_error_t error = { 0 };
nlog_notice("update sub app_name:%s driver_node:%s group:%s params:%s",
cmd->app, cmd->driver, cmd->group,
cmd->params != NULL ? cmd->params : "");
error.error = neu_manager_update_subscribe(
manager, cmd->app, cmd->driver, cmd->group, cmd->params);
@@ -914,7 +948,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_UNSUBSCRIBE_GROUP: {
neu_req_unsubscribe_t *cmd = (neu_req_unsubscribe_t *) &header[1];
neu_resp_error_t error = { 0 };
nlog_notice("del sub app_name:%s driver_node:%s group:%s", cmd->app,
cmd->driver, cmd->group);
error.error =
neu_manager_unsubscribe(manager, cmd->app, cmd->driver, cmd->group);
@@ -1007,6 +1042,7 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_REQ_GET_GROUP:
case NEU_REQ_GET_NODE_SETTING:
case NEU_REQ_READ_GROUP:
case NEU_REQ_READ_GROUP_PAGINATE:
case NEU_REQ_WRITE_TAG:
case NEU_REQ_WRITE_TAGS:
case NEU_REQ_WRITE_GTAGS:
@@ -1017,6 +1053,9 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
NULL) {
if (NEU_REQ_READ_GROUP == header->type) {
neu_req_read_group_fini((neu_req_read_group_t *) &header[1]);
} else if (NEU_REQ_READ_GROUP_PAGINATE == header->type) {
neu_req_read_group_paginate_fini(
(neu_req_read_group_paginate_t *) &header[1]);
} else if (NEU_REQ_WRITE_TAG == header->type) {
neu_req_write_tag_fini((neu_req_write_tag_t *) &header[1]);
} else if (NEU_REQ_WRITE_TAGS == header->type) {
@@ -1036,6 +1075,8 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
}
case NEU_REQ_PRGFILE_PROCESS:
case NEU_REQ_PRGFILE_UPLOAD:
case NEU_REQ_SCAN_TAGS:
case NEU_REQ_TEST_READ_TAG:
case NEU_REQ_GET_NODE_STATE: {
if (neu_node_manager_find(manager->node_manager, header->receiver) ==
NULL) {
@@ -1244,7 +1285,10 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
case NEU_RESP_GET_NODE_SETTING:
case NEU_RESP_ERROR:
case NEU_RESP_READ_GROUP:
case NEU_RESP_READ_GROUP_PAGINATE:
case NEU_RESP_TEST_READ_TAG:
case NEU_RESP_PRGFILE_PROCESS:
case NEU_RESP_SCAN_TAGS:
forward_msg(manager, header, header->receiver);
break;
+5 -3
View File
@@ -243,9 +243,11 @@ int neu_manager_subscribe(neu_manager_t *manager, const char *app,
// guard against empty mqtt topic parameter
// this is not an elegant solution due to the current architecture
if (params && 0 == strcmp(adapter->module->module_name, "MQTT")) {
neu_json_elem_t elem = { .name = "topic", .t = NEU_JSON_STR };
neu_parse_param(params, NULL, 1, &elem);
if (elem.v.val_str && 0 == strlen(elem.v.val_str)) {
neu_json_elem_t elem = { .name = "topic",
.t = NEU_JSON_STR,
.v.val_str = NULL };
int ret = neu_parse_param(params, NULL, 1, &elem);
if (ret != 0 || (elem.v.val_str && 0 == strlen(elem.v.val_str))) {
free(elem.v.val_str);
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
}
+1 -1
View File
@@ -108,7 +108,7 @@ static void *event_loop(void *arg)
neu_events_t *events = (neu_events_t *) arg;
int epoll_fd = events->epoll_fd;
while (true) {
while (!events->stop) {
struct epoll_event event = { 0 };
struct event_data *data = NULL;
+4 -1
View File
@@ -39,8 +39,10 @@ static bool exit_flag = false;
static neu_manager_t *g_manager = NULL;
zlog_category_t * neuron = NULL;
bool disable_jwt = false;
bool sub_filter_err = false;
int default_log_level = ZLOG_LEVEL_NOTICE;
char host_port[32] = { 0 };
char g_status[32] = { 0 };
int64_t global_timestamp = 0;
@@ -164,7 +166,8 @@ int main(int argc, char *argv[])
global_timestamp = neu_time_ms();
neu_cli_args_init(&args, argc, argv);
disable_jwt = args.disable_auth;
disable_jwt = args.disable_auth;
sub_filter_err = args.sub_filter_err;
snprintf(host_port, sizeof(host_port), "http://%s:%d", args.ip, args.port);
if (args.daemonized) {
+443 -5
View File
@@ -30,6 +30,7 @@
#include "json/json.h"
#include "define.h"
#include "msg.h"
#include "tag.h"
#include "json/neu_json_rw.h"
@@ -43,6 +44,7 @@ int neu_json_encode_read_resp(void *json_object, void *param)
neu_json_read_resp_tag_t *p_tag = resp->tags;
for (int i = 0; i < resp->n_tag; i++) {
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
int if_precision = 0;
tag_elems[0].name = "name";
tag_elems[0].t = NEU_JSON_STR;
@@ -57,16 +59,25 @@ int neu_json_encode_read_resp(void *json_object, void *param)
tag_elems[1].t = p_tag->t;
tag_elems[1].v = p_tag->value;
tag_elems[1].precision = p_tag->precision;
tag_elems[1].bias = p_tag->datatag.bias;
if (p_tag->t == NEU_JSON_FLOAT || p_tag->t == NEU_JSON_DOUBLE) {
if_precision = 1;
tag_elems[2].name = "transferPrecision";
tag_elems[2].t = NEU_JSON_INT;
tag_elems[2].v.val_int =
p_tag->precision > 0 ? p_tag->precision : 1;
}
}
for (int k = 0; k < p_tag->n_meta; k++) {
tag_elems[2 + k].name = p_tag->metas[k].name;
tag_elems[2 + k].t = p_tag->metas[k].t;
tag_elems[2 + k].v = p_tag->metas[k].value;
tag_elems[if_precision + 2 + k].name = p_tag->metas[k].name;
tag_elems[if_precision + 2 + k].t = p_tag->metas[k].t;
tag_elems[if_precision + 2 + k].v = p_tag->metas[k].value;
}
tag_array =
neu_json_encode_array(tag_array, tag_elems, 2 + p_tag->n_meta);
tag_array = neu_json_encode_array(tag_array, tag_elems,
2 + if_precision + p_tag->n_meta);
p_tag++;
}
@@ -81,6 +92,133 @@ int neu_json_encode_read_resp(void *json_object, void *param)
return ret;
}
int neu_json_encode_read_paginate_resp(void *json_object, void *param)
{
int ret = 0;
neu_json_read_paginate_resp_t *resp =
(neu_json_read_paginate_resp_t *) param;
void * tag_array = neu_json_array();
neu_json_read_paginate_resp_tag_t *p_tag = resp->tags;
for (int i = 0; i < resp->n_tag; i++) {
neu_json_elem_t tag_elems[10 + NEU_TAG_META_SIZE] = { 0 };
int if_precision = 0;
tag_elems[0].name = "name";
tag_elems[0].t = NEU_JSON_STR;
tag_elems[0].v.val_str = p_tag->name;
tag_elems[1].name = "type";
tag_elems[1].t = NEU_JSON_INT;
tag_elems[1].v.val_int = p_tag->datatag.type;
tag_elems[2].name = "address";
tag_elems[2].t = NEU_JSON_STR;
tag_elems[2].v.val_str = p_tag->datatag.address;
tag_elems[3].name = "attribute";
tag_elems[3].t = NEU_JSON_INT;
tag_elems[3].v.val_int = p_tag->datatag.attribute;
tag_elems[4].name = "description";
tag_elems[4].t = NEU_JSON_STR;
tag_elems[4].v.val_str = p_tag->datatag.description;
tag_elems[5].name = "precision";
tag_elems[5].t = NEU_JSON_INT;
tag_elems[5].v.val_int = p_tag->datatag.precision;
tag_elems[6].name = "decimal";
tag_elems[6].t = NEU_JSON_DOUBLE;
tag_elems[6].v.val_double = p_tag->datatag.decimal;
tag_elems[7].name = "bias";
tag_elems[7].t = NEU_JSON_DOUBLE;
tag_elems[7].v.val_double = p_tag->datatag.bias;
if (p_tag->error != 0) {
tag_elems[8].name = "error";
tag_elems[8].t = NEU_JSON_INT;
tag_elems[8].v.val_int = p_tag->error;
} else {
tag_elems[8].name = "value";
tag_elems[8].t = p_tag->t;
tag_elems[8].v = p_tag->value;
tag_elems[8].precision = p_tag->precision;
tag_elems[8].bias = p_tag->datatag.bias;
if (p_tag->t == NEU_JSON_FLOAT || p_tag->t == NEU_JSON_DOUBLE) {
if_precision = 1;
tag_elems[9].name = "transferPrecision";
tag_elems[9].t = NEU_JSON_INT;
tag_elems[9].v.val_int =
p_tag->precision > 0 ? p_tag->precision : 1;
}
}
for (int k = 0; k < p_tag->n_meta; k++) {
tag_elems[if_precision + 9 + k].name = p_tag->metas[k].name;
tag_elems[if_precision + 9 + k].t = p_tag->metas[k].t;
tag_elems[if_precision + 9 + k].v = p_tag->metas[k].value;
}
tag_array = neu_json_encode_array(tag_array, tag_elems,
9 + if_precision + p_tag->n_meta);
free(p_tag->datatag.name);
free(p_tag->datatag.address);
free(p_tag->datatag.description);
p_tag++;
}
void * meta_object = neu_json_encode_new();
neu_json_elem_t meta_elems[] = {
{ .name = "currentPage",
.t = NEU_JSON_INT,
.v.val_int = resp->meta.current_page },
{ .name = "pageSize",
.t = NEU_JSON_INT,
.v.val_int = resp->meta.page_size },
{ .name = "total", .t = NEU_JSON_INT, .v.val_int = resp->meta.total }
};
neu_json_encode_field(meta_object, meta_elems, 3);
neu_json_elem_t resp_elems[] = {
{ .name = "meta", .t = NEU_JSON_OBJECT, .v.val_object = meta_object },
{ .name = "items", .t = NEU_JSON_OBJECT, .v.val_object = tag_array },
};
ret = neu_json_encode_field(json_object, resp_elems, 2);
return ret;
}
int neu_json_encode_test_read_tag_resp(void *json_object, void *param)
{
int ret = 0;
neu_resp_test_read_tag_t *resp = (neu_resp_test_read_tag_t *) param;
neu_json_elem_t resp_elem = { 0 };
if (resp->type == NEU_TYPE_ERROR) {
resp_elem.name = "error";
resp_elem.t = NEU_JSON_INT;
resp_elem.v.val_int = resp->error;
} else {
resp_elem.name = "value";
resp_elem.t = resp->t;
resp_elem.v = resp->value;
}
ret = neu_json_encode_field(json_object, &resp_elem, 1);
if (resp->t == NEU_JSON_STR) {
free(resp->value.val_str);
}
return ret;
}
int neu_json_encode_read_resp1(void *json_object, void *param)
{
int ret = 0;
@@ -99,6 +237,7 @@ int neu_json_encode_read_resp1(void *json_object, void *param)
tag_elem.t = p_tag->t;
tag_elem.v = p_tag->value;
tag_elem.precision = p_tag->precision;
tag_elem.bias = p_tag->datatag.bias;
neu_json_encode_field(values, &tag_elem, 1);
} else {
tag_elem.name = p_tag->name;
@@ -185,6 +324,11 @@ int decode_write_req_json(void *json_obj, neu_json_write_req_t *req)
.name = "value",
.t = NEU_JSON_VALUE,
},
{
.name = "precision",
.t = NEU_JSON_INT,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
};
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
req_elems);
@@ -192,6 +336,11 @@ int decode_write_req_json(void *json_obj, neu_json_write_req_t *req)
goto error;
}
if (req_elems[4].v.val_int > 0) {
req_elems[3].t = NEU_JSON_DOUBLE;
req_elems[3].v.val_double = (double_t) req_elems[3].v.val_int;
}
req->node = req_elems[0].v.val_str;
req->group = req_elems[1].v.val_str;
req->tag = req_elems[2].v.val_str;
@@ -500,6 +649,220 @@ void neu_json_decode_read_req_free(neu_json_read_req_t *req)
free(req);
}
int neu_json_decode_read_paginate_req(char * buf,
neu_json_read_paginate_req_t **result)
{
int ret = 0;
void *json_obj = NULL;
json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
return -1;
}
neu_json_read_paginate_req_t *req =
calloc(1, sizeof(neu_json_read_paginate_req_t));
if (req == NULL) {
neu_json_decode_free(json_obj);
return -1;
}
neu_json_elem_t req_elems[] = {
{
.name = "node",
.t = NEU_JSON_STR,
},
{
.name = "group",
.t = NEU_JSON_STR,
},
{
.name = "sync",
.t = NEU_JSON_BOOL,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "query",
.t = NEU_JSON_OBJECT,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
};
neu_json_elem_t query_elems[] = {
{
.name = "name",
.t = NEU_JSON_STR,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "description",
.t = NEU_JSON_STR,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "currentPage",
.t = NEU_JSON_INT,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "pageSize",
.t = NEU_JSON_INT,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
{
.name = "isError",
.t = NEU_JSON_BOOL,
.attribute = NEU_JSON_ATTRIBUTE_OPTIONAL,
},
};
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
req_elems);
if (ret != 0) {
goto error;
}
req->node = req_elems[0].v.val_str;
req->group = req_elems[1].v.val_str;
req->sync = req_elems[2].v.val_bool;
if (req_elems[3].v.val_object) {
ret = neu_json_decode_by_json(req_elems[3].v.val_object,
NEU_JSON_ELEM_SIZE(query_elems),
query_elems);
if (ret != 0) {
goto error;
}
req->name = query_elems[0].v.val_str;
req->desc = query_elems[1].v.val_str;
req->current_page = query_elems[2].v.val_int;
req->page_size = query_elems[3].v.val_int;
req->is_error = query_elems[4].v.val_bool;
}
*result = req;
neu_json_decode_free(json_obj);
return ret;
error:
free(query_elems[0].v.val_str);
free(query_elems[1].v.val_str);
free(req_elems[0].v.val_str);
free(req_elems[1].v.val_str);
free(req);
if (json_obj != NULL) {
neu_json_decode_free(json_obj);
}
return ret;
}
void neu_json_decode_read_paginate_req_free(neu_json_read_paginate_req_t *req)
{
free(req->group);
free(req->node);
free(req);
}
int neu_json_decode_test_read_tag_req(char * buf,
neu_json_test_read_tag_req_t **result)
{
int ret = 0;
void * json_obj = NULL;
neu_json_test_read_tag_req_t *req =
calloc(1, sizeof(neu_json_test_read_tag_req_t));
if (req == NULL) {
return -1;
}
json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
free(req);
return -1;
}
neu_json_elem_t req_elems[] = {
{
.name = "driver",
.t = NEU_JSON_STR,
},
{
.name = "group",
.t = NEU_JSON_STR,
},
{
.name = "tag",
.t = NEU_JSON_STR,
},
{
.name = "address",
.t = NEU_JSON_STR,
},
{
.name = "attribute",
.t = NEU_JSON_INT,
},
{
.name = "type",
.t = NEU_JSON_INT,
},
{
.name = "precision",
.t = NEU_JSON_INT,
},
{
.name = "decimal",
.t = NEU_JSON_DOUBLE,
},
{
.name = "bias",
.t = NEU_JSON_DOUBLE,
},
};
ret = neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_elems),
req_elems);
if (ret != 0) {
goto decode_fail;
}
req->driver = req_elems[0].v.val_str;
req->group = req_elems[1].v.val_str;
req->tag = req_elems[2].v.val_str;
req->address = req_elems[3].v.val_str;
req->attribute = req_elems[4].v.val_int;
req->type = req_elems[5].v.val_int;
req->precision = req_elems[6].v.val_int;
req->decimal = req_elems[7].v.val_double;
req->bias = req_elems[8].v.val_double;
*result = req;
goto decode_exit;
decode_fail:
free(req);
free(req_elems[0].v.val_str);
free(req_elems[1].v.val_str);
free(req_elems[2].v.val_str);
free(req_elems[3].v.val_str);
ret = -1;
decode_exit:
if (json_obj != NULL) {
neu_json_decode_free(json_obj);
}
return ret;
}
void neu_json_decode_test_read_tag_req_free(neu_json_test_read_tag_req_t *req)
{
free(req->driver);
free(req->group);
free(req->tag);
free(req->address);
free(req);
}
int neu_json_encode_read_periodic_resp(void *json_object, void *param)
{
int ret = 0;
@@ -600,6 +963,81 @@ void neu_json_metas_to_json(neu_tag_meta_t *metas, int n_meta,
}
}
void neu_json_metas_to_json_paginate(
neu_tag_meta_t *metas, int n_meta,
neu_json_read_paginate_resp_tag_t *json_tag)
{
for (int k = 0; k < n_meta; k++) {
if (strlen(metas[k].name) > 0) {
json_tag->metas[k].name = metas[k].name;
switch (metas[k].value.type) {
case NEU_TYPE_UINT8:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.u8;
break;
case NEU_TYPE_INT8:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.i8;
break;
case NEU_TYPE_INT16:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.i16;
break;
case NEU_TYPE_INT32:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.i32;
break;
case NEU_TYPE_INT64:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.i64;
break;
case NEU_TYPE_WORD:
case NEU_TYPE_UINT16:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.u16;
break;
case NEU_TYPE_DWORD:
case NEU_TYPE_UINT32:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.u32;
break;
case NEU_TYPE_LWORD:
case NEU_TYPE_UINT64:
json_tag->metas[k].t = NEU_JSON_INT;
json_tag->metas[k].value.val_int = metas[k].value.value.u64;
break;
case NEU_TYPE_FLOAT:
json_tag->metas[k].t = NEU_JSON_FLOAT;
json_tag->metas[k].value.val_float = metas[k].value.value.f32;
break;
case NEU_TYPE_DOUBLE:
json_tag->metas[k].t = NEU_JSON_DOUBLE;
json_tag->metas[k].value.val_double = metas[k].value.value.d64;
break;
case NEU_TYPE_BOOL:
json_tag->metas[k].t = NEU_JSON_BOOL;
json_tag->metas[k].value.val_bool =
metas[k].value.value.boolean;
break;
case NEU_TYPE_BIT:
json_tag->metas[k].t = NEU_JSON_BIT;
json_tag->metas[k].value.val_bit = metas[k].value.value.u8;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_TIME:
case NEU_TYPE_DATA_AND_TIME:
json_tag->metas[k].t = NEU_JSON_STR;
json_tag->metas[k].value.val_str = metas[k].value.value.str;
break;
default:
break;
}
} else {
break;
}
}
}
int neu_json_decode_write_gtags_req(char * buf,
neu_json_write_gtags_req_t **result)
{
+154
View File
@@ -0,0 +1,154 @@
/**
* NEURON IIoT System for Industry 4.0
* Copyright (C) 2020-2022 EMQ Technologies Co., Ltd All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
/*
* DO NOT EDIT THIS FILE MANUALLY!
* It was automatically generated by `json-autotype`.
*/
#include <stdlib.h>
#include <string.h>
#include <jansson.h>
#include "define.h"
#include "msg.h"
#include "json/json.h"
#include "json/neu_json_scan.h"
int neu_json_decode_scan_tags_req(char *buf, neu_json_scan_tags_req_t **result)
{
void *json_obj = neu_json_decode_new(buf);
if (NULL == json_obj) {
return -1;
}
neu_json_scan_tags_req_t *req = calloc(1, sizeof(neu_json_scan_tags_req_t));
if (req == NULL) {
return -1;
}
neu_json_elem_t req_node_elems[] = { {
.name = "node",
.t = NEU_JSON_STR,
} };
neu_json_elem_t req_id_elems[] = {
{
.name = "id",
.t = NEU_JSON_STR,
},
};
if (0 !=
neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_node_elems),
req_node_elems)) {
neu_json_decode_free(json_obj);
free(req);
return -1;
}
neu_json_decode_by_json(json_obj, NEU_JSON_ELEM_SIZE(req_id_elems),
req_id_elems);
req->node = req_node_elems[0].v.val_str;
req->id = req_id_elems[0].v.val_str;
*result = req;
neu_json_decode_free(json_obj);
return 0;
}
void neu_json_decode_scan_tags_req_free(neu_json_scan_tags_req_t *req)
{
free(req->node);
free(req->id);
free(req);
}
int neu_json_encode_scan_tags_resp(void *json_object, void *param)
{
int ret = 0;
neu_resp_scan_tags_t *resp = (neu_resp_scan_tags_t *) param;
void * tag_array = neu_json_array();
int len = 0;
if (NULL != resp->scan_tags) {
len = utarray_len(resp->scan_tags);
utarray_foreach(resp->scan_tags, neu_scan_tag_t *, p_tag)
{
if (NULL != p_tag) {
neu_json_elem_t tag_elems[] = {
{
.name = "name",
.t = NEU_JSON_STR,
.v.val_str = p_tag->name,
},
{
.name = "id",
.t = NEU_JSON_STR,
.v.val_str = p_tag->id,
},
{
.name = "tag",
.t = NEU_JSON_INT,
.v.val_int = p_tag->type,
},
};
neu_json_encode_array(tag_array, tag_elems,
NEU_JSON_ELEM_SIZE(tag_elems));
}
}
utarray_free(resp->scan_tags);
}
neu_json_elem_t resp_elems[] = { {
.name = "error",
.t = NEU_JSON_INT,
.v.val_int = resp->error,
},
{
.name = "total",
.t = NEU_JSON_INT,
.v.val_int = len,
},
{
.name = "type",
.t = NEU_JSON_INT,
.v.val_int = resp->type,
},
{
.name = "is_array",
.t = NEU_JSON_BOOL,
.v.val_bool = resp->is_array,
},
{
.name = "tags",
.t = NEU_JSON_OBJECT,
.v.val_object = tag_array,
} };
ret = neu_json_encode_field(json_object, resp_elems,
NEU_JSON_ELEM_SIZE(resp_elems));
return ret;
}
+12
View File
@@ -159,4 +159,16 @@ void neu_async_queue_clean(neu_async_queue_t *q)
free(el);
}
pthread_mutex_unlock(&q->mtx);
}
int neu_async_queue_len(neu_async_queue_t *q)
{
int count = 0;
element *elt = NULL;
pthread_mutex_lock(&q->mtx);
DL_COUNT(q->list, elt, count);
pthread_mutex_unlock(&q->mtx);
return count;
}
+47 -5
View File
@@ -17,6 +17,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -25,6 +26,38 @@
#include "utils/log.h"
#include "json/json.h"
static double format_tag_value(float ele_value)
{
double scale = pow(10, 5);
double value = ele_value;
int64_t integer_part = (int64_t)(value);
double decimal_part = value - integer_part;
decimal_part *= scale;
decimal_part = round(decimal_part);
char str[6] = { 0 };
snprintf(str, sizeof(str), "%05" PRId64 "", (int64_t) decimal_part);
int i = 0, flag = 0;
for (; i < 4; i++) {
if (str[i] == '0' && str[i + 1] == '0') {
flag = 1;
break;
} else if (str[i] == '9' && str[i + 1] == '9') {
flag = 2;
break;
}
}
if (flag != 0 && i != 0) {
decimal_part = round(decimal_part / pow(10, 5 - i));
value = (double) integer_part + decimal_part / pow(10, i);
} else {
value = (double) integer_part + decimal_part / scale;
}
return value;
}
static json_t *encode_object_value(neu_json_elem_t *ele)
{
json_t *ob = NULL;
@@ -42,9 +75,14 @@ static json_t *encode_object_value(neu_json_elem_t *ele)
case NEU_JSON_DOUBLE:
ob = json_realp(ele->v.val_double, ele->precision);
break;
case NEU_JSON_FLOAT:
ob = json_realp(ele->v.val_float, ele->precision);
case NEU_JSON_FLOAT: {
double t = ele->v.val_float;
if (ele->precision == 0 && ele->bias == 0) {
t = format_tag_value(ele->v.val_float);
}
ob = json_realp(t, ele->precision);
break;
}
case NEU_JSON_BOOL:
ob = json_boolean(ele->v.val_bool);
break;
@@ -69,10 +107,14 @@ static json_t *encode_object(json_t *object, neu_json_elem_t ele)
case NEU_JSON_STR:
json_object_set_new(ob, ele.name, json_string(ele.v.val_str));
break;
case NEU_JSON_FLOAT:
json_object_set_new(ob, ele.name,
json_realp(ele.v.val_float, ele.precision));
case NEU_JSON_FLOAT: {
double t = ele.v.val_float;
if (ele.precision == 0 && ele.bias == 0) {
t = format_tag_value(ele.v.val_float);
}
json_object_set_new(ob, ele.name, json_realp(t, ele.precision));
break;
}
case NEU_JSON_DOUBLE:
json_object_set_new(ob, ele.name,
json_realp(ele.v.val_double, ele.precision));
+21
View File
@@ -744,6 +744,27 @@ class TestModbus:
assert 0 == api.read_tag(
node=param[0], group='group', tag=input_bit_5[0]['name'])
@description(given="created modbus node", when="test read tag", then="read tcp success and read rtu failed")
def test_modbus_test_read_tag(self, param):
body = {
"driver": param[0],
"group": "group",
"tag": "tag",
"address": "1!400001",
"attribute": config.NEU_TAG_ATTRIBUTE_RW,
"type": config.NEU_TYPE_INT16,
"precision": 0,
"decimal": 0,
"bias": 0.0
}
if param[0] == 'modbus-tcp':
time.sleep(1)
response = api.test_read_tag(json=body)
assert response.json()["value"] == -123
else:
response = api.test_read_tag(json=body)
assert response.json()["error"] == 3022
@description(given="created modbus node and tags", when="read tags fuzz", then="should return correct result")
def test_read_tags_fuzz(self, param):
response = api.read_tags(
+40 -34
View File
@@ -222,12 +222,13 @@ driver_2 = {
]
}
class TestHttp:
@description(given="running neuron", when="add driver/app node/group/tag, app subscribes driver group, and get global config", then="success")
def test_get_global_config(self):
response = api.put_global_config(json=global_config)
assert 200 == response.status_code
assert 200 == response.status_code
assert error.NEU_ERR_SUCCESS == response.json()['error']
response = api.get_global_config()
@@ -258,7 +259,7 @@ class TestHttp:
assert config_data['settings'][0]['node'] == 'mqtt'
response = api.put_global_config(json=global_config_del_modbus)
assert 200 == response.status_code
assert 200 == response.status_code
assert error.NEU_ERR_SUCCESS == response.json()['error']
response = api.get_global_config()
@@ -286,41 +287,39 @@ class TestHttp:
for node in global_config['nodes']:
api.del_node(node['name'])
@description(given="running neuron", when="put drivers with too long node name", then="should fail")
def test_put_drivers_with_long_node_name(self):
response = api.put_driver(name='long'*100, plugin=driver_1['plugin'], params=driver_1['params'])
response = api.put_driver(
name='long'*100, plugin=driver_1['plugin'], params=driver_1['params'])
assert 400 == response.status_code
assert error.NEU_ERR_NODE_NAME_TOO_LONG == response.json()['error']
@description(given="running neuron", when="put drivers with duplicate node name", then="should fail")
def test_put_drivers_with_duplicate_node(self):
response = api.put_drivers([driver_1, driver_1])
assert 400 == response.status_code
assert error.NEU_ERR_BODY_IS_WRONG == response.json()['error']
@description(given="running neuron", when="put drivers with non-existent plugin", then="should fail")
def test_put_drivers_with_nonexistent_plugin(self):
response = api.put_driver(name=driver_1['name'], plugin='unkown', params=driver_1['params'])
response = api.put_driver(
name=driver_1['name'], plugin='unkown', params=driver_1['params'])
assert 404 == response.status_code
assert error.NEU_ERR_LIBRARY_NOT_FOUND == response.json()['error']
@description(given="running neuron", when="put drivers with too long plugin name", then="should fail")
def test_put_drivers_with_long_plugin_name(self):
response = api.put_driver(name=driver_1['name'], plugin='long'*100, params=driver_1['params'])
response = api.put_driver(
name=driver_1['name'], plugin='long'*100, params=driver_1['params'])
assert 400 == response.status_code
assert error.NEU_ERR_PLUGIN_NAME_TOO_LONG == response.json()['error']
@description(given="running neuron", when="put drivers with north plugin", then="should fail")
def test_put_drivers_with_north_plugin(self):
response = api.put_driver(name='not-driver', plugin='MQTT', params={})
assert 400 == response.status_code
assert error.NEU_ERR_PLUGIN_TYPE_NOT_SUPPORT == response.json()['error']
assert error.NEU_ERR_PLUGIN_TYPE_NOT_SUPPORT == response.json()[
'error']
@description(given="running neuron", when="put drivers with too long group name", then="should fail")
def test_put_drivers_with_long_group_name(self):
@@ -330,7 +329,6 @@ class TestHttp:
assert 400 == response.status_code
assert error.NEU_ERR_GROUP_NAME_TOO_LONG == response.json()['error']
@description(given="running neuron", when="put drivers with duplicate group name", then="should fail")
def test_put_drivers_with_duplicate_group(self):
driver = copy.deepcopy(driver_1)
@@ -339,15 +337,14 @@ class TestHttp:
assert 400 == response.status_code
assert error.NEU_ERR_BODY_IS_WRONG == response.json()['error']
@description(given="running neuron", when="put drivers with invalid group interval", then="should fail")
def test_put_drivers_with_invalid_group_interval(self):
driver = copy.deepcopy(driver_1)
driver["groups"][0]["interval"] = 10
response = api.put_drivers([driver])
assert 400 == response.status_code
assert error.NEU_ERR_GROUP_PARAMETER_INVALID == response.json()['error']
assert error.NEU_ERR_GROUP_PARAMETER_INVALID == response.json()[
'error']
@description(given="running neuron", when="put drivers with too many groups", then="should fail")
def test_put_drivers_with_too_many_groups(self):
@@ -361,7 +358,6 @@ class TestHttp:
assert 400 == response.status_code
assert error.NEU_ERR_GROUP_MAX_GROUPS == response.json()['error']
@description(given="running neuron", when="put drivers with duplicate tag name", then="should fail")
def test_put_drivers_with_duplicate_tag(self):
driver = copy.deepcopy(driver_1)
@@ -370,7 +366,6 @@ class TestHttp:
assert 400 == response.status_code
assert error.NEU_ERR_BODY_IS_WRONG == response.json()['error']
@description(given="running neuron", when="put drivers", then="should success")
def test_put_drivers(self):
drivers = [driver_1, driver_2]
@@ -394,7 +389,6 @@ class TestHttp:
api.del_node(driver["name"])
@description(given="running neuron", when="put drivers that exists", then="should replace")
def test_put_drivers_already_exist(self):
response = api.put_drivers([driver_1])
@@ -426,7 +420,6 @@ class TestHttp:
api.del_node(driver["name"])
@description(given="running neuron", when="put drivers", then="should be persisted")
def test_put_drivers_persistence(self, class_setup_and_teardown):
drivers = [driver_1, driver_2]
@@ -443,7 +436,6 @@ class TestHttp:
assert len(group["tags"]) == len(response.json()["tags"])
api.del_node(driver["name"])
@description(given="running neuron", when="get drivers", then="should success")
def test_get_drivers(self):
drivers = [driver_1, driver_2]
@@ -474,25 +466,26 @@ class TestHttp:
# filter by driver_1 and driver_2
response = api.get_drivers(names=[driver_1["name"], driver_2["name"]])
assert 200 == response.status_code
resp_drivers = sorted(response.json()["nodes"], key=lambda x: x["name"])
resp_drivers = sorted(
response.json()["nodes"], key=lambda x: x["name"])
assert 2 == len(resp_drivers)
assert drivers == resp_drivers
# no filter
response = api.get_drivers()
assert 200 == response.status_code
resp_drivers = sorted(response.json()["nodes"], key=lambda x: x["name"])
resp_drivers = sorted(
response.json()["nodes"], key=lambda x: x["name"])
assert 2 == len(resp_drivers)
assert drivers == resp_drivers
for driver in drivers:
api.del_node(driver["name"])
@description(given="running neuron", when="get subscribe info", then="should success")
def test_get_subscribe_info(self):
app = 'MQTT-1'
params = {'topic':'/neuron/test'}
params = {'topic': '/neuron/test'}
driver_1 = 'modbus-01'
driver_2 = 'modbus-02'
group_1 = 'group-01'
@@ -513,7 +506,8 @@ class TestHttp:
# match all drivers
response = api.get_subscribe_group(app, driver='modbus')
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 4
assert groups[0]['driver'] == driver_1
assert groups[0]['group'] == group_1
@@ -527,7 +521,8 @@ class TestHttp:
# match one driver
response = api.get_subscribe_group(app, driver=driver_1)
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 2
assert groups[0]['driver'] == driver_1
assert groups[0]['group'] == group_1
@@ -542,7 +537,8 @@ class TestHttp:
# match all groups
response = api.get_subscribe_group(app, group='group')
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 4
assert groups[0]['driver'] == driver_1
assert groups[0]['group'] == group_1
@@ -556,7 +552,8 @@ class TestHttp:
# match one group
response = api.get_subscribe_group(app, group=group_1)
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 2
assert groups[0]['driver'] == driver_1
assert groups[0]['group'] == group_1
@@ -569,15 +566,19 @@ class TestHttp:
assert len(response.json()['groups']) == 0
# match driver and group
response = api.get_subscribe_group(app, driver=driver_1, group=group_1)
response = api.get_subscribe_group(
app, driver=driver_1, group=group_1)
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 1
assert groups[0]['driver'] == driver_1
assert groups[0]['group'] == group_1
response = api.get_subscribe_group(app, driver=driver_2, group=group_2)
response = api.get_subscribe_group(
app, driver=driver_2, group=group_2)
assert 200 == response.status_code
groups = sorted(response.json()['groups'], key=lambda g: (g['driver'], g['group']))
groups = sorted(response.json()['groups'], key=lambda g: (
g['driver'], g['group']))
assert len(groups) == 1
assert groups[0]['driver'] == driver_2
assert groups[0]['group'] == group_2
@@ -608,6 +609,11 @@ class TestHttp:
response = api.get_version()
assert 200 == response.status_code
@description(given="running neuron", when="get status", then="success")
def test_get_status(self):
response = api.get_status()
assert 200 == response.status_code
@description(given="running neuron", when="test jwt error", then="failed")
def test_jwt_err(self):
response = api.change_password(new_password='123456', jwt='invalid')
@@ -626,4 +632,4 @@ class TestHttp:
assert 404 == response.status_code
response = api.delete_virtual_license(jwt='invalid')
assert 404 == response.status_code
assert 404 == response.status_code
+293
View File
@@ -0,0 +1,293 @@
import neuron.api as api
import neuron.error as error
import neuron.config as config
from neuron.common import *
tcp_port = random_port()
@pytest.fixture(params=[('modbus-tcp', config.PLUGIN_MODBUS_TCP)], scope='class')
def param(request):
return request.param
@pytest.fixture(autouse=True, scope='class')
def simulator_setup_teardown(param):
p = process.start_simulator(
['./modbus_simulator', 'tcp', f'{tcp_port}', 'ip_v4'])
response = api.add_node(node=param[0], plugin=param[1])
assert 200 == response.status_code
response = api.add_group(node=param[0], group='group')
assert 200 == response.status_code
response = api.modbus_tcp_node_setting(
node=param[0], interval=1, port=tcp_port)
yield
process.stop_simulator(p)
hold_bit = [{"name": "hold_bit", "address": "1!400001.15",
"attribute": config.NEU_TAG_ATTRIBUTE_READ_SUBSCRIBE, "type": config.NEU_TYPE_BIT, "description": "123"}]
hold_int16 = [{"name": "hold_int16", "address": "1!400001",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_INT16, "description": "123"}]
hold_uint16 = [{"name": "hold_uint16", "address": "1!400002",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_UINT16, "description": "456"}]
hold_int32 = [{"name": "hold_int32", "address": "1!400003",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_INT32, "description": "456"}]
hold_uint32 = [{"name": "hold_uint32", "address": "1!400015",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_UINT32}]
hold_float = [{"name": "hold_float", "address": "1!400017",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_FLOAT}]
hold_string = [{"name": "hold_string", "address": "1!400020.10",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_STRING}]
hold_bytes = [{"name": "hold_bytes", "address": "1!400040.10",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_BYTES}]
class TestReadPaginate:
@description(given="created modbus node", when="add multiple tags", then="add success")
def test_add_tags(self, param):
api.add_tags_check(node=param[0], group='group', tags=hold_bit)
api.add_tags_check(node=param[0], group='group', tags=hold_int16)
api.add_tags_check(node=param[0], group='group', tags=hold_uint16)
api.add_tags_check(node=param[0], group='group', tags=hold_int32)
api.add_tags_check(node=param[0], group='group', tags=hold_uint32)
api.add_tags_check(node=param[0], group='group', tags=hold_float)
api.add_tags_check(node=param[0], group='group', tags=hold_string)
api.add_tags_check(node=param[0], group='group', tags=hold_bytes)
@description(given="created modbus node and tags", when="write/read tags without filter", then="write/read success")
def test_write_read_tags(self, param):
api.write_tag_check(
node=param[0], group='group', tag=hold_int16[0]['name'], value=-123)
api.write_tag_check(
node=param[0], group='group', tag=hold_uint16[0]['name'], value=123)
api.write_tag_check(
node=param[0], group='group', tag=hold_int32[0]['name'], value=-1234)
api.write_tag_check(
node=param[0], group='group', tag=hold_uint32[0]['name'], value=1234)
api.write_tag_check(
node=param[0], group='group', tag=hold_float[0]['name'], value=13.4121)
api.write_tag_check(
node=param[0], group='group', tag=hold_string[0]['name'], value='hello')
api.write_tag_check(
node=param[0], group='group', tag=hold_bytes[0]['name'], value=[0x1, 0x2, 0x3, 0x4])
time.sleep(0.3)
response = api.read_tags_paginate(node=param[0], group='group')
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 8 == len(response.json()["items"])
assert "hold_bit" == response.json()["items"][0]["name"]
assert 1 == response.json()["items"][0]["value"]
assert "hold_int16" == response.json()["items"][1]["name"]
assert -123 == response.json()["items"][1]["value"]
assert "hold_uint16" == response.json()["items"][2]["name"]
assert 123 == response.json()["items"][2]["value"]
assert "hold_int32" == response.json()["items"][3]["name"]
assert -1234 == response.json()["items"][3]["value"]
assert "hold_uint32" == response.json()["items"][4]["name"]
assert 1234 == response.json()["items"][4]["value"]
assert "hold_float" == response.json()["items"][5]["name"]
assert compare_float(13.4121, response.json()["items"][5]["value"])
assert "hold_string" == response.json()["items"][6]["name"]
assert 'hello' == response.json()["items"][6]["value"]
assert "hold_bytes" == response.json()["items"][7]["name"]
assert [0x1, 0x2, 0x3, 0x4, 0, 0, 0, 0, 0, 0] == response.json()["items"][7]["value"]
@description(given="created modbus node and tags", when="read tags with filter(name)", then="read success")
def test_read_tags_filter_name(self, param):
response = api.read_tags_paginate(node=param[0], group='group', query= {"name": "int16"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 2 == response.json()["meta"]["total"]
assert 2 == len(response.json()["items"])
assert "hold_int16" == response.json()["items"][0]["name"]
assert -123 == response.json()["items"][0]["value"]
assert "hold_uint16" == response.json()["items"][1]["name"]
assert 123 == response.json()["items"][1]["value"]
@description(given="created modbus node and tags", when="read tags with filter(desc)", then="read success")
def test_read_tags_filter_desc(self, param):
response = api.read_tags_paginate(node=param[0], group='group', query= {"description": "12"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 2 == response.json()["meta"]["total"]
assert 2 == len(response.json()["items"])
assert "hold_bit" == response.json()["items"][0]["name"]
assert 1 == response.json()["items"][0]["value"]
assert "hold_int16" == response.json()["items"][1]["name"]
assert -123 == response.json()["items"][1]["value"]
@description(given="created modbus node and tags", when="read tags with paginate", then="read success")
def test_read_tags_paginate(self, param):
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 1, "pageSize": 5})
assert 1 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 5 == len(response.json()["items"])
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 2, "pageSize": 5})
assert 2 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 3 == len(response.json()["items"])
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 3, "pageSize": 5})
assert 3 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 0 == len(response.json()["items"])
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 6, "pageSize": 5})
assert 6 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 0 == len(response.json()["items"])
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 0, "pageSize": 5})
assert 0 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 8 == len(response.json()["items"])
@description(given="created modbus node and tags", when="read tags with filter(isError)", then="read success")
def test_read_tags_filter_isError(self, param):
response = api.read_tags_paginate(node=param[0], group='group', query= {"isError": True})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 0 == response.json()["meta"]["total"]
assert 0 == len(response.json()["items"])
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_STOP)
response = api.read_tags_paginate(node=param[0], group='group', query= {"isError": True})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 8 == len(response.json()["items"])
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_START)
time.sleep(0.3)
@description(given="created modbus node and tags", when="read tags with filter(name&desc)", then="read success")
def test_read_tags_filter_name_desc(self, param):
response = api.read_tags_paginate(node=param[0], group='group', query= {"name": "16", "description": "123"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 1 == response.json()["meta"]["total"]
assert 1 == len(response.json()["items"])
assert "hold_int16" == response.json()["items"][0]["name"]
assert -123 == response.json()["items"][0]["value"]
@description(given="created modbus node and tags", when="read tags with filter(isError&name)", then="read success")
def test_read_tags_filter_isError_name(self, param):
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_STOP)
response = api.read_tags_paginate(node=param[0], group='group', query= {"isError": True, "name": "16"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 2 == response.json()["meta"]["total"]
assert 2 == len(response.json()["items"])
assert "hold_int16" == response.json()["items"][0]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][0]["error"]
assert "hold_uint16" == response.json()["items"][1]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][1]["error"]
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_START)
time.sleep(0.3)
@description(given="created modbus node and tags", when="read tags with filter(isError&desc)", then="read success")
def test_read_tags_filter_isError_desc(self, param):
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_STOP)
response = api.read_tags_paginate(node=param[0], group='group', query= {"isError": True, "description": "12"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 2 == response.json()["meta"]["total"]
assert 2 == len(response.json()["items"])
assert "hold_bit" == response.json()["items"][0]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][0]["error"]
assert "hold_int16" == response.json()["items"][1]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][1]["error"]
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_START)
time.sleep(0.3)
@description(given="created modbus node and tags", when="read tags with filter(isError&name&desc)", then="read success")
def test_read_tags_filter_isError_name_desc(self, param):
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_STOP)
response = api.read_tags_paginate(node=param[0], group='group', query= {"isError": True, "name":"16", "description": "12"})
assert 0 == response.json()["meta"]["currentPage"]
assert 0 == response.json()["meta"]["pageSize"]
assert 1 == response.json()["meta"]["total"]
assert 1 == len(response.json()["items"])
assert "hold_int16" == response.json()["items"][0]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][0]["error"]
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_START)
time.sleep(0.3)
@description(given="created modbus node and tags", when="read tags with paginate & filter(isError)", then="read success")
def test_read_tags_paginate_filter_isError(self, param):
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_STOP)
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 1, "pageSize": 5, "isError": True})
assert 1 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 5 == len(response.json()["items"])
assert "hold_bit" == response.json()["items"][0]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][0]["error"]
assert "hold_int16" == response.json()["items"][1]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][1]["error"]
assert "hold_uint16" == response.json()["items"][2]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][2]["error"]
assert "hold_int32" == response.json()["items"][3]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][3]["error"]
assert "hold_uint32" == response.json()["items"][4]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][4]["error"]
response = api.read_tags_paginate(node=param[0], group='group', query= {"currentPage": 2, "pageSize": 5, "isError": True})
assert 2 == response.json()["meta"]["currentPage"]
assert 5 == response.json()["meta"]["pageSize"]
assert 8 == response.json()["meta"]["total"]
assert 3 == len(response.json()["items"])
assert "hold_float" == response.json()["items"][0]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][0]["error"]
assert "hold_string" == response.json()["items"][1]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][1]["error"]
assert "hold_bytes" == response.json()["items"][2]["name"]
assert error.NEU_ERR_PLUGIN_NOT_RUNNING == response.json()["items"][2]["error"]
api.node_ctl_check(node='modbus-tcp', ctl=config.NEU_CTL_START)
time.sleep(0.3)
+2 -1
View File
@@ -3,5 +3,6 @@
"port": 7000,
"disable_auth": 1,
"syslog_host": "",
"syslog_port": 541
"syslog_port": 541,
"sub_filter_error": 0
}
+8
View File
@@ -0,0 +1,8 @@
{
"ip": "0.0.0.0",
"port": 7000,
"disable_auth": 0,
"syslog_host": "",
"syslog_port": 541,
"sub_filter_error": 1
}
+144 -1
View File
@@ -1,14 +1,157 @@
import pytest
import neuron.api as api
from neuron.config import *
from neuron.common import description
from neuron.common import (
description,
random_port,
)
import neuron.process as process
import neuron.config as config
from neuron.error import *
import shutil
import os
from neuron.mqtt import Mock
import time
mqtt_node = "mqtt"
upload_topic = "/neuron/test/sub_filter"
modbus_port = random_port()
modbus_node = "modbus_tcp"
hold_bit = [{"name": "hold_bit", "address": "1!400001.15",
"attribute": config.NEU_TAG_ATTRIBUTE_READ_SUBSCRIBE, "type": config.NEU_TYPE_BIT}]
hold_int16 = [{"name": "hold_int16", "address": "1!400001",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_INT16}]
hold_uint16 = [{"name": "hold_uint16", "address": "1!400002",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_UINT16}]
hold_int32 = [{"name": "hold_int32", "address": "1!400003",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_INT32}]
hold_uint32 = [{"name": "hold_uint32", "address": "1!400015",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_UINT32}]
hold_float = [{"name": "hold_float", "address": "1!400017",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_FLOAT}]
hold_string = [{"name": "hold_string", "address": "1!400020.10",
"attribute": config.NEU_TAG_ATTRIBUTE_RW_SUBSCRIBE, "type": config.NEU_TYPE_STRING}]
@pytest.fixture(autouse=True, scope="class")
def mocker():
mock = Mock()
yield mock
mock.done()
class TestLaunch:
@description(
given="sub_filter_error(command line)",
when="start neuron",
then="should make sense",
)
def test_sub_filter_error_command(self, mocker):
process.remove_persistence()
p = process.NeuronProcess()
p.start_sub_filter_err()
api.add_node(node=mqtt_node, plugin=config.PLUGIN_MQTT)
api.mqtt_node_setting(node=mqtt_node, client_id=mocker.rand_id(), host="127.0.0.1", port=mocker.port)
api.add_node(node=modbus_node, plugin=config.PLUGIN_MODBUS_TCP)
api.modbus_tcp_node_setting(node=modbus_node, port=modbus_port)
api.add_group(node=modbus_node, group='group')
api.add_tags_check(node=modbus_node, group='group', tags=hold_bit)
api.add_tags_check(node=modbus_node, group='group', tags=hold_int16)
api.add_tags_check(node=modbus_node, group='group', tags=hold_uint16)
api.add_tags_check(node=modbus_node, group='group', tags=hold_int32)
api.add_tags_check(node=modbus_node, group='group', tags=hold_uint32)
api.add_tags_check(node=modbus_node, group='group', tags=hold_float)
api.add_tags_check(node=modbus_node, group='group', tags=hold_string)
api.subscribe_group(app=mqtt_node, driver=modbus_node, group='group', params={"topic":upload_topic})
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
p_s = process.start_simulator(
["./modbus_simulator", "tcp", f"{modbus_port}", "ip_v4"]
)
time.sleep(5)
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
p.stop()
process.stop_simulator(p_s)
@description(
given="sub_filter_error(environment variable)",
when="start neuron",
then="should make sense",
)
def test_sub_filter_error_environment(self, mocker):
os.environ['NEURON_SUB_FILTER_ERROR'] = '1'
p = process.NeuronProcess()
p.start()
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
p_s = process.start_simulator(
["./modbus_simulator", "tcp", f"{modbus_port}", "ip_v4"]
)
time.sleep(5)
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
del os.environ['NEURON_SUB_FILTER_ERROR']
p.stop()
process.stop_simulator(p_s)
@description(
given="sub_filter_error(configuration file)",
when="start neuron",
then="should make sense",
)
def test_sub_filter_error_file(self, mocker):
dst_file = './build/config/neuron.json'
dst_backup = dst_file + '_backup'
os.rename(dst_file, dst_backup)
try:
shutil.copy2('./tests/ft/login/sub_filter_error.json', dst_file)
except Exception as e:
if os.path.exists(dst_backup):
os.rename(dst_backup, dst_file)
return
p = process.NeuronProcess()
p.start()
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
p_s = process.start_simulator(
["./modbus_simulator", "tcp", f"{modbus_port}", "ip_v4"]
)
time.sleep(5)
msg = mocker.get(upload_topic, timeout=3)
assert msg is None
p.stop()
process.stop_simulator(p_s)
os.remove(dst_file)
os.rename(dst_backup, dst_file)
@description(given="encironment variables 0, configuration file 0 , command line 1",
when="start neuron",
then="command line has the highest priority")
+30 -6
View File
@@ -22,6 +22,7 @@ def gen_check(func):
def ping():
return requests.post(url=config.BASE_URL + '/api/v2/ping')
def login(user='admin', password='0000'):
return requests.post(url=config.BASE_URL + '/api/v2/login', json={"name": user, "pass": password})
@@ -158,6 +159,17 @@ def read_tags(node, group, sync=False, query=None):
return requests.post(url=config.BASE_URL + "/api/v2/read", headers={"Authorization": config.default_jwt}, json=body)
def read_tags_paginate(node, group, sync=False, query=None):
body = {"node": node, "group": group, "sync": sync}
if query:
body["query"] = query
return requests.post(url=config.BASE_URL + "/api/v2/read/paginate", headers={"Authorization": config.default_jwt}, json=body)
def test_read_tag(json):
return requests.post(url=config.BASE_URL + '/api/v2/read/test', headers={"Authorization": config.default_jwt}, json=json)
def read_tag(node, group, tag, sync=False):
response = read_tags(node, group, sync, query={"name": tag})
assert 200 == response.status_code
@@ -235,12 +247,12 @@ def get_subscribe_group(app, driver=None, group=None):
@gen_check
def subscribe_group(app, driver, group, params={}):
def subscribe_group(app, driver, group, params={"topic": "/neuron/mqtt/test"}):
return requests.post(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group, "params": params})
@gen_check
def subscribe_group_update(app, driver, group, params={}):
def subscribe_group_update(app, driver, group, params={"topic": "/neuron/mqtt/test"}):
return requests.put(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group, "params": params})
@@ -276,6 +288,10 @@ def put_drivers(drivers, jwt=config.default_jwt):
return requests.put(url=config.BASE_URL + '/api/v2/global/drivers', headers={"Authorization": jwt}, json={"nodes": drivers})
def get_status():
return requests.get(url=config.BASE_URL + "/api/v2/status", headers={"Authorization": config.default_jwt})
def get_driver(name, jwt=config.default_jwt):
return get_drivers(names=[name])
@@ -320,6 +336,7 @@ def modbus_rtu_node_setting(node, port=502, connection_mode=0, transport_mode=0,
"max_retries": max_retries, "link": link, "device": device, "stop": stop,
"parity": parity, "baud": baud, "data": data})
def modbus_tcp_node_setting_endian(node, port, connection_mode=0, transport_mode=0, interval=0, host='127.0.0.1', timeout=3000, max_retries=2, endianness=1):
return node_setting(node, json={"connection_mode": connection_mode, "transport_mode": transport_mode, "interval": interval,
"host": host, "port": port, "timeout": timeout, "max_retries": max_retries, "endianess": endianness})
@@ -331,6 +348,7 @@ def modbus_rtu_node_setting_endian(node, port=502, connection_mode=0, transport_
"max_retries": max_retries, "link": link, "device": device, "stop": stop,
"parity": parity, "baud": baud, "data": data, "endianess": endianness})
def modbus_tcp_node_setting_base(node, port, connection_mode=0, transport_mode=0, interval=0, host='127.0.0.1', timeout=3000, max_retries=2, base=1):
return node_setting(node, json={"connection_mode": connection_mode, "transport_mode": transport_mode, "interval": interval,
"host": host, "port": port, "timeout": timeout, "max_retries": max_retries, "address_base": base})
@@ -343,10 +361,16 @@ def modbus_rtu_node_setting_base(node, port=502, connection_mode=0, transport_mo
"parity": parity, "baud": baud, "data": data, "address_base": base})
def mqtt_node_setting(node):
return node_setting(node, json={"client-id": "neuron_aBcDeF", "qos": 0, "format": 0,
def mqtt_node_setting(node, client_id="neuron_aBcDeF", host="broker.emqx.io", port=1883):
return node_setting(node, json={"client-id": client_id, "qos": 0, "format": 0,
"write-req-topic": f"/neuron/{node}/write/req", "write-resp-topic": f"/neuron/{node}/write/resp",
"offline-cache": False, "cache-sync-interval": 100, "host": "broker.emqx.io", "port": 1883, "username": "", "password": "", "ssl": False})
"offline-cache": False, "cache-sync-interval": 100, "host": host, "port": port, "username": "", "password": "", "ssl": False})
def get_nodes_disable_auth(type):
return requests.get(url=config.BASE_URL + '/api/v2/node', params={"type": type})
return requests.get(url=config.BASE_URL + '/api/v2/node', params={"type": type})
@gen_check
def scan_tags(node, id):
return requests.post(url=config.BASE_URL + "/api/v2/scan/tags", headers={"Authorization": config.default_jwt}, json={"node": node, "id": id})
+1 -1
View File
@@ -1,5 +1,5 @@
BASE_URL = "http://127.0.0.1:7000"
default_jwt = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJuZXVyb24iLCJib2R5RW5jb2RlIjowLCJleHAiOjE3MTc4MzUyNjIsImlhdCI6MTY4NjI5OTI2MiwiaXNzIjoibmV1cm9uIn0.tJ8Z12S5lzzyqvJedFr11w0FmQ8l9inFHuzcuA_3uKoNBJSZlQAkcWyDAO2XELyuZFtHPrk8pJFgEqTzwphtBAybVXbeHBRWED5XuHvYqznzwk1J2UCOuw_ehmHnLszZHRAcMoeLWIRIx0KM7BXvZAyFA2J1axJntxfRrurNMn6MbfnGGtza6hJfuQ6pG-h4cHhrBOogf8nw3f8RLfd16vbWobhEp8KBUrwsfn2Iv4hMXvZMekv_PXboLO74f7oMkEL6pdM9g6G6rDBTjTU8FssfeyJcAP7Xb9mS2G7GNW5B8twtPVLtpOQH9VNbLa4OQxdMb0WN86i9vSDiCOoN6A"
default_jwt = "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJuZXVyb24iLCJib2R5RW5jb2RlIjowLCJleHAiOjE3ODExNTc4MzcsImlhdCI6MTcxODA4NTgzOCwiaXNzIjoibmV1cm9uIn0.OmMIxGiaJYcuetslmliVGAWtjIZxNgvOCsZGdljHUSnFBOpTV1BqFSBqR55tZx51z09RPEdm8tIeGZN-jUUQgXgS22K7LUqhAYXgGY8bhh37pN6GXPzaHCdjan3VzS_5ywuiGHgNIjr5RrHNTCjLGb_dYlUGL-Hv0z0cOC6ObbqS0snlEOJsxNcjOaRMqbpwtxuTKc4_QA0yWtYTyGXjhXVA2ZAg1HsF9M_9XJ2qk-_6qEadAR2MzjphJvsk-um1oHOGtJhGGxlRNONL6yxFav2BTHs2dSz2P1YanVsUtFF0HO44HYPU4vs511RuOvcHyTM1TV3BudKgDpCeWKpq1Q"
NEU_NODE_DRIVER = 1
NEU_NODE_APP = 2
+1
View File
@@ -107,5 +107,6 @@ NEU_ERR_PLUGIN_NOT_SUPPORT_WRITE_TAGS = 3017
NEU_ERR_PLUGIN_NOT_SUPPORT_READ_SYNC = 3018
NEU_ERR_PLUGIN_TYPE_NOT_SUPPORT = 3019
NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE = 3020
NEU_ERR_PLUGIN_NOT_SUPPORT_SCAN_TAGS = 3021
NEU_ERR_MQTT_SUBSCRIBE_FAILURE = 4010
+11
View File
@@ -30,6 +30,9 @@ class NeuronProcess:
def start_debug(self):
self.p = start_neuron_debug(self.dir)
def start_sub_filter_err(self):
self.p = start_neuron_sub_filter_err(self.dir)
def start_neuron_disable_auth(dir='build/'):
command = ['./neuron', '--disable_auth']
process = subprocess.Popen(
@@ -46,6 +49,14 @@ def start_neuron_debug(dir='build/'):
assert process.poll() is None
return process
def start_neuron_sub_filter_err(dir='build/'):
command = ['./neuron', '--sub_filter_error']
process = subprocess.Popen(
command, stderr=subprocess.PIPE, cwd=dir)
time.sleep(1)
assert process.poll() is None
return process
def start_neuron(dir='build/'):
process = subprocess.Popen(
['./neuron'], stderr=subprocess.PIPE, cwd=dir)
+1 -1
View File
@@ -244,7 +244,7 @@ class TestPlugin:
assert 200 == response.status_code
for plugin in response.json().get("plugins"):
if plugin['name'] == 'c1':
assert plugin['version'] == '2.7.99'
assert plugin['version'] == '2.9.99'
@description(given="incorrect configuration", when="update plugin", then="fail")
def test_10_update_plugin_fail3(self):
+1 -1
View File
@@ -63,7 +63,7 @@ static const neu_plugin_intf_funs_t plugin_intf_funs = {
};
const neu_plugin_module_t neu_plugin_module = {
.version = NEU_VERSION(2, 7, 99),
.version = NEU_VERSION(2, 9, 99),
.schema = "c1",
.module_name = "c1",
.module_descr = "c1 v2",
+1 -1
View File
@@ -1 +1 @@
2.7.0-dev
2.9.5