mirror of
https://github.com/emqx/neuron.git
synced 2026-10-30 07:45:59 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1814ec84b2 | ||
|
|
08f7ba5c41 | ||
|
|
6c58bfe212 | ||
|
|
1c2f37adbe | ||
|
|
c1cacfe21e | ||
|
|
b9c8a96a8c | ||
|
|
5c05e7d4ec | ||
|
|
7b7a590d8f | ||
|
|
199965c12d | ||
|
|
ba65158442 | ||
|
|
cfde4a9dd7 | ||
|
|
20b629b242 | ||
|
|
752719abc2 | ||
|
|
4387db1fc1 | ||
|
|
151d4b9c70 | ||
|
|
a441dd0209 | ||
|
|
4659a8381d | ||
|
|
cdad099f0c | ||
|
|
ddb89ceea0 | ||
|
|
4b7fa2773e | ||
|
|
0a30599817 | ||
|
|
845b21a4e0 | ||
|
|
c7a255eee5 | ||
|
|
c6df9045ed | ||
|
|
16330d3409 | ||
|
|
602613b88d | ||
|
|
addc570a90 | ||
|
|
c642cee9f1 | ||
|
|
5adcfeed22 | ||
|
|
823cb8c970 | ||
|
|
08d91027d9 | ||
|
|
97f0cd873d | ||
|
|
fa9c278a03 | ||
|
|
989235c033 | ||
|
|
f8189c4ff8 | ||
|
|
b8f06d14a0 | ||
|
|
088d5ccdbb | ||
|
|
df2c33d71c | ||
|
|
b2abc42675 | ||
|
|
6779877965 | ||
|
|
2e05ab4bba | ||
|
|
6793c0a1f0 | ||
|
|
8bd802c492 | ||
|
|
d2502d0482 | ||
|
|
a058f8deb8 | ||
|
|
54c7a73878 | ||
|
|
250d19af8d | ||
|
|
515d31c4e8 | ||
|
|
264796888c | ||
|
|
ad3e7b929d | ||
|
|
1ed8d3775c | ||
|
|
6e7883c1bc | ||
|
|
f8f4da41a1 | ||
|
|
6fd41502fe | ||
|
|
d5df0b6dc6 | ||
|
|
58eb2e6864 | ||
|
|
2915e9790c | ||
|
|
b4482f19be | ||
|
|
356ba04f12 | ||
|
|
0f75d43b5c | ||
|
|
0dd8fc3262 | ||
|
|
2180913545 | ||
|
|
96ec0c5a81 | ||
|
|
5c6140ec35 | ||
|
|
a867dd6266 | ||
|
|
7593060a3e | ||
|
|
a7946c4f17 | ||
|
|
224f748ddf | ||
|
|
734bf74367 | ||
|
|
315f44baf1 | ||
|
|
53999c225f | ||
|
|
3381f531d9 | ||
|
|
b6921c6d1d | ||
|
|
d3094dd316 | ||
|
|
14a3dbd03b | ||
|
|
22b5802c08 | ||
|
|
13599083d0 | ||
|
|
27529b5a91 | ||
|
|
58775e1761 | ||
|
|
fa21137553 | ||
|
|
764bd59b0d | ||
|
|
0baedd7efd | ||
|
|
1357d11b70 | ||
|
|
0b9c4db032 | ||
|
|
768eed6426 | ||
|
|
6ef055c5e2 | ||
|
|
253cdb9e91 | ||
|
|
4d6a3a2c69 | ||
|
|
6cef73d435 | ||
|
|
27766d7ec2 | ||
|
|
e8d5ee7866 | ||
|
|
3d38558a0b | ||
|
|
c711378067 | ||
|
|
65129936bc | ||
|
|
a28a0e0df5 | ||
|
|
0094e29415 | ||
|
|
2668fbfa94 | ||
|
|
bafd1b9d0d | ||
|
|
9db6a96f02 | ||
|
|
df1aa78d4f | ||
|
|
5208bb08c3 | ||
|
|
80aca7abf3 | ||
|
|
c0824c4bf1 | ||
|
|
87718d57f1 | ||
|
|
f0d16c369c | ||
|
|
9c2d9215ed | ||
|
|
f8e6d30442 | ||
|
|
566a794e3e | ||
|
|
66bad84a57 | ||
|
|
b69499ba65 | ||
|
|
462b7e08a5 | ||
|
|
59f1252ebb | ||
|
|
d01eeb954d | ||
|
|
ce4b0afcd0 | ||
|
|
315d40b7ad | ||
|
|
82986bdfd6 | ||
|
|
3c0f4ac355 | ||
|
|
667435ca10 | ||
|
|
c76a420ddb | ||
|
|
e526c104c6 | ||
|
|
32c965a8e9 | ||
|
|
55a2ff38f8 | ||
|
|
4b5744b7a0 | ||
|
|
69ff345fec | ||
|
|
bd184aede6 | ||
|
|
784cc2d3ef | ||
|
|
092a8cb848 | ||
|
|
c5a6b1f6fd | ||
|
|
e49941f534 | ||
|
|
f7efbb55de | ||
|
|
0d2b8633cf | ||
|
|
38631ce11f | ||
|
|
7390d24fab | ||
|
|
d417f0f691 | ||
|
|
d69c9e1bca | ||
|
|
d0f0126cd7 | ||
|
|
9255bdccae | ||
|
|
fa532eeb1a | ||
|
|
59987563df | ||
|
|
19029624ef | ||
|
|
4cd25717b4 | ||
|
|
0233b646f4 | ||
|
|
d5591c2b14 | ||
|
|
97a9b59333 | ||
|
|
535fdb5b92 | ||
|
|
d0bd9df277 | ||
|
|
e6db324af6 | ||
|
|
34cd23cc79 | ||
|
|
53ff65ca4b | ||
|
|
40569f843c |
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
clang_format_check:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
# checkout
|
||||
@@ -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.8
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -60,24 +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@v3
|
||||
with:
|
||||
verbose: true
|
||||
fail_ci_if_error: true
|
||||
directory: ./cov_report/
|
||||
files: cov-ut.info
|
||||
|
||||
ft:
|
||||
runs-on: ubuntu-20.04
|
||||
container: ghcr.io/neugates/build:x86_64-main
|
||||
container: ghcr.io/neugates/build:x86_64-v2.8
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -105,24 +90,9 @@ jobs:
|
||||
path: |
|
||||
build/neuron.log
|
||||
|
||||
- name: create cov report
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install lcov
|
||||
mkdir -p cov_report
|
||||
./create_cov_report.sh ft
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
verbose: true
|
||||
fail_ci_if_error: true
|
||||
directory: ./cov_report/
|
||||
files: cov-ft.info
|
||||
|
||||
pft:
|
||||
runs-on: ubuntu-20.04
|
||||
container: ghcr.io/neugates/build:x86_64-main
|
||||
container: ghcr.io/neugates/build:x86_64-v2.8
|
||||
strategy:
|
||||
matrix:
|
||||
plugin: [core, ekuiper, modbus, mqtt, metrics]
|
||||
@@ -164,17 +134,3 @@ jobs:
|
||||
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@v3
|
||||
with:
|
||||
verbose: true
|
||||
directory: ./cov_report/
|
||||
files: cov-${{ matrix.plugin }}.info
|
||||
|
||||
+10
-10
@@ -8,20 +8,20 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.7.0
|
||||
VERSION: 2.8.3
|
||||
UI_VERSION: 2.6.1
|
||||
BRANCH: main
|
||||
BRANCH: v2.8
|
||||
|
||||
jobs:
|
||||
cross-build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
- [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.8
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -52,19 +52,19 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
name: neuron-sdk-${{ matrix.arch[2] }}
|
||||
path: |
|
||||
neuron-sdk-*.tar.gz
|
||||
|
||||
build-debug-sdk:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
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.8
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
path: |
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
|
||||
|
||||
+6
-1
@@ -102,6 +102,11 @@ if (CLIB)
|
||||
add_definitions(-DNEU_CLIB=${CLIB})
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
message(STATUS "build release")
|
||||
add_definitions(-DNEU_RELEASE)
|
||||
endif()
|
||||
|
||||
|
||||
add_library(neuron-base SHARED)
|
||||
target_sources(neuron-base PRIVATE ${NEURON_BASE_SOURCES} ${NEURON_SRC_PARSE})
|
||||
@@ -109,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
|
||||
|
||||
@@ -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.8/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -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.8/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -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.8/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -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.8/libs)
|
||||
|
||||
set(CMAKE_C_COMPILER ${COMPILER_PREFIX}-gcc)
|
||||
set(CMAKE_CXX_COMPILER ${COMPILER_PREFIX}-g++)
|
||||
|
||||
@@ -53,6 +53,20 @@ typedef enum {
|
||||
|
||||
typedef struct neu_mqtt_client_s neu_mqtt_client_t;
|
||||
|
||||
/**
|
||||
* Check that `topic_filter` is a valid MQTT topic filter.
|
||||
*/
|
||||
bool neu_mqtt_topic_filter_is_valid(const char *topic_filter);
|
||||
|
||||
/**
|
||||
* Check the given `topic_filter` matches the given `topic_name`.
|
||||
*
|
||||
* @Precondition `topic_filter` must be a valid MQTT topic filter.
|
||||
* @Precondition `topic_name` must be a valid MQTT topic name.
|
||||
*/
|
||||
bool neu_mqtt_topic_filter_is_match(const char *topic_filter,
|
||||
const char *topic_name);
|
||||
|
||||
typedef void (*neu_mqtt_client_connection_cb_t)(void *data);
|
||||
typedef void (*neu_mqtt_client_publish_cb_t)(int errcode, neu_mqtt_qos_e qos,
|
||||
char *topic, uint8_t *payload,
|
||||
|
||||
@@ -254,6 +254,8 @@ ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len);
|
||||
ssize_t neu_conn_udp_recvfrom(neu_conn_t *conn, uint8_t *buf, ssize_t len,
|
||||
void *src);
|
||||
|
||||
void neu_conn_clear_recv_buffer(neu_conn_t *conn);
|
||||
|
||||
/**
|
||||
* @brief Specify the client to send data.
|
||||
*
|
||||
|
||||
@@ -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 8
|
||||
#define NEU_VERSION_FIX 3
|
||||
|
||||
#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,
|
||||
|
||||
@@ -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,
|
||||
@@ -82,7 +83,6 @@ typedef enum {
|
||||
NEU_ERR_TAG_DESCRIPTION_TOO_LONG = 2208,
|
||||
NEU_ERR_TAG_PRECISION_INVALID = 2209,
|
||||
NEU_ERR_TAG_EXIST = 2210,
|
||||
NEU_ERR_TAG_VALUE_INVALID = 2211,
|
||||
|
||||
NEU_ERR_LIBRARY_NOT_FOUND = 2301,
|
||||
NEU_ERR_LIBRARY_INFO_INVALID = 2302,
|
||||
|
||||
@@ -62,6 +62,31 @@ 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_resp2(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,28 @@ 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+42
-14
@@ -41,16 +41,22 @@ typedef enum {
|
||||
NEU_METRIC_TYPE_GAUAGE,
|
||||
NEU_METRIC_TYPE_COUNTER_SET,
|
||||
NEU_METRIC_TYPE_ROLLING_COUNTER,
|
||||
|
||||
NEU_METRIC_TYPE_FLAG_NO_RESET = 0x80,
|
||||
} neu_metric_type_e;
|
||||
|
||||
#define NEU_METRIC_TYPE_MASK 0x0F
|
||||
|
||||
// node running state
|
||||
#define NEU_METRIC_RUNNING_STATE "running_state"
|
||||
#define NEU_METRIC_RUNNING_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_RUNNING_STATE_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_RUNNING_STATE_HELP "Node running state"
|
||||
|
||||
// node link state
|
||||
#define NEU_METRIC_LINK_STATE "link_state"
|
||||
#define NEU_METRIC_LINK_STATE_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_LINK_STATE_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_LINK_STATE_HELP "Node link state"
|
||||
|
||||
// last round trip time in millisends
|
||||
@@ -86,13 +92,15 @@ typedef enum {
|
||||
// maintained by neuron core
|
||||
// number of tags in group
|
||||
#define NEU_METRIC_TAGS_TOTAL "tags_total"
|
||||
#define NEU_METRIC_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_TAGS_TOTAL_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_TAGS_TOTAL_HELP "Total number of tags in the node"
|
||||
|
||||
// maintained by neuron core
|
||||
// number of tags in group
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL "group_tags_total"
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_TYPE NEU_METRIC_TYPE_GAUAGE
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_TYPE \
|
||||
(NEU_METRIC_TYPE_GAUAGE | NEU_METRIC_TYPE_FLAG_NO_RESET)
|
||||
#define NEU_METRIC_GROUP_TAGS_TOTAL_HELP "Total number of tags in the group"
|
||||
|
||||
// number of messages sent in last group timer
|
||||
@@ -240,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
|
||||
@@ -301,9 +310,24 @@ void neu_metrics_unregister_entry(const char *name);
|
||||
typedef void (*neu_metrics_cb_t)(const neu_metrics_t *metrics, void *data);
|
||||
void neu_metrics_visist(neu_metrics_cb_t cb, void *data);
|
||||
|
||||
static inline bool neu_metric_type_is_counter(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_COUNTER == (type & NEU_METRIC_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline bool neu_metric_type_is_rolling_counter(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_ROLLING_COUNTER == (type & NEU_METRIC_TYPE_MASK);
|
||||
}
|
||||
|
||||
static inline bool neu_metric_type_no_reset(neu_metric_type_e type)
|
||||
{
|
||||
return NEU_METRIC_TYPE_FLAG_NO_RESET & type;
|
||||
}
|
||||
|
||||
static inline const char *neu_metric_type_str(neu_metric_type_e type)
|
||||
{
|
||||
if (NEU_METRIC_TYPE_COUNTER == type) {
|
||||
if (neu_metric_type_is_counter(type)) {
|
||||
return "counter";
|
||||
} else {
|
||||
return "gauge";
|
||||
@@ -316,7 +340,7 @@ int neu_metric_entries_add(neu_metric_entry_t **entries, const char *name,
|
||||
|
||||
static inline void neu_metric_entry_free(neu_metric_entry_t *entry)
|
||||
{
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == entry->type) {
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_free(entry->rcnt);
|
||||
}
|
||||
free(entry);
|
||||
@@ -445,9 +469,9 @@ static inline int neu_node_metrics_update(neu_node_metrics_t *node_metrics,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NEU_METRIC_TYPE_COUNTER == entry->type) {
|
||||
if (neu_metric_type_is_counter(entry->type)) {
|
||||
entry->value += n;
|
||||
} else if (NEU_METRIC_TYPE_ROLLING_COUNTER == entry->type) {
|
||||
} else if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
entry->value =
|
||||
neu_rolling_counter_inc(entry->rcnt, global_timestamp, n);
|
||||
} else {
|
||||
@@ -465,9 +489,11 @@ static inline void neu_node_metrics_reset(neu_node_metrics_t *node_metrics)
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_LOOP(hh, node_metrics->entries, entry)
|
||||
{
|
||||
entry->value = 0;
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == entry->type) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
if (!neu_metric_type_no_reset(entry->type)) {
|
||||
entry->value = entry->init;
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,9 +502,11 @@ static inline void neu_node_metrics_reset(neu_node_metrics_t *node_metrics)
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, entry)
|
||||
{
|
||||
entry->value = 0;
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == entry->type) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
if (!neu_metric_type_no_reset(entry->type)) {
|
||||
entry->value = entry->init;
|
||||
if (neu_metric_type_is_rolling_counter(entry->type)) {
|
||||
neu_rolling_counter_reset(entry->rcnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+216
-13
@@ -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,8 @@ 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_WRITE_TAG,
|
||||
NEU_REQ_WRITE_TAGS,
|
||||
NEU_REQ_WRITE_GTAGS,
|
||||
@@ -119,11 +123,13 @@ typedef enum neu_reqresp_type {
|
||||
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_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",
|
||||
@@ -612,6 +618,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;
|
||||
@@ -694,6 +720,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 +758,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;
|
||||
@@ -841,14 +906,26 @@ 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;
|
||||
@@ -859,6 +936,131 @@ static inline void neu_tag_value_to_json(neu_resp_tag_value_meta_t *tag_value,
|
||||
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.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;
|
||||
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;
|
||||
@@ -904,10 +1106,11 @@ inline static void neu_msg_exchange(neu_reqresp_head_t *header)
|
||||
typedef struct {
|
||||
char driver[NEU_NODE_NAME_LEN];
|
||||
char path[128];
|
||||
int prg_int_param1;
|
||||
int prg_int_param2;
|
||||
bool del_flag;
|
||||
char prg_str_param1[128];
|
||||
char prg_str_param2[128];
|
||||
char prg_str_param3[128];
|
||||
char prg_str_param4[128];
|
||||
} neu_req_prgfile_upload_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -44,6 +44,10 @@ typedef enum {
|
||||
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL 2,1,4,3
|
||||
NEU_DATATAG_ENDIAN_L64 = 6, // #L 8,7,6,5,4,3,2,1
|
||||
NEU_DATATAG_ENDIAN_B64 = 7, // #B 1,2,3,4,5,6,7,8
|
||||
NEU_DATATAG_ENDIAN_LL64 = 8,
|
||||
NEU_DATATAG_ENDIAN_LB64 = 9,
|
||||
NEU_DATATAG_ENDIAN_BB64 = 10,
|
||||
NEU_DATATAG_ENDIAN_BL64 = 11,
|
||||
} neu_datatag_endian_e;
|
||||
|
||||
typedef enum {
|
||||
@@ -59,13 +63,16 @@ typedef union {
|
||||
} value16;
|
||||
struct {
|
||||
neu_datatag_endian_e endian;
|
||||
bool is_default;
|
||||
} value32;
|
||||
struct {
|
||||
neu_datatag_endian_e endian;
|
||||
bool is_default;
|
||||
} value64;
|
||||
struct {
|
||||
uint16_t length;
|
||||
neu_datatag_string_type_e type;
|
||||
bool is_default;
|
||||
} string;
|
||||
|
||||
struct {
|
||||
|
||||
+65
-21
@@ -31,25 +31,27 @@ extern "C" {
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
NEU_TYPE_INT8 = 1,
|
||||
NEU_TYPE_UINT8 = 2,
|
||||
NEU_TYPE_INT16 = 3,
|
||||
NEU_TYPE_UINT16 = 4,
|
||||
NEU_TYPE_INT32 = 5,
|
||||
NEU_TYPE_UINT32 = 6,
|
||||
NEU_TYPE_INT64 = 7,
|
||||
NEU_TYPE_UINT64 = 8,
|
||||
NEU_TYPE_FLOAT = 9,
|
||||
NEU_TYPE_DOUBLE = 10,
|
||||
NEU_TYPE_BIT = 11,
|
||||
NEU_TYPE_BOOL = 12,
|
||||
NEU_TYPE_STRING = 13,
|
||||
NEU_TYPE_BYTES = 14,
|
||||
NEU_TYPE_ERROR = 15,
|
||||
NEU_TYPE_WORD = 16,
|
||||
NEU_TYPE_DWORD = 17,
|
||||
NEU_TYPE_LWORD = 18,
|
||||
NEU_TYPE_PTR = 19,
|
||||
NEU_TYPE_INT8 = 1,
|
||||
NEU_TYPE_UINT8 = 2,
|
||||
NEU_TYPE_INT16 = 3,
|
||||
NEU_TYPE_UINT16 = 4,
|
||||
NEU_TYPE_INT32 = 5,
|
||||
NEU_TYPE_UINT32 = 6,
|
||||
NEU_TYPE_INT64 = 7,
|
||||
NEU_TYPE_UINT64 = 8,
|
||||
NEU_TYPE_FLOAT = 9,
|
||||
NEU_TYPE_DOUBLE = 10,
|
||||
NEU_TYPE_BIT = 11,
|
||||
NEU_TYPE_BOOL = 12,
|
||||
NEU_TYPE_STRING = 13,
|
||||
NEU_TYPE_BYTES = 14,
|
||||
NEU_TYPE_ERROR = 15,
|
||||
NEU_TYPE_WORD = 16,
|
||||
NEU_TYPE_DWORD = 17,
|
||||
NEU_TYPE_LWORD = 18,
|
||||
NEU_TYPE_PTR = 19,
|
||||
NEU_TYPE_TIME = 20,
|
||||
NEU_TYPE_DATA_AND_TIME = 21,
|
||||
} neu_type_e;
|
||||
|
||||
inline static const char *neu_type_string(neu_type_e type)
|
||||
@@ -93,6 +95,10 @@ inline static const char *neu_type_string(neu_type_e type)
|
||||
return "NEU_TYPE_LWORD";
|
||||
case NEU_TYPE_PTR:
|
||||
return "NEU_TYPE_PTR";
|
||||
case NEU_TYPE_TIME:
|
||||
return "NEU_TYPE_TIME";
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
return "NEU_TYPE_DATA_AND_TIME";
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -130,7 +136,7 @@ typedef union {
|
||||
|
||||
static inline char *neu_value_str(neu_type_e type, neu_value_u value)
|
||||
{
|
||||
static __thread char str[32] = { 0 };
|
||||
static __thread char str[128] = { 0 };
|
||||
|
||||
switch (type) {
|
||||
case NEU_TYPE_INT8:
|
||||
@@ -188,7 +194,9 @@ static inline char *neu_value_str(neu_type_e type, neu_value_u value)
|
||||
snprintf(str, sizeof(str), "type: %s, value: %u", neu_type_string(type),
|
||||
value.boolean);
|
||||
break;
|
||||
case NEU_TYPE_STRING: {
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME: {
|
||||
snprintf(str, sizeof(str), "type: %s, value: %c%c%c",
|
||||
neu_type_string(type), value.str[0], value.str[1],
|
||||
value.str[2]);
|
||||
@@ -498,6 +506,42 @@ static inline uint64_t neu_htonll(uint64_t u)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonlb(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[1];
|
||||
out_bytes[1] = in[0];
|
||||
out_bytes[2] = in[3];
|
||||
out_bytes[3] = in[2];
|
||||
out_bytes[4] = in[5];
|
||||
out_bytes[5] = in[4];
|
||||
out_bytes[6] = in[7];
|
||||
out_bytes[7] = in[6];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonbl(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[6];
|
||||
out_bytes[1] = in[7];
|
||||
out_bytes[2] = in[4];
|
||||
out_bytes[3] = in[5];
|
||||
out_bytes[4] = in[2];
|
||||
out_bytes[5] = in[3];
|
||||
out_bytes[6] = in[0];
|
||||
out_bytes[7] = in[1];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_ntohll(uint64_t u)
|
||||
{
|
||||
return neu_htonll(u);
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -3,5 +3,6 @@
|
||||
"port": 7000,
|
||||
"disable_auth": 0,
|
||||
"syslog_host": "",
|
||||
"syslog_port": 541
|
||||
"syslog_port": 541,
|
||||
"sub_filter_error": 0
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* NEURON IIoT System for Industry 4.0
|
||||
* Copyright (C) 2020-2024 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.
|
||||
**/
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
ALTER TABLE tags RENAME TO temp_tags;
|
||||
|
||||
CREATE TABLE
|
||||
IF NOT EXISTS tags (
|
||||
driver_name TEXT NOT NULL,
|
||||
group_name TEXT NOT NULL,
|
||||
name TEXT NULL check (length (name) <= 128),
|
||||
address TEXT NULL check (length (address) <= 128),
|
||||
attribute INTEGER NOT NULL check (attribute BETWEEN 0 AND 15),
|
||||
precision INTEGER NOT NULL check (precision BETWEEN 0 AND 17),
|
||||
decimal REAL NOT NULL,
|
||||
type INTEGER NOT NULL check (type BETWEEN 0 AND 21),
|
||||
description TEXT NULL check (length (description) <= 512),
|
||||
value TEXT,
|
||||
UNIQUE (driver_name, group_name, name),
|
||||
FOREIGN KEY (driver_name, group_name) REFERENCES groups (driver_name, name) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
);
|
||||
|
||||
INSERT INTO tags SELECT * FROM temp_tags;
|
||||
|
||||
DROP TABLE temp_tags;
|
||||
|
||||
COMMIT;
|
||||
@@ -162,7 +162,16 @@ static inline int start(neu_plugin_t *plugin, const char *url)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
while (plugin->receiving) {
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
nng_msleep(10);
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
}
|
||||
plugin->receiving = true;
|
||||
nng_recv_aio(plugin->sock, plugin->recv_aio);
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -313,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");
|
||||
@@ -333,6 +346,8 @@ static int ekuiper_plugin_request(neu_plugin_t * plugin,
|
||||
case NEU_REQ_UPDATE_GROUP: {
|
||||
break;
|
||||
}
|
||||
case NEU_REQ_DEL_GROUP:
|
||||
break;
|
||||
case NEU_REQ_SUBSCRIBE_GROUP:
|
||||
case NEU_REQ_UPDATE_SUBSCRIBE_GROUP: {
|
||||
neu_req_subscribe_t *sub_info = data;
|
||||
|
||||
@@ -37,6 +37,7 @@ struct neu_plugin {
|
||||
nng_socket sock;
|
||||
nng_mtx * mtx;
|
||||
bool started;
|
||||
bool receiving;
|
||||
nng_aio * recv_aio;
|
||||
char * host;
|
||||
uint16_t port;
|
||||
|
||||
@@ -83,6 +83,9 @@ void recv_data_callback(void *arg)
|
||||
rv = nng_aio_result(plugin->recv_aio);
|
||||
if (0 != rv) {
|
||||
plog_error(plugin, "nng_recv error: %s", nng_strerror(rv));
|
||||
nng_mtx_lock(plugin->mtx);
|
||||
plugin->receiving = false;
|
||||
nng_mtx_unlock(plugin->mtx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -106,6 +106,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -93,6 +93,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -66,6 +66,13 @@ typedef enum modbus_area {
|
||||
MODBUS_AREA_HOLD_REGISTER = 4,
|
||||
} modbus_area_e;
|
||||
|
||||
typedef enum modbus_endianess_64 {
|
||||
MODBUS_LL = 1, // 12 34 56 78
|
||||
MODBUS_LB = 2, // 21 43 65 87
|
||||
MODBUS_BB = 3, // 87 65 43 21
|
||||
MODBUS_BL = 4, // 78 56 34 12
|
||||
} modbus_endianess_64;
|
||||
|
||||
struct modbus_header {
|
||||
uint16_t seq;
|
||||
uint16_t protocol;
|
||||
|
||||
@@ -221,7 +221,8 @@ modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
|
||||
return sort_result;
|
||||
}
|
||||
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option,
|
||||
modbus_endianess_64 endianess_64, bool default_tag_endian_64)
|
||||
{
|
||||
int n = 0;
|
||||
switch (type) {
|
||||
@@ -240,6 +241,9 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (default_tag_endian_64) {
|
||||
modbus_convert_endianess_64(value, endianess_64);
|
||||
}
|
||||
n = sizeof(uint64_t);
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
@@ -273,7 +277,8 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
return n;
|
||||
}
|
||||
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64)
|
||||
{
|
||||
neu_tag_sort_result_t *result =
|
||||
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
|
||||
@@ -295,14 +300,17 @@ modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
utarray_foreach(result->sorts[i].tags, modbus_point_write_t **, tag_s)
|
||||
{
|
||||
if ((*tag_s)->point.area == MODBUS_AREA_COIL) {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64, true);
|
||||
data_bit[k / 8] += ((*tag_s)->value.i8) << k % 8;
|
||||
n_byte += n_byte_tag;
|
||||
k++;
|
||||
} else {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64,
|
||||
(*tag_s)->point.option.value64.is_default);
|
||||
memcpy(sort_result->cmd[i].bytes +
|
||||
2 *
|
||||
((*tag_s)->point.start_address -
|
||||
@@ -512,4 +520,24 @@ static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64)
|
||||
{
|
||||
switch (endianess_64) {
|
||||
case MODBUS_LL:
|
||||
break;
|
||||
case MODBUS_BB:
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
case MODBUS_LB:
|
||||
value->u64 = neu_htonlb(value->u64);
|
||||
break;
|
||||
case MODBUS_BL:
|
||||
value->u64 = neu_htonbl(value->u64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -79,9 +79,13 @@ typedef struct modbus_write_cmd_sort {
|
||||
modbus_write_cmd_t *cmd;
|
||||
} modbus_write_cmd_sort_t;
|
||||
|
||||
modbus_read_cmd_sort_t * modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes)
|
||||
neu_plugin_t *plugin = (neu_plugin_t *) ctx;
|
||||
int ret = 0;
|
||||
|
||||
neu_conn_clear_recv_buffer(plugin->conn);
|
||||
|
||||
plog_send_protocol(plugin, bytes, n_byte);
|
||||
|
||||
if (plugin->is_server) {
|
||||
@@ -203,6 +205,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 +217,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 +247,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 +256,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 +278,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 +289,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(
|
||||
@@ -403,6 +411,10 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if ((*p_tag)->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&dvalue.value,
|
||||
plugin->endianess_64);
|
||||
}
|
||||
dvalue.value.u64 = neu_ntohll(dvalue.value.u64);
|
||||
break;
|
||||
case NEU_TYPE_BIT: {
|
||||
@@ -477,6 +489,9 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (tag->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&value, plugin->endianess_64);
|
||||
}
|
||||
value.u64 = neu_htonll(value.u64);
|
||||
n_byte = sizeof(uint64_t);
|
||||
break;
|
||||
@@ -544,7 +559,7 @@ int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
|
||||
|
||||
utarray_push_back(gtags->tags, &p);
|
||||
}
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags);
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags, plugin->endianess_64);
|
||||
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
|
||||
uint16_t response_size = 0;
|
||||
|
||||
@@ -699,7 +714,7 @@ static int process_protocol_buf(neu_plugin_t *plugin, uint8_t slave_id,
|
||||
plog_recv_protocol(plugin, recv_buf, ret);
|
||||
}
|
||||
neu_protocol_unpack_buf_init(&pbuf, recv_buf, ret);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, 0, &pbuf);
|
||||
int ret_s = modbus_stack_recv(plugin->stack, slave_id, &pbuf);
|
||||
if (ret_s == MODBUS_DEVICE_ERR) {
|
||||
ret = ret_s;
|
||||
} else {
|
||||
|
||||
@@ -43,6 +43,8 @@ struct neu_plugin {
|
||||
uint16_t interval;
|
||||
uint16_t retry_interval;
|
||||
uint16_t max_retries;
|
||||
|
||||
modbus_endianess_64 endianess_64;
|
||||
};
|
||||
|
||||
void modbus_conn_connected(void *data, int fd);
|
||||
|
||||
@@ -167,6 +167,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
neu_json_elem_t retry_interval = { .name = "retry_interval",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
neu_json_elem_t endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout,
|
||||
&interval);
|
||||
if (ret != 0) {
|
||||
@@ -206,9 +209,16 @@ 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, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
plugin->max_retries = max_retries.v.val_int;
|
||||
plugin->retry_interval = retry_interval.v.val_int;
|
||||
plugin->endianess_64 = endianess_64.v.val_int;
|
||||
|
||||
if (link.v.val_int == 0) {
|
||||
param.type = NEU_CONN_TTY_CLIENT;
|
||||
|
||||
@@ -84,10 +84,8 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP) {
|
||||
if (code.slave_id != slave_id) {
|
||||
return -1;
|
||||
}
|
||||
if (code.slave_id != slave_id) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (code.function) {
|
||||
@@ -102,18 +100,36 @@ int modbus_stack_recv(modbus_stack_t *stack, uint8_t slave_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stack->protocol == MODBUS_PROTOCOL_TCP && data.n_byte == 0xff) {
|
||||
bytes = neu_protocol_unpack_buf(buf,
|
||||
header.len -
|
||||
sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data));
|
||||
stack->value_fn(stack->ctx, code.slave_id,
|
||||
header.len - sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data),
|
||||
bytes, 0);
|
||||
} else {
|
||||
switch (stack->protocol) {
|
||||
case MODBUS_PROTOCOL_TCP:
|
||||
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;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id,
|
||||
header.len - sizeof(struct modbus_code) -
|
||||
sizeof(struct modbus_data),
|
||||
bytes, 0);
|
||||
} else {
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes,
|
||||
0);
|
||||
}
|
||||
break;
|
||||
case MODBUS_PROTOCOL_RTU:
|
||||
bytes = neu_protocol_unpack_buf(buf, data.n_byte);
|
||||
if (bytes == NULL) {
|
||||
return -1;
|
||||
}
|
||||
stack->value_fn(stack->ctx, code.slave_id, data.n_byte, bytes, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -158,6 +158,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 endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
|
||||
&timeout, &interval);
|
||||
@@ -186,10 +188,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, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
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->endianess_64 = endianess_64.v.val_int;
|
||||
|
||||
if (mode.v.val_int == 1) {
|
||||
param.type = NEU_CONN_TCP_SERVER;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
"description_zh": "MQTT 客户端 ID",
|
||||
"type": "string",
|
||||
"attribute": "required",
|
||||
"default": "neuron_${random_str}",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
@@ -64,7 +63,6 @@
|
||||
"description_zh": "接收点位写入请求的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${node-name}/write/req",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
@@ -76,7 +74,6 @@
|
||||
"description_zh": "发送点位写入响应的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${node-name}/write/resp",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ static char *generate_upload_json(neu_plugin_t * plugin,
|
||||
neu_json_encode_read_periodic_resp,
|
||||
&json_str);
|
||||
} else if (MQTT_UPLOAD_FORMAT_TAGS == format) { // tags
|
||||
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp, &header,
|
||||
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp2, &header,
|
||||
neu_json_encode_read_periodic_resp,
|
||||
&json_str);
|
||||
} else {
|
||||
@@ -606,6 +606,14 @@ int handle_unsubscribe_group(neu_plugin_t * plugin,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_del_group(neu_plugin_t *plugin, neu_req_del_group_t *req)
|
||||
{
|
||||
route_tbl_del(&plugin->route_tbl, req->driver, req->group);
|
||||
plog_notice(plugin, "del route driver:%s group:%s", req->driver,
|
||||
req->group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handle_update_group(neu_plugin_t *plugin, neu_req_update_group_t *req)
|
||||
{
|
||||
route_tbl_update_group(&plugin->route_tbl, req->driver, req->group,
|
||||
|
||||
@@ -49,6 +49,7 @@ int handle_unsubscribe_group(neu_plugin_t * plugin,
|
||||
neu_req_unsubscribe_t *unsub_info);
|
||||
|
||||
int handle_update_group(neu_plugin_t *plugin, neu_req_update_group_t *req);
|
||||
int handle_del_group(neu_plugin_t *plugin, neu_req_del_group_t *cmd);
|
||||
|
||||
int handle_update_driver(neu_plugin_t *plugin, neu_req_update_node_t *req);
|
||||
int handle_del_driver(neu_plugin_t *plugin, neu_reqresp_node_deleted_t *req);
|
||||
|
||||
@@ -366,9 +366,13 @@ static 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;
|
||||
}
|
||||
@@ -384,6 +388,9 @@ static int mqtt_plugin_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
case NEU_REQ_UPDATE_GROUP:
|
||||
error = handle_update_group(plugin, data);
|
||||
break;
|
||||
case NEU_REQ_DEL_GROUP:
|
||||
error = handle_del_group(plugin, data);
|
||||
break;
|
||||
case NEU_REQ_UPDATE_NODE:
|
||||
error = handle_update_driver(plugin, data);
|
||||
break;
|
||||
|
||||
@@ -72,6 +72,9 @@ static struct neu_http_handler cors_handler[] = {
|
||||
{
|
||||
.url = "/api/v2/read",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/read/paginate",
|
||||
},
|
||||
{
|
||||
.url = "/api/v2/write",
|
||||
},
|
||||
@@ -259,6 +262,12 @@ 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,
|
||||
@@ -379,6 +388,12 @@ static struct neu_http_handler rest_handlers[] = {
|
||||
.url = "/api/v2/metrics",
|
||||
.value.handler = handle_get_metric,
|
||||
},
|
||||
{
|
||||
.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)
|
||||
|
||||
@@ -181,7 +181,7 @@ static inline void gen_single_node_metrics(neu_node_metrics_t *node_metrics,
|
||||
pthread_mutex_lock(&node_metrics->lock);
|
||||
HASH_LOOP(hh, node_metrics->entries, e)
|
||||
{
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == e->type) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value = neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
}
|
||||
@@ -196,7 +196,7 @@ static inline void gen_single_node_metrics(neu_node_metrics_t *node_metrics,
|
||||
{
|
||||
HASH_LOOP(hh, g->entries, e)
|
||||
{
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == e->type) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value =
|
||||
neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
@@ -278,7 +278,7 @@ static void gen_all_node_metrics(neu_metrics_t *metrics, int type_filter,
|
||||
pthread_mutex_lock(&n->lock);
|
||||
HASH_FIND_STR(n->entries, r->name, e);
|
||||
if (e) {
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == e->type) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value =
|
||||
neu_rolling_counter_inc(e->rcnt, global_timestamp, 0);
|
||||
@@ -294,7 +294,7 @@ static void gen_all_node_metrics(neu_metrics_t *metrics, int type_filter,
|
||||
{
|
||||
HASH_FIND_STR(g->entries, r->name, e);
|
||||
if (e) {
|
||||
if (NEU_METRIC_TYPE_ROLLING_COUNTER == e->type) {
|
||||
if (neu_metric_type_is_rolling_counter(e->type)) {
|
||||
// force clean stale value
|
||||
e->value = neu_rolling_counter_inc(e->rcnt,
|
||||
global_timestamp, 0);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -40,7 +40,7 @@ void handle_add_plugin(nng_aio *aio)
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_ADD_PLUGIN;
|
||||
strcpy(cmd.library, req->library);
|
||||
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
|
||||
cmd.schema_file = req->schema_file;
|
||||
cmd.so_file = req->so_file;
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
@@ -64,7 +64,7 @@ void handle_update_plugin(nng_aio *aio)
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_UPDATE_PLUGIN;
|
||||
strcpy(cmd.library, req->library);
|
||||
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
|
||||
cmd.schema_file = req->schema_file;
|
||||
cmd.so_file = req->so_file;
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
|
||||
@@ -223,6 +223,10 @@ 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;
|
||||
default:
|
||||
nlog_fatal("recv unhandle msg: %s",
|
||||
neu_reqresp_type_string(header->type));
|
||||
|
||||
@@ -80,6 +80,61 @@ 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_write(nng_aio *aio)
|
||||
{
|
||||
neu_plugin_t *plugin = neu_rest_get_plugin();
|
||||
@@ -384,3 +439,143 @@ 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);
|
||||
}
|
||||
@@ -27,9 +27,12 @@
|
||||
void handle_rw_init();
|
||||
void handle_rw_uninit();
|
||||
void handle_read(nng_aio *aio);
|
||||
void handle_read_paginate(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);
|
||||
|
||||
#endif
|
||||
+104
-32
@@ -152,18 +152,38 @@ neu_adapter_t *neu_adapter_create(neu_adapter_info_t *info, bool load)
|
||||
break;
|
||||
}
|
||||
|
||||
adapter->control_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||
adapter->control_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (adapter->control_fd <= 0) {
|
||||
free(adapter);
|
||||
return NULL;
|
||||
}
|
||||
adapter->trans_data_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||
|
||||
adapter->trans_data_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (adapter->trans_data_fd <= 0) {
|
||||
close(adapter->control_fd);
|
||||
free(adapter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct timeval sock_timeout = {
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
if (setsockopt(adapter->control_fd, SOL_SOCKET, SO_SNDTIMEO, &sock_timeout,
|
||||
sizeof(sock_timeout)) < 0 ||
|
||||
setsockopt(adapter->control_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_timeout,
|
||||
sizeof(sock_timeout)) < 0 ||
|
||||
setsockopt(adapter->trans_data_fd, SOL_SOCKET, SO_SNDTIMEO,
|
||||
&sock_timeout, sizeof(sock_timeout)) < 0 ||
|
||||
setsockopt(adapter->trans_data_fd, SOL_SOCKET, SO_RCVTIMEO,
|
||||
&sock_timeout, sizeof(sock_timeout)) < 0) {
|
||||
nlog_error("fail to set sock timeout for adapter:%s", info->name);
|
||||
close(adapter->trans_data_fd);
|
||||
close(adapter->control_fd);
|
||||
free(adapter);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
adapter->name = strdup(info->name);
|
||||
adapter->events = neu_event_new();
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_INIT;
|
||||
@@ -406,13 +426,6 @@ static int adapter_update_metric(neu_adapter_t *adapter,
|
||||
return neu_node_metrics_update(adapter->metrics, group, metric_name, n);
|
||||
}
|
||||
|
||||
static inline void adapter_reset_metrics(neu_adapter_t *adapter)
|
||||
{
|
||||
if (NULL != adapter->metrics) {
|
||||
neu_node_metrics_reset(adapter->metrics);
|
||||
}
|
||||
}
|
||||
|
||||
static int adapter_command(neu_adapter_t *adapter, neu_reqresp_head_t header,
|
||||
void *data)
|
||||
{
|
||||
@@ -431,6 +444,12 @@ 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_WRITE_TAG: {
|
||||
neu_req_write_tag_t *cmd = (neu_req_write_tag_t *) data;
|
||||
strcpy(pheader->receiver, cmd->driver);
|
||||
@@ -714,6 +733,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 };
|
||||
|
||||
@@ -763,7 +806,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);
|
||||
@@ -856,7 +899,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 {
|
||||
@@ -881,7 +925,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,
|
||||
@@ -906,12 +951,15 @@ 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);
|
||||
} else {
|
||||
error.error = NEU_ERR_GROUP_NOT_ALLOW;
|
||||
adapter->module->intf_funs->request(
|
||||
adapter->plugin, (neu_reqresp_head_t *) header, &header[1]);
|
||||
neu_msg_free(msg);
|
||||
break;
|
||||
}
|
||||
|
||||
if (error.error == NEU_ERR_SUCCESS) {
|
||||
@@ -959,6 +1007,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) {
|
||||
@@ -1048,12 +1098,6 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
|
||||
if (adapter->module->type != NEU_NA_TYPE_DRIVER) {
|
||||
resp.error = NEU_ERR_GROUP_NOT_ALLOW;
|
||||
} else if (neu_adapter_driver_new_group_count(
|
||||
(neu_adapter_driver_t *) adapter, cmd) +
|
||||
neu_adapter_driver_group_count(
|
||||
(neu_adapter_driver_t *) adapter) >
|
||||
NEU_GROUP_MAX_PER_NODE) {
|
||||
resp.error = NEU_ERR_GROUP_MAX_GROUPS;
|
||||
} else {
|
||||
if (neu_adapter_validate_gtags(adapter, cmd, &resp) == 0 &&
|
||||
neu_adapter_try_add_gtags(adapter, cmd, &resp) == 0 &&
|
||||
@@ -1184,22 +1228,30 @@ static int adapter_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
int neu_adapter_validate_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd,
|
||||
neu_resp_add_tag_t *resp)
|
||||
{
|
||||
neu_adapter_driver_t *driver_adapter = (neu_adapter_driver_t *) adapter;
|
||||
if (neu_adapter_driver_new_group_count(driver_adapter, cmd) +
|
||||
neu_adapter_driver_group_count(driver_adapter) >
|
||||
NEU_GROUP_MAX_PER_NODE) {
|
||||
resp->error = NEU_ERR_GROUP_MAX_GROUPS;
|
||||
resp->index = 0;
|
||||
return NEU_ERR_GROUP_MAX_GROUPS;
|
||||
}
|
||||
|
||||
for (int group_index = 0; group_index < cmd->n_group; group_index++) {
|
||||
for (int tag_index = 0; tag_index < cmd->groups[group_index].n_tag;
|
||||
tag_index++) {
|
||||
neu_gdatatag_t *current_group = &cmd->groups[group_index];
|
||||
for (int tag_index = 0; tag_index < current_group->n_tag; tag_index++) {
|
||||
int validation_result = neu_adapter_driver_validate_tag(
|
||||
(neu_adapter_driver_t *) adapter,
|
||||
cmd->groups[group_index].group,
|
||||
&cmd->groups[group_index].tags[tag_index]);
|
||||
if (validation_result == 0) {
|
||||
resp->index += 1;
|
||||
} else {
|
||||
driver_adapter, current_group->group,
|
||||
¤t_group->tags[tag_index]);
|
||||
if (validation_result != 0) {
|
||||
resp->error = validation_result;
|
||||
resp->index = 0;
|
||||
return validation_result;
|
||||
}
|
||||
resp->index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1233,6 +1285,8 @@ int neu_adapter_add_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd,
|
||||
neu_adapter_driver_add_group((neu_adapter_driver_t *) adapter,
|
||||
cmd->groups[group_index].group,
|
||||
cmd->groups[group_index].interval);
|
||||
adapter_storage_add_group(adapter->name, cmd->groups[group_index].group,
|
||||
cmd->groups[group_index].interval);
|
||||
for (int tag_index = 0; tag_index < cmd->groups[group_index].n_tag;
|
||||
tag_index++) {
|
||||
int add_tag_result = neu_adapter_driver_add_tag(
|
||||
@@ -1262,12 +1316,17 @@ int neu_adapter_add_gtags(neu_adapter_t *adapter, neu_req_add_gtag_t *cmd,
|
||||
cmd->groups[group_index].group,
|
||||
cmd->groups[group_index].tags[added_tag_index].name);
|
||||
}
|
||||
for (int groups_count = 0; groups_count < cmd->n_group;
|
||||
groups_count++) {
|
||||
|
||||
neu_adapter_driver_try_del_tag((neu_adapter_driver_t *) adapter,
|
||||
cmd->groups[group_index].n_tag -
|
||||
tag_index);
|
||||
|
||||
for (++group_index; group_index < cmd->n_group; group_index++) {
|
||||
neu_adapter_driver_try_del_tag(
|
||||
(neu_adapter_driver_t *) adapter,
|
||||
cmd->groups[groups_count].n_tag);
|
||||
cmd->groups[group_index].n_tag);
|
||||
}
|
||||
|
||||
resp->index = 0;
|
||||
resp->error = add_tag_result;
|
||||
return add_tag_result;
|
||||
@@ -1312,6 +1371,11 @@ void neu_adapter_destroy(neu_adapter_t *adapter)
|
||||
}
|
||||
|
||||
neu_event_close(adapter->events);
|
||||
#ifdef NEU_RELEASE
|
||||
if (adapter->handle != NULL) {
|
||||
dlclose(adapter->handle);
|
||||
}
|
||||
#endif
|
||||
free(adapter);
|
||||
}
|
||||
|
||||
@@ -1357,6 +1421,10 @@ int neu_adapter_start(neu_adapter_t *adapter)
|
||||
if (error == NEU_ERR_SUCCESS) {
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_RUNNING;
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
if (NEU_NA_TYPE_DRIVER == neu_adapter_get_type(adapter)) {
|
||||
neu_adapter_driver_start_group_timer(
|
||||
(neu_adapter_driver_t *) adapter);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -1395,7 +1463,11 @@ int neu_adapter_stop(neu_adapter_t *adapter)
|
||||
if (error == NEU_ERR_SUCCESS) {
|
||||
adapter->state = NEU_NODE_RUNNING_STATE_STOPPED;
|
||||
adapter_storage_state(adapter->name, adapter->state);
|
||||
adapter_reset_metrics(adapter);
|
||||
if (NEU_NA_TYPE_DRIVER == neu_adapter_get_type(adapter)) {
|
||||
neu_adapter_driver_stop_group_timer(
|
||||
(neu_adapter_driver_t *) adapter);
|
||||
}
|
||||
neu_adapter_reset_metrics(adapter);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
||||
@@ -96,6 +96,13 @@ int neu_adapter_set_setting(neu_adapter_t *adapter, const char *config);
|
||||
int neu_adapter_get_setting(neu_adapter_t *adapter, char **config);
|
||||
neu_node_state_t neu_adapter_get_state(neu_adapter_t *adapter);
|
||||
|
||||
static inline void neu_adapter_reset_metrics(neu_adapter_t *adapter)
|
||||
{
|
||||
if (NULL != adapter->metrics) {
|
||||
neu_node_metrics_reset(adapter->metrics);
|
||||
}
|
||||
}
|
||||
|
||||
int neu_adapter_register_group_metric(neu_adapter_t *adapter,
|
||||
const char *group_name, const char *name,
|
||||
const char *help, neu_metric_type_e type,
|
||||
|
||||
+101
-1
@@ -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:
|
||||
@@ -157,6 +243,8 @@ void neu_driver_cache_update_change(neu_driver_cache_t *cache,
|
||||
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:
|
||||
@@ -216,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;
|
||||
}
|
||||
@@ -299,6 +395,8 @@ int neu_driver_cache_meta_get(neu_driver_cache_t *cache, const char *group,
|
||||
value->value.value.boolean = elem->value.value.boolean;
|
||||
break;
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
memcpy(value->value.value.str, elem->value.value.str,
|
||||
sizeof(elem->value.value.str));
|
||||
break;
|
||||
@@ -381,6 +479,8 @@ int neu_driver_cache_meta_get_changed(neu_driver_cache_t *cache,
|
||||
value->value.value.boolean = elem->value.value.boolean;
|
||||
break;
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
memcpy(value->value.value.str, elem->value.value.str,
|
||||
sizeof(elem->value.value.str));
|
||||
break;
|
||||
|
||||
+479
-142
@@ -89,6 +89,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,
|
||||
@@ -102,8 +106,48 @@ static void update_with_meta(neu_adapter_t *adapter, const char *group,
|
||||
const char *tag, neu_dvalue_t value,
|
||||
neu_tag_meta_t *metas, int n_meta);
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error);
|
||||
static group_t *find_group(neu_adapter_driver_t *driver, const char *name);
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag);
|
||||
static group_t * find_group(neu_adapter_driver_t *driver, const char *name);
|
||||
static void store_write_tag(group_t *group, to_be_write_tag_t *tag);
|
||||
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);
|
||||
|
||||
int negative = 1;
|
||||
|
||||
if (value->value.d64 < 0) {
|
||||
value->value.d64 *= -1;
|
||||
negative = -1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
value->value.d64 *= negative;
|
||||
}
|
||||
|
||||
static void write_response(neu_adapter_t *adapter, void *r, neu_error error)
|
||||
{
|
||||
@@ -168,7 +212,7 @@ static void update_with_meta(neu_adapter_t *adapter, const char *group,
|
||||
update_metric(&driver->adapter, NEU_METRIC_TAG_READ_ERRORS_TOTAL,
|
||||
NEU_TYPE_ERROR == value.type, NULL);
|
||||
}
|
||||
nlog_info(
|
||||
nlog_debug(
|
||||
"update driver: %s, group: %s, tag: %s, type: %s, timestamp: %" PRId64
|
||||
" n_meta: %d",
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
@@ -181,14 +225,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;
|
||||
}
|
||||
|
||||
@@ -196,24 +234,31 @@ 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);
|
||||
neu_datatag_t *first = utarray_front(tags);
|
||||
|
||||
if (first == NULL ||
|
||||
!neu_tag_attribute_test(first, NEU_ATTRIBUTE_SUBSCRIBE)) {
|
||||
utarray_free(tags);
|
||||
nlog_info("update immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
if (value.type == NEU_TYPE_ERROR) {
|
||||
return;
|
||||
}
|
||||
|
||||
nlog_info("update and report immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
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) {
|
||||
utarray_free(tags);
|
||||
nlog_debug("update immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag,
|
||||
neu_type_string(value.type), global_timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
nlog_debug("update and report immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
"timestamp: %" PRId64,
|
||||
driver->adapter.name, group, tag, neu_type_string(value.type),
|
||||
global_timestamp);
|
||||
|
||||
neu_reqresp_head_t header = {
|
||||
.type = NEU_REQRESP_TRANS_DATA,
|
||||
@@ -324,9 +369,7 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
HASH_DEL(driver->groups, el);
|
||||
|
||||
neu_adapter_driver_try_del_tag(driver, neu_group_tag_size(el->group));
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, el->report);
|
||||
neu_event_del_timer(driver->driver_events, el->read);
|
||||
neu_event_del_timer(driver->driver_events, el->write);
|
||||
stop_group_timer(driver, el);
|
||||
if (el->grp.group_free != NULL) {
|
||||
el->grp.group_free(&el->grp);
|
||||
}
|
||||
@@ -349,34 +392,67 @@ int neu_adapter_driver_uninit(neu_adapter_driver_t *driver)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void start_group_timer(neu_adapter_driver_t *driver, group_t *grp)
|
||||
{
|
||||
uint32_t interval = neu_group_get_interval(grp->group);
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) grp,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
grp->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
grp->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
|
||||
param.second = 0;
|
||||
param.millisecond = 3;
|
||||
param.cb = write_callback;
|
||||
grp->write = neu_event_add_timer(driver->driver_events, param);
|
||||
}
|
||||
|
||||
void neu_adapter_driver_start_group_timer(neu_adapter_driver_t *driver)
|
||||
{
|
||||
group_t *el = NULL, *tmp = NULL;
|
||||
|
||||
HASH_ITER(hh, driver->groups, el, tmp)
|
||||
{
|
||||
uint32_t interval = neu_group_get_interval(el->group);
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = el,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
start_group_timer(driver, el);
|
||||
neu_adapter_update_group_metric(
|
||||
&driver->adapter, neu_group_get_name(el->group),
|
||||
NEU_METRIC_GROUP_TAGS_TOTAL, neu_group_tag_size(el->group));
|
||||
}
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
el->read = neu_event_add_timer(driver->driver_events, param);
|
||||
driver->adapter.cb_funs.update_metric(
|
||||
&driver->adapter, NEU_METRIC_TAGS_TOTAL, driver->tag_cnt, NULL);
|
||||
}
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
el->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
static inline void stop_group_timer(neu_adapter_driver_t *driver, group_t *grp)
|
||||
{
|
||||
if (grp->report) {
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, grp->report);
|
||||
grp->report = NULL;
|
||||
}
|
||||
if (grp->read) {
|
||||
neu_event_del_timer(driver->driver_events, grp->read);
|
||||
grp->read = NULL;
|
||||
}
|
||||
if (grp->write) {
|
||||
neu_event_del_timer(driver->driver_events, grp->write);
|
||||
grp->write = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,13 +460,7 @@ void neu_adapter_driver_stop_group_timer(neu_adapter_driver_t *driver)
|
||||
{
|
||||
group_t *el = NULL, *tmp = NULL;
|
||||
|
||||
HASH_ITER(hh, driver->groups, el, tmp)
|
||||
{
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, el->report);
|
||||
el->report = NULL;
|
||||
neu_event_del_timer(driver->driver_events, el->read);
|
||||
el->read = NULL;
|
||||
}
|
||||
HASH_ITER(hh, driver->groups, el, tmp) { stop_group_timer(driver, el); }
|
||||
}
|
||||
|
||||
void neu_adapter_driver_read_group(neu_adapter_driver_t *driver,
|
||||
@@ -466,12 +536,121 @@ 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.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.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)
|
||||
{
|
||||
switch (tag->type) {
|
||||
case NEU_TYPE_BOOL:
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
case NEU_TYPE_BYTES:
|
||||
break;
|
||||
case NEU_TYPE_BIT:
|
||||
@@ -546,9 +725,17 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
|
||||
case NEU_TYPE_LWORD:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value->value.u64 = neu_ntohll(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value->value.u64 = neu_htonlb(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value->value.u64 = neu_htonbl(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -637,26 +824,6 @@ static void cal_decimal(neu_type_e tag_type, neu_type_e value_type,
|
||||
}
|
||||
}
|
||||
|
||||
bool is_value_in_range(neu_type_e type, int64_t value)
|
||||
{
|
||||
switch (type) {
|
||||
case NEU_TYPE_INT8:
|
||||
return value >= INT8_MIN && value <= INT8_MAX;
|
||||
case NEU_TYPE_UINT8:
|
||||
return value >= 0 && value <= UINT8_MAX;
|
||||
case NEU_TYPE_INT16:
|
||||
return value >= INT16_MIN && value <= INT16_MAX;
|
||||
case NEU_TYPE_UINT16:
|
||||
return value >= 0 && value <= UINT16_MAX;
|
||||
case NEU_TYPE_INT32:
|
||||
return value >= INT32_MIN && value <= INT32_MAX;
|
||||
case NEU_TYPE_UINT32:
|
||||
return value >= 0 && value <= UINT32_MAX;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void neu_adapter_driver_write_tags(neu_adapter_driver_t *driver,
|
||||
neu_reqresp_head_t * req)
|
||||
{
|
||||
@@ -688,8 +855,7 @@ void neu_adapter_driver_write_tags(neu_adapter_driver_t *driver,
|
||||
for (int i = 0; i < cmd->n_tag; i++) {
|
||||
neu_datatag_t *tag = neu_group_find_tag(g->group, cmd->tags[i].tag);
|
||||
if (tag != NULL && neu_tag_attribute_test(tag, NEU_ATTRIBUTE_WRITE) &&
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) == false &&
|
||||
is_value_in_range(tag->type, cmd->tags[i].value.value.i64)) {
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) == false) {
|
||||
if (tag->type == NEU_TYPE_FLOAT || tag->type == NEU_TYPE_DOUBLE) {
|
||||
if (cmd->tags[i].value.type == NEU_TYPE_INT64) {
|
||||
cmd->tags[i].value.value.d64 =
|
||||
@@ -776,9 +942,7 @@ void neu_adapter_driver_write_gtags(neu_adapter_driver_t *driver,
|
||||
neu_group_find_tag(g->group, cmd->groups[i].tags[k].tag);
|
||||
if (tag != NULL &&
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_WRITE) &&
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) == false &&
|
||||
is_value_in_range(tag->type,
|
||||
cmd->groups[i].tags[k].value.value.i64)) {
|
||||
neu_tag_attribute_test(tag, NEU_ATTRIBUTE_STATIC) == false) {
|
||||
|
||||
if (tag->type == NEU_TYPE_FLOAT ||
|
||||
tag->type == NEU_TYPE_DOUBLE) {
|
||||
@@ -860,12 +1024,6 @@ void neu_adapter_driver_write_tag(neu_adapter_driver_t *driver,
|
||||
neu_tag_free(tag);
|
||||
return;
|
||||
}
|
||||
if (!is_value_in_range(tag->type, cmd->value.value.i64)) {
|
||||
driver->adapter.cb_funs.driver.write_response(
|
||||
&driver->adapter, req, NEU_ERR_TAG_VALUE_INVALID);
|
||||
neu_tag_free(tag);
|
||||
return;
|
||||
}
|
||||
if (tag->type == NEU_TYPE_FLOAT || tag->type == NEU_TYPE_DOUBLE) {
|
||||
if (cmd->value.type == NEU_TYPE_INT64) {
|
||||
cmd->value.value.d64 = (double) cmd->value.value.i64;
|
||||
@@ -917,13 +1075,6 @@ int neu_adapter_driver_add_group(neu_adapter_driver_t *driver, const char *name,
|
||||
if (find == NULL) {
|
||||
find = calloc(1, sizeof(group_t));
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) find,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
pthread_mutex_init(&find->wt_mtx, NULL);
|
||||
pthread_mutex_init(&find->apps_mtx, NULL);
|
||||
|
||||
@@ -934,28 +1085,13 @@ 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);
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
find->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
find->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
|
||||
param.second = 0;
|
||||
param.millisecond = 3;
|
||||
param.cb = write_callback;
|
||||
find->write = neu_event_add_timer(driver->driver_events, param);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
start_group_timer(driver, find);
|
||||
}
|
||||
|
||||
REGISTER_GROUP_METRIC(&driver->adapter, find->name,
|
||||
NEU_METRIC_GROUP_TAGS_TOTAL,
|
||||
@@ -999,11 +1135,14 @@ 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
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, find->report);
|
||||
neu_event_del_timer(driver->driver_events, find->read);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
stop_group_timer(driver, find);
|
||||
}
|
||||
|
||||
// a diminutive value should keep the interval untouched
|
||||
if (interval < NEU_GROUP_INTERVAL_LIMIT) {
|
||||
@@ -1023,7 +1162,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);
|
||||
@@ -1032,31 +1170,14 @@ int neu_adapter_driver_update_group(neu_adapter_driver_t *driver,
|
||||
}
|
||||
}
|
||||
|
||||
neu_event_timer_param_t param = {
|
||||
.second = interval / 1000,
|
||||
.millisecond = interval % 1000,
|
||||
.usr_data = (void *) find,
|
||||
.type = NEU_EVENT_TIMER_NOBLOCK,
|
||||
};
|
||||
|
||||
find->timestamp = global_timestamp; // trigger group_change
|
||||
find->grp.interval = interval;
|
||||
neu_group_set_interval(find->group, interval);
|
||||
|
||||
// restore the timers
|
||||
|
||||
param.type = driver->adapter.module->timer_type;
|
||||
param.cb = read_callback;
|
||||
find->read = neu_event_add_timer(driver->driver_events, param);
|
||||
|
||||
struct timespec t1 = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = 1000 * 1000 * 20,
|
||||
};
|
||||
struct timespec t2 = { 0 };
|
||||
nanosleep(&t1, &t2);
|
||||
|
||||
param.type = NEU_EVENT_TIMER_NOBLOCK;
|
||||
param.cb = report_callback;
|
||||
find->report = neu_adapter_add_timer((neu_adapter_t *) driver, param);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
start_group_timer(driver, find);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1072,9 +1193,10 @@ int neu_adapter_driver_del_group(neu_adapter_driver_t *driver, const char *name)
|
||||
|
||||
neu_adapter_driver_try_del_tag(driver, neu_group_tag_size(find->group));
|
||||
|
||||
neu_adapter_del_timer((neu_adapter_t *) driver, find->report);
|
||||
neu_event_del_timer(driver->driver_events, find->read);
|
||||
neu_event_del_timer(driver->driver_events, find->write);
|
||||
if (NEU_NODE_RUNNING_STATE_RUNNING == driver->adapter.state) {
|
||||
stop_group_timer(driver, find);
|
||||
}
|
||||
|
||||
if (find->grp.group_free != NULL) {
|
||||
find->grp.group_free(&find->grp);
|
||||
}
|
||||
@@ -1620,6 +1742,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,
|
||||
@@ -1716,7 +1839,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 {
|
||||
@@ -1740,6 +1863,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:
|
||||
@@ -1785,9 +1916,17 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1861,6 +2000,9 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tag->precision == 0 && tag->type == NEU_TYPE_DOUBLE) {
|
||||
format_tag_value(&tag_value.value);
|
||||
}
|
||||
}
|
||||
|
||||
utarray_push_back(tag_values, &tag_value);
|
||||
@@ -1940,9 +2082,17 @@ static void read_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2016,6 +2166,193 @@ static void read_group(int64_t timestamp, int64_t timeout,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tag->precision == 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.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:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
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_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;
|
||||
break;
|
||||
case NEU_TYPE_UINT8:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.u8 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_INT16:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.i16 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_UINT16:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.u16 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_INT32:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.i32 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_UINT32:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.u32 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_INT64:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.i64 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_UINT64:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.u64 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_FLOAT:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.f32 * tag->decimal;
|
||||
break;
|
||||
case NEU_TYPE_DOUBLE:
|
||||
tag_value.value.value.d64 =
|
||||
(double) tag_value.value.value.d64 * tag->decimal;
|
||||
break;
|
||||
default:
|
||||
tag_value.value.type = tag->type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tag->precision == 0 && tag->type == NEU_TYPE_DOUBLE) {
|
||||
format_tag_value(&tag_value.value);
|
||||
}
|
||||
}
|
||||
utarray_push_back(tag_values, &tag_value);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ 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_write_tag(neu_adapter_driver_t *driver,
|
||||
neu_reqresp_head_t * req);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+48
-6
@@ -212,16 +212,17 @@ static unsigned cpu_usage()
|
||||
return (double) work / total * 100.0 * sysconf(_SC_NPROCESSORS_CONF);
|
||||
}
|
||||
|
||||
static bool has_core_dumps()
|
||||
static bool has_core_dump_in_dir(const char *dir, const char *prefix)
|
||||
{
|
||||
DIR *dp = opendir("core");
|
||||
if (NULL == dp) {
|
||||
DIR *dp = opendir(dir);
|
||||
if (dp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (struct dirent *de = NULL; NULL != (de = readdir(dp));) {
|
||||
if (0 == strncmp("core", de->d_name, 4)) {
|
||||
struct dirent *de;
|
||||
bool found = false;
|
||||
while ((de = readdir(dp)) != NULL) {
|
||||
if (strncmp(prefix, de->d_name, strlen(prefix)) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@@ -231,6 +232,46 @@ static bool has_core_dumps()
|
||||
return found;
|
||||
}
|
||||
|
||||
static char *get_core_dir(const char *core_pattern)
|
||||
{
|
||||
char *last_slash = strrchr(core_pattern, '/');
|
||||
if (last_slash != NULL) {
|
||||
static char core_dir[256];
|
||||
ptrdiff_t path_length = last_slash - core_pattern + 1;
|
||||
strncpy(core_dir, core_pattern, path_length);
|
||||
core_dir[path_length] = '\0';
|
||||
return core_dir;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool has_core_dumps()
|
||||
{
|
||||
if (has_core_dump_in_dir("core", "core-neuron")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE *fp = fopen("/proc/sys/kernel/core_pattern", "r");
|
||||
if (fp == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char core_pattern[256];
|
||||
if (fgets(core_pattern, sizeof(core_pattern), fp) == NULL) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
char *core_dir =
|
||||
(core_pattern[0] == '|') ? "/var/crash/" : get_core_dir(core_pattern);
|
||||
if (core_dir == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return has_core_dump_in_dir(core_dir, "core-neuron");
|
||||
}
|
||||
|
||||
static inline void metrics_unregister_entry(const char *name)
|
||||
{
|
||||
neu_metric_entry_t *e = NULL;
|
||||
@@ -272,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;
|
||||
|
||||
@@ -34,6 +34,8 @@ 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_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) \
|
||||
|
||||
+56
-25
@@ -161,19 +161,24 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
|
||||
switch (t) {
|
||||
case 'H':
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_H;
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_H;
|
||||
option->string.is_default = false;
|
||||
break;
|
||||
case 'L':
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_L;
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_L;
|
||||
option->string.is_default = false;
|
||||
break;
|
||||
case 'D':
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_D;
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_D;
|
||||
option->string.is_default = false;
|
||||
break;
|
||||
case 'E':
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_D;
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_E;
|
||||
option->string.is_default = false;
|
||||
break;
|
||||
default:
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_H;
|
||||
option->string.type = NEU_DATATAG_STRING_TYPE_H;
|
||||
option->string.is_default = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -210,10 +215,13 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
}
|
||||
case NEU_TYPE_FLOAT:
|
||||
case NEU_TYPE_INT32:
|
||||
case NEU_TYPE_UINT32: {
|
||||
case NEU_TYPE_UINT32:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
case NEU_TYPE_TIME: {
|
||||
char *op = find_last_character(datatag->address, '#');
|
||||
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LL32;
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LL32;
|
||||
option->value32.is_default = true;
|
||||
if (op != NULL) {
|
||||
char e1 = 0;
|
||||
char e2 = 0;
|
||||
@@ -221,16 +229,20 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
|
||||
if (n == 2) {
|
||||
if (e1 == 'B' && e2 == 'B') {
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_BB32;
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_BB32;
|
||||
option->value32.is_default = false;
|
||||
}
|
||||
if (e1 == 'B' && e2 == 'L') {
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_BL32;
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_BL32;
|
||||
option->value32.is_default = false;
|
||||
}
|
||||
if (e1 == 'L' && e2 == 'L') {
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LL32;
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LL32;
|
||||
option->value32.is_default = false;
|
||||
}
|
||||
if (e1 == 'L' && e2 == 'B') {
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LB32;
|
||||
option->value32.endian = NEU_DATATAG_ENDIAN_LB32;
|
||||
option->value32.is_default = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,21 +254,35 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
case NEU_TYPE_UINT64: {
|
||||
char *op = find_last_character(datatag->address, '#');
|
||||
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = true;
|
||||
if (op != NULL) {
|
||||
char e = 0;
|
||||
sscanf(op, "#%c", &e);
|
||||
char e1 = 0;
|
||||
char e2 = 0;
|
||||
int n = sscanf(op, "#%c%c", &e1, &e2);
|
||||
|
||||
switch (e) {
|
||||
case 'B':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
break;
|
||||
case 'L':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
default:
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
if (n == 2) {
|
||||
if (e1 == 'B' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BB64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'B' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LB64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
} else if (n == 1) {
|
||||
if (e1 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +549,8 @@ int neu_tag_get_static_value_json(neu_datatag_t *tag, neu_json_type_e *t,
|
||||
v->val_double = value->d64;
|
||||
break;
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
*t = NEU_JSON_STR;
|
||||
v->val_str = value->str;
|
||||
break;
|
||||
@@ -625,7 +653,8 @@ int neu_tag_set_static_value_json(neu_datatag_t *tag, neu_json_type_e t,
|
||||
break;
|
||||
}
|
||||
case NEU_JSON_STR: {
|
||||
if (NEU_TYPE_STRING == tag->type) {
|
||||
if (NEU_TYPE_STRING == tag->type || NEU_TYPE_TIME == tag->type ||
|
||||
NEU_TYPE_DATA_AND_TIME == tag->type) {
|
||||
snprintf(value.str, sizeof(value.str), "%s", v->val_str);
|
||||
} else {
|
||||
rv = -1;
|
||||
@@ -695,6 +724,8 @@ char *neu_tag_dump_static_value(const neu_datatag_t *tag)
|
||||
jval = json_real(value.d64);
|
||||
break;
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
jval = json_string(value.str);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -405,6 +407,40 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neu_conn_clear_recv_buffer(neu_conn_t *conn)
|
||||
{
|
||||
if (!conn->is_connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t temp_buf[256];
|
||||
ssize_t ret;
|
||||
|
||||
switch (conn->param.type) {
|
||||
case NEU_CONN_TCP_CLIENT:
|
||||
do {
|
||||
ret = recv(conn->fd, temp_buf, sizeof(temp_buf), MSG_DONTWAIT);
|
||||
|
||||
if (ret > 0) {
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
zlog_info(conn->param.log,
|
||||
"Connection closed while clearing buffer.");
|
||||
break;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
break;
|
||||
} else {
|
||||
zlog_error(conn->param.log, "Error clearing buffer: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
} while (ret > 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
@@ -1290,6 +1326,12 @@ int neu_conn_stream_consume(neu_conn_t *conn, void *context,
|
||||
break;
|
||||
} else {
|
||||
pthread_mutex_lock(&conn->mtx);
|
||||
if (conn->offset - used < 0) {
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
zlog_warn(conn->param.log, "reset offset: %d, used: %d",
|
||||
conn->offset, used);
|
||||
return -1;
|
||||
}
|
||||
conn->offset -= used;
|
||||
memmove(conn->buf, conn->buf + used, conn->offset);
|
||||
neu_protocol_unpack_buf_init(&protocol_buf, conn->buf,
|
||||
@@ -1320,10 +1362,18 @@ int neu_conn_stream_tcp_server_consume(neu_conn_t *conn, int fd, void *context,
|
||||
neu_conn_tcp_server_close_client(conn, fd);
|
||||
break;
|
||||
} else {
|
||||
pthread_mutex_lock(&conn->mtx);
|
||||
if (conn->offset - used < 0) {
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
zlog_warn(conn->param.log, "reset offset: %d, used: %d",
|
||||
conn->offset, used);
|
||||
return -1;
|
||||
}
|
||||
conn->offset -= used;
|
||||
memmove(conn->buf, conn->buf + used, conn->offset);
|
||||
neu_protocol_unpack_buf_init(&protocol_buf, conn->buf,
|
||||
conn->offset);
|
||||
pthread_mutex_unlock(&conn->mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <nng/supplemental/util/platform.h>
|
||||
|
||||
#include "connection/mqtt_client.h"
|
||||
#include "errcodes.h"
|
||||
#include "event/event.h"
|
||||
#include "utils/asprintf.h"
|
||||
#include "utils/time.h"
|
||||
@@ -179,6 +180,93 @@ static inline uint8_t neu_mqtt_version_to_nng_mqtt_version(neu_mqtt_version_e v)
|
||||
}
|
||||
}
|
||||
|
||||
bool neu_mqtt_topic_filter_is_valid(const char *topic_filter)
|
||||
{
|
||||
if (NULL == topic_filter || '\0' == *topic_filter ||
|
||||
strlen(topic_filter) > 65535) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char c;
|
||||
while ((c = *topic_filter++)) {
|
||||
switch (c) {
|
||||
case '#':
|
||||
// '#' must be last character
|
||||
return '\0' == *topic_filter;
|
||||
case '+':
|
||||
// '+' must occupy an entire level
|
||||
if (*topic_filter && '/' != *topic_filter) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (; '/' != c; c = *topic_filter++) {
|
||||
if ('#' == c || '+' == c) {
|
||||
return false;
|
||||
} else if ('\0' == c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool topic_filter_is_match(const char *topic_filter,
|
||||
const char *topic_name,
|
||||
uint32_t topic_name_len)
|
||||
{
|
||||
// The Server MUST NOT match Topic Filters starting with a wildcard
|
||||
// character (# or +) with Topic Names beginning with a $ character
|
||||
// [MQTT-4.7.2-1].
|
||||
if ('$' == topic_name[0]) {
|
||||
if ('$' != topic_filter[0]) {
|
||||
return false;
|
||||
}
|
||||
} else if (0 == strcmp("#", topic_filter)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
while (true) {
|
||||
switch (*topic_filter) {
|
||||
case '#':
|
||||
return true;
|
||||
case '+':
|
||||
while (i < topic_name_len && '/' != topic_name[i]) {
|
||||
++i;
|
||||
};
|
||||
++topic_filter;
|
||||
break;
|
||||
case '/':
|
||||
if (i < topic_name_len && '/' == topic_name[i]) {
|
||||
++i;
|
||||
} else if ('#' != topic_filter[1]) { // '#' include parent level
|
||||
return false;
|
||||
}
|
||||
++topic_filter;
|
||||
break;
|
||||
case '\0':
|
||||
return i == topic_name_len;
|
||||
default:
|
||||
for (; *topic_filter && '/' != *topic_filter; ++topic_filter, ++i) {
|
||||
if (!(i < topic_name_len && *topic_filter == topic_name[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool neu_mqtt_topic_filter_is_match(const char *topic_filter,
|
||||
const char *topic_name)
|
||||
{
|
||||
return topic_filter_is_match(topic_filter, topic_name, strlen(topic_name));
|
||||
}
|
||||
|
||||
static inline task_t *task_new(neu_mqtt_client_t *client)
|
||||
{
|
||||
task_t *task = calloc(1, sizeof(*task));
|
||||
@@ -405,6 +493,26 @@ static inline void subscriptions_free(subscription_t *subscriptions)
|
||||
}
|
||||
}
|
||||
|
||||
static inline subscription_t *
|
||||
subscription_find_match(subscription_t *subscriptions, const char *topic_name,
|
||||
uint32_t topic_name_len)
|
||||
{
|
||||
subscription_t *sub = NULL, *tmp = NULL;
|
||||
HASH_FIND(hh, subscriptions, topic_name, topic_name_len, sub);
|
||||
if (NULL == sub) {
|
||||
// subscription wildcard matching
|
||||
// TODO: linear scanning is enough for current usages,
|
||||
// but may pose performance issues in the future
|
||||
HASH_ITER(hh, subscriptions, sub, tmp)
|
||||
{
|
||||
if (topic_filter_is_match(sub->topic, topic_name, topic_name_len)) {
|
||||
return sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sub;
|
||||
}
|
||||
|
||||
static int resub_cb(void *data)
|
||||
{
|
||||
neu_mqtt_client_t *client = data;
|
||||
@@ -433,8 +541,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
|
||||
@@ -459,8 +569,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;
|
||||
@@ -517,10 +630,9 @@ static void recv_cb(void *arg)
|
||||
log(debug, "recv [%.*s, QoS%d] %" PRIu32 " bytes", (unsigned) topic_len,
|
||||
topic, (int) qos, payload_len);
|
||||
|
||||
// find matching subscription
|
||||
// NOTE: does not support wildcards
|
||||
nng_mtx_lock(client->mtx);
|
||||
HASH_FIND(hh, client->subscriptions, topic, topic_len, subscription);
|
||||
subscription =
|
||||
subscription_find_match(client->subscriptions, topic, topic_len);
|
||||
if (NULL != subscription) {
|
||||
task_t *task = client_alloc_task(client);
|
||||
if (NULL != task) {
|
||||
@@ -1375,6 +1487,10 @@ int neu_mqtt_client_subscribe(neu_mqtt_client_t *client, neu_mqtt_qos_e qos,
|
||||
int rv = 0;
|
||||
subscription_t *subscription = NULL;
|
||||
|
||||
if (!neu_mqtt_topic_filter_is_valid(topic)) {
|
||||
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
}
|
||||
|
||||
nng_mtx_lock(client->mtx);
|
||||
if (NULL == client->recv_aio) {
|
||||
if ((rv = nng_aio_alloc(&client->recv_aio, recv_cb, client)) != 0) {
|
||||
|
||||
+97
-14
@@ -99,9 +99,20 @@ neu_manager_t *neu_manager_create()
|
||||
manager->subscribe_manager = neu_subscribe_manager_create();
|
||||
manager->log_level = ZLOG_LEVEL_NOTICE;
|
||||
|
||||
manager->server_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||||
manager->server_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
assert(manager->server_fd > 0);
|
||||
|
||||
struct timeval sock_timeout = {
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
if (setsockopt(manager->server_fd, SOL_SOCKET, SO_SNDTIMEO, &sock_timeout,
|
||||
sizeof(sock_timeout)) < 0 ||
|
||||
setsockopt(manager->server_fd, SOL_SOCKET, SO_RCVTIMEO, &sock_timeout,
|
||||
sizeof(sock_timeout)) < 0) {
|
||||
assert(!"fail to set manager sock timeout");
|
||||
}
|
||||
|
||||
// abstract domain socket is a Linux extension, thus not portable.
|
||||
// use abstract domain socket here to avoid polluting the file system
|
||||
struct sockaddr_un local = {
|
||||
@@ -117,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);
|
||||
|
||||
@@ -145,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);
|
||||
|
||||
@@ -165,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,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);
|
||||
@@ -511,6 +531,35 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!neu_plugin_manager_create_instance_by_lib_name(
|
||||
manager->plugin_manager, cmd->library, &ins)) {
|
||||
nlog_warn("library %s not instance", cmd->library);
|
||||
free(cmd->so_file);
|
||||
free(cmd->schema_file);
|
||||
free(so_tmp_path);
|
||||
header->type = NEU_RESP_ERROR;
|
||||
e.error = NEU_ERR_LIBRARY_UPDATE_FAIL;
|
||||
strcpy(header->receiver, header->sender);
|
||||
reply(manager, header, &e);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(module_name, ins.module->module_name) != 0) {
|
||||
nlog_warn("library %s module name mismatch!", cmd->library);
|
||||
neu_plugin_manager_destroy_instance(manager->plugin_manager,
|
||||
&ins);
|
||||
free(cmd->so_file);
|
||||
free(cmd->schema_file);
|
||||
free(so_tmp_path);
|
||||
header->type = NEU_RESP_ERROR;
|
||||
e.error = NEU_ERR_LIBRARY_UPDATE_FAIL;
|
||||
strcpy(header->receiver, header->sender);
|
||||
reply(manager, header, &e);
|
||||
break;
|
||||
}
|
||||
|
||||
neu_plugin_manager_destroy_instance(manager->plugin_manager, &ins);
|
||||
|
||||
if (!neu_plugin_manager_exists(manager->plugin_manager,
|
||||
module_name)) {
|
||||
|
||||
@@ -659,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) {
|
||||
@@ -679,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 !=
|
||||
@@ -703,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);
|
||||
@@ -801,6 +855,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);
|
||||
|
||||
@@ -826,7 +884,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);
|
||||
@@ -854,7 +914,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);
|
||||
|
||||
@@ -874,7 +936,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);
|
||||
|
||||
@@ -967,6 +1030,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:
|
||||
@@ -977,6 +1041,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) {
|
||||
@@ -1098,9 +1165,24 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
neu_msg_exchange(header);
|
||||
reply(manager, header, &e);
|
||||
} else {
|
||||
UT_array *apps = neu_subscribe_manager_find(
|
||||
manager->subscribe_manager, cmd->driver, cmd->group);
|
||||
|
||||
forward_msg(manager, header, header->receiver);
|
||||
neu_subscribe_manager_remove(manager->subscribe_manager,
|
||||
cmd->driver, cmd->group);
|
||||
|
||||
if (NULL == apps) {
|
||||
break;
|
||||
}
|
||||
|
||||
// notify app node about group deletion
|
||||
utarray_foreach(apps, neu_app_subscribe_t *, app)
|
||||
{
|
||||
forward_msg_copy(manager, header, app->app_name);
|
||||
}
|
||||
|
||||
utarray_free(apps);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1189,6 +1271,7 @@ 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_PRGFILE_PROCESS:
|
||||
forward_msg(manager, header, header->receiver);
|
||||
break;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -460,6 +462,7 @@ static inline int add_driver(neu_manager_t *manager, neu_req_driver_t *driver)
|
||||
if (0 != neu_adapter_validate_gtags(adapter, &cmd, &resp) ||
|
||||
0 != neu_adapter_try_add_gtags(adapter, &cmd, &resp) ||
|
||||
0 != neu_adapter_add_gtags(adapter, &cmd, &resp)) {
|
||||
neu_adapter_uninit(adapter);
|
||||
neu_manager_del_node(manager, driver->node);
|
||||
}
|
||||
|
||||
@@ -498,11 +501,21 @@ int neu_manager_add_drivers(neu_manager_t *manager, neu_req_driver_array_t *req)
|
||||
for (uint16_t i = 0; i < req->n_driver; ++i) {
|
||||
ret = add_driver(manager, &req->drivers[i]);
|
||||
if (0 != ret) {
|
||||
nlog_notice("add i:%" PRIu16 " driver:%s fail", i,
|
||||
req->drivers[i].node);
|
||||
while (i-- > 0) {
|
||||
nlog_notice("rollback i:%" PRIu16 " driver:%s", i,
|
||||
req->drivers[i].node);
|
||||
neu_adapter_t *adapter = neu_node_manager_find(
|
||||
manager->node_manager, req->drivers[i].node);
|
||||
neu_adapter_uninit(adapter);
|
||||
neu_manager_del_node(manager, req->drivers[i].node);
|
||||
}
|
||||
nlog_error("fail to add %" PRIu16 " drivers", req->n_driver);
|
||||
break;
|
||||
}
|
||||
nlog_notice("add i:%" PRIu16 " driver:%s success", i,
|
||||
req->drivers[i].node);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -489,6 +489,38 @@ bool neu_plugin_manager_create_instance_by_path(neu_plugin_manager_t *mgr,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool neu_plugin_manager_create_instance_by_lib_name(
|
||||
neu_plugin_manager_t *mgr, const char *lib_name,
|
||||
neu_plugin_instance_t *instance)
|
||||
{
|
||||
(void) mgr;
|
||||
char lib_paths[3][64] = { 0 };
|
||||
snprintf(lib_paths[0], sizeof(lib_paths[0]), "%s", g_plugin_dir);
|
||||
snprintf(lib_paths[1], sizeof(lib_paths[1]), "%s/system", g_plugin_dir);
|
||||
snprintf(lib_paths[2], sizeof(lib_paths[2]), "%s/custom", g_plugin_dir);
|
||||
|
||||
for (size_t i = 0; i < sizeof(lib_paths) / sizeof(lib_paths[0]); i++) {
|
||||
char lib_path[256] = { 0 };
|
||||
|
||||
snprintf(lib_path, sizeof(lib_path) - 1, "%s/%s", lib_paths[i],
|
||||
lib_name);
|
||||
instance->handle = dlopen(lib_path, RTLD_NOW);
|
||||
|
||||
if (instance->handle == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
instance->module = (neu_plugin_module_t *) dlsym(instance->handle,
|
||||
"neu_plugin_module");
|
||||
assert(instance->module != NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(instance->handle != NULL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool neu_plugin_manager_remove_library(neu_plugin_manager_t *mgr,
|
||||
const char * library)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,10 @@ bool neu_plugin_manager_create_instance_by_path(neu_plugin_manager_t *mgr,
|
||||
neu_plugin_instance_t *instance,
|
||||
int * error);
|
||||
|
||||
bool neu_plugin_manager_create_instance_by_lib_name(
|
||||
neu_plugin_manager_t *mgr, const char *lib_name,
|
||||
neu_plugin_instance_t *instance);
|
||||
|
||||
bool neu_plugin_manager_remove_library(neu_plugin_manager_t *mgr,
|
||||
const char * library);
|
||||
|
||||
|
||||
@@ -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
-2
@@ -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;
|
||||
|
||||
@@ -125,7 +127,6 @@ static int neuron_run(const neu_cli_args_t *args)
|
||||
int rv = 0;
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGABRT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGKILL, sig_handler);
|
||||
|
||||
@@ -165,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) {
|
||||
|
||||
+373
-19
@@ -43,6 +43,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 +58,24 @@ 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;
|
||||
|
||||
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 +90,103 @@ 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[9 + 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;
|
||||
|
||||
if (p_tag->error != 0) {
|
||||
tag_elems[7].name = "error";
|
||||
tag_elems[7].t = NEU_JSON_INT;
|
||||
tag_elems[7].v.val_int = p_tag->error;
|
||||
} else {
|
||||
tag_elems[7].name = "value";
|
||||
tag_elems[7].t = p_tag->t;
|
||||
tag_elems[7].v = p_tag->value;
|
||||
tag_elems[7].precision = p_tag->precision;
|
||||
|
||||
if (p_tag->t == NEU_JSON_FLOAT || p_tag->t == NEU_JSON_DOUBLE) {
|
||||
if_precision = 1;
|
||||
tag_elems[8].name = "transferPrecision";
|
||||
tag_elems[8].t = NEU_JSON_INT;
|
||||
tag_elems[8].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 + 8 + k].name = p_tag->metas[k].name;
|
||||
tag_elems[if_precision + 8 + k].t = p_tag->metas[k].t;
|
||||
tag_elems[if_precision + 8 + k].v = p_tag->metas[k].value;
|
||||
}
|
||||
|
||||
tag_array = neu_json_encode_array(tag_array, tag_elems,
|
||||
8 + 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_read_resp1(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -152,6 +258,53 @@ int neu_json_encode_read_resp1(void *json_object, void *param)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_encode_read_resp2(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_json_read_resp_t *resp = (neu_json_read_resp_t *) param;
|
||||
|
||||
void * tag_array = neu_json_array();
|
||||
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 };
|
||||
|
||||
tag_elems[0].name = "name";
|
||||
tag_elems[0].t = NEU_JSON_STR;
|
||||
tag_elems[0].v.val_str = p_tag->name;
|
||||
|
||||
if (p_tag->error != 0) {
|
||||
tag_elems[1].name = "error";
|
||||
tag_elems[1].t = NEU_JSON_INT;
|
||||
tag_elems[1].v.val_int = p_tag->error;
|
||||
} else {
|
||||
tag_elems[1].name = "value";
|
||||
tag_elems[1].t = p_tag->t;
|
||||
tag_elems[1].v = p_tag->value;
|
||||
tag_elems[1].precision = p_tag->precision;
|
||||
}
|
||||
|
||||
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_array =
|
||||
neu_json_encode_array(tag_array, tag_elems, 2 + p_tag->n_meta);
|
||||
p_tag++;
|
||||
}
|
||||
|
||||
neu_json_elem_t resp_elems[] = { {
|
||||
.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;
|
||||
}
|
||||
|
||||
int neu_json_decode_write_req(char *buf, neu_json_write_req_t **result)
|
||||
{
|
||||
void *json_obj = neu_json_decode_new(buf);
|
||||
@@ -407,14 +560,19 @@ void neu_json_decode_write_free(neu_json_write_t *req)
|
||||
|
||||
int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result)
|
||||
{
|
||||
int ret = 0;
|
||||
void * json_obj = NULL;
|
||||
neu_json_read_req_t *req = calloc(1, sizeof(neu_json_read_req_t));
|
||||
if (req == NULL) {
|
||||
int ret = 0;
|
||||
void *json_obj = NULL;
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
neu_json_read_req_t *req = calloc(1, sizeof(neu_json_read_req_t));
|
||||
if (req == NULL) {
|
||||
neu_json_decode_free(json_obj);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
{
|
||||
@@ -436,15 +594,6 @@ int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result)
|
||||
.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;
|
||||
|
||||
neu_json_elem_t query_elems[] = {
|
||||
{
|
||||
@@ -458,6 +607,17 @@ int neu_json_decode_read_req(char *buf, neu_json_read_req_t **result)
|
||||
.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),
|
||||
@@ -493,6 +653,123 @@ 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_encode_read_periodic_resp(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -579,6 +856,83 @@ void neu_json_metas_to_json(neu_tag_meta_t *metas, int n_meta,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -199,6 +199,8 @@ int neu_json_tag_check_type(neu_json_tag_t *tag)
|
||||
return NEU_JSON_BOOL == tag->t;
|
||||
case NEU_TYPE_BYTES:
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_TIME:
|
||||
case NEU_TYPE_DATA_AND_TIME:
|
||||
return NEU_JSON_STR == tag->t &&
|
||||
strlen(tag->value.val_str) <= NEU_VALUE_SIZE;
|
||||
}
|
||||
@@ -292,7 +294,8 @@ int neu_json_decode_add_tags_req(char *buf, neu_json_add_tags_req_t **result)
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
goto decode_fail;
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
@@ -563,7 +566,8 @@ int neu_json_decode_add_gtags_req(char *buf, neu_json_add_gtags_req_t **result)
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
goto decode_fail;
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
@@ -657,6 +661,10 @@ int neu_json_decode_del_tags_req(char *buf, neu_json_del_tags_req_t **result)
|
||||
}
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = { {
|
||||
.name = "node",
|
||||
@@ -773,7 +781,8 @@ int neu_json_decode_update_tags_req(char * buf,
|
||||
|
||||
json_obj = neu_json_decode_new(buf);
|
||||
if (NULL == json_obj) {
|
||||
goto decode_fail;
|
||||
free(req);
|
||||
return -1;
|
||||
}
|
||||
|
||||
neu_json_elem_t req_elems[] = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -320,7 +320,6 @@ int neu_http_response(nng_aio *aio, neu_err_code_e code, char *content)
|
||||
case NEU_ERR_TAG_PRECISION_INVALID:
|
||||
case NEU_ERR_TAG_NAME_TOO_LONG:
|
||||
case NEU_ERR_TAG_ADDRESS_TOO_LONG:
|
||||
case NEU_ERR_TAG_VALUE_INVALID:
|
||||
case NEU_ERR_GROUP_MAX_GROUPS:
|
||||
case NEU_ERR_LICENSE_MAX_TAGS:
|
||||
case NEU_ERR_LICENSE_BAD_CLOCK:
|
||||
|
||||
+53
-5
@@ -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,44 @@
|
||||
#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;
|
||||
int negative = 1;
|
||||
|
||||
if (value < 0) {
|
||||
value *= -1;
|
||||
negative = -1;
|
||||
}
|
||||
|
||||
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 * negative;
|
||||
}
|
||||
|
||||
static json_t *encode_object_value(neu_json_elem_t *ele)
|
||||
{
|
||||
json_t *ob = NULL;
|
||||
@@ -42,9 +81,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) {
|
||||
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 +113,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) {
|
||||
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));
|
||||
|
||||
@@ -484,6 +484,35 @@ class TestMQTT:
|
||||
finally:
|
||||
api.update_group_check(DRIVER, new_name, GROUP)
|
||||
|
||||
@description(
|
||||
given="MQTT node",
|
||||
when="delete subscribed driver group and add back group",
|
||||
then="broker should receive data on upload topic",
|
||||
)
|
||||
def test_mqtt_upload_when_group_deleted(self, mocker, conf_fmt_tags):
|
||||
api.node_setting_check(NODE, conf_fmt_tags)
|
||||
api.node_ctl(NODE, config.NEU_CTL_START)
|
||||
|
||||
# delete driver group
|
||||
api.del_group_check(DRIVER, GROUP)
|
||||
# add back driver group
|
||||
api.add_group_check(DRIVER, GROUP, INTERVAL)
|
||||
api.add_tags_check(DRIVER, GROUP, tags=[TAG0])
|
||||
# add back subscription on new topic
|
||||
topic = UPLOAD_TOPIC + "-new"
|
||||
params = {"topic": topic}
|
||||
api.subscribe_group_check(NODE, DRIVER, GROUP, params)
|
||||
|
||||
msg = mocker.get(topic, timeout=3)
|
||||
try:
|
||||
assert msg is not None
|
||||
assert DRIVER == msg["node"]
|
||||
assert GROUP == msg["group"]
|
||||
assert TAG0["name"] in [tag["name"] for tag in msg["tags"]]
|
||||
finally:
|
||||
params["topic"] = UPLOAD_TOPIC
|
||||
api.subscribe_group_update(NODE, DRIVER, GROUP, params)
|
||||
|
||||
@description(
|
||||
given="MQTT node and conf_cache",
|
||||
when="broken network connection restored",
|
||||
|
||||
@@ -452,80 +452,6 @@ class TestModbus:
|
||||
assert error.NEU_ERR_TAG_ADDRESS_FORMAT_INVALID == response.json()[
|
||||
'error']
|
||||
|
||||
@description(given="created modbus node and tags", when="write tags with invalid value", then="write failed")
|
||||
def test_write_tags_invalid_value(self, param):
|
||||
response = api.write_tag(node=param[0], group='group', tag=hold_int16[0]['name'], value=32768)
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_TAG_VALUE_INVALID == response.json()['error']
|
||||
|
||||
response = api.write_tag(node=param[0], group='group', tag=hold_uint16[0]['name'], value=-1)
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_TAG_VALUE_INVALID == response.json()['error']
|
||||
|
||||
response = api.write_tag(node=param[0], group='group', tag=hold_int32[0]['name'], value=2147483648)
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_TAG_VALUE_INVALID == response.json()['error']
|
||||
|
||||
response = api.write_tag(node=param[0], group='group', tag=hold_uint32[0]['name'], value=-1)
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_TAG_VALUE_INVALID == response.json()['error']
|
||||
|
||||
response = api.write_tags(node=param[0], group='group', tag_values=[
|
||||
{"tag": hold_int16[0]['name'], "value": 32768},
|
||||
{"tag": hold_uint16[0]['name'], "value": 2},
|
||||
{"tag": hold_int32[0]['name'], "value": 3},
|
||||
{"tag": hold_uint32[0]['name'], "value": 4}])
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
response = api.write_tags(node=param[0], group='group', tag_values=[
|
||||
{"tag": hold_int16[0]['name'], "value": 1},
|
||||
{"tag": hold_uint16[0]['name'], "value": -1},
|
||||
{"tag": hold_int32[0]['name'], "value": 3},
|
||||
{"tag": hold_uint32[0]['name'], "value": 4}])
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
response = api.write_tags(node=param[0], group='group', tag_values=[
|
||||
{"tag": hold_int16[0]['name'], "value": 1},
|
||||
{"tag": hold_uint16[0]['name'], "value": 2},
|
||||
{"tag": hold_int32[0]['name'], "value": 2147483648},
|
||||
{"tag": hold_uint32[0]['name'], "value": 4}])
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
response = api.write_tags(node=param[0], group='group', tag_values=[
|
||||
{"tag": hold_int16[0]['name'], "value": 1},
|
||||
{"tag": hold_uint16[0]['name'], "value": 2},
|
||||
{"tag": hold_int32[0]['name'], "value": 3},
|
||||
{"tag": hold_uint32[0]['name'], "value": -1}])
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
modbus_write_gtags = {"node": param[0], "groups": [{"group": "group", "tags" : [{"tag": "hold_int16", "value": 32768},
|
||||
{"tag": "hold_uint16", "value": 2}, {"tag": "hold_int32", "value": 3}, {"tag": "hold_uint32", "value": 4}]}]}
|
||||
response = api.write_gtags(json=modbus_write_gtags)
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
modbus_write_gtags = {"node": param[0], "groups": [{"group": "group", "tags" : [{"tag": "hold_int16", "value": 1},
|
||||
{"tag": "hold_uint16", "value": -1}, {"tag": "hold_int32", "value": 3}, {"tag": "hold_uint32", "value": 4}]}]}
|
||||
response = api.write_gtags(json=modbus_write_gtags)
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
modbus_write_gtags = {"node": param[0], "groups": [{"group": "group", "tags" : [{"tag": "hold_int16", "value": 1},
|
||||
{"tag": "hold_uint16", "value": 2}, {"tag": "hold_int32", "value": 2147483648}, {"tag": "hold_uint32", "value": 4}]}]}
|
||||
response = api.write_gtags(json=modbus_write_gtags)
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
modbus_write_gtags = {"node": param[0], "groups": [{"group": "group", "tags" : [{"tag": "hold_int16", "value": 1},
|
||||
{"tag": "hold_uint16", "value": 2}, {"tag": "hold_int32", "value": 3}, {"tag": "hold_uint32", "value": -1}]}]}
|
||||
response = api.write_gtags(json=modbus_write_gtags)
|
||||
assert 404 == response.status_code
|
||||
assert error.NEU_ERR_TAG_NOT_EXIST == response.json()['error']
|
||||
|
||||
@description(given="created modbus node and tags", when="write/read tags", then="write/read success")
|
||||
def test_write_read_tags(self, param):
|
||||
api.write_tag_check(
|
||||
|
||||
@@ -216,12 +216,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()
|
||||
@@ -252,7 +253,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()
|
||||
@@ -280,41 +281,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):
|
||||
@@ -324,7 +323,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)
|
||||
@@ -333,15 +331,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):
|
||||
@@ -355,7 +352,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)
|
||||
@@ -364,7 +360,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]
|
||||
@@ -388,7 +383,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])
|
||||
@@ -420,7 +414,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]
|
||||
@@ -437,7 +430,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]
|
||||
@@ -468,25 +460,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'
|
||||
@@ -507,7 +500,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
|
||||
@@ -521,7 +515,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
|
||||
@@ -536,7 +531,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
|
||||
@@ -550,7 +546,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
|
||||
@@ -563,15 +560,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
|
||||
@@ -602,6 +603,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')
|
||||
@@ -620,4 +626,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
|
||||
|
||||
@@ -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)
|
||||
+27
-4
@@ -155,6 +155,13 @@ 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 read_tag(node, group, tag, sync=False):
|
||||
response = read_tags(node, group, sync, query={"name": tag})
|
||||
assert 200 == response.status_code
|
||||
@@ -232,12 +239,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})
|
||||
|
||||
|
||||
@@ -273,6 +280,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])
|
||||
|
||||
@@ -295,8 +306,8 @@ def get_version():
|
||||
return requests.get(url=config.BASE_URL + "/api/v2/version", headers={"Authorization": config.default_jwt})
|
||||
|
||||
|
||||
def prgfile_upload(driver, path, params):
|
||||
return requests.post(url=config.BASE_URL + "/api/v2/prgfile", headers={"Authorization": config.default_jwt}, json={"driver": driver, "path": path, "parameters": params})
|
||||
def prgfile_upload(driver, path, del_flag, params):
|
||||
return requests.post(url=config.BASE_URL + "/api/v2/prgfile", headers={"Authorization": config.default_jwt}, json={"driver": driver, "path": path, "del_flag": del_flag, "parameters": params})
|
||||
|
||||
|
||||
def prgfile_process(driver):
|
||||
@@ -318,6 +329,18 @@ def modbus_rtu_node_setting(node, port=502, connection_mode=0, transport_mode=0,
|
||||
"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})
|
||||
|
||||
|
||||
def modbus_rtu_node_setting_endian(node, port=502, connection_mode=0, transport_mode=0, interval=0, host='127.0.0.1', timeout=3000, max_retries=2, link=1, device="", stop=0, parity=0, baud=4, data=3, 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, "link": link, "device": device, "stop": stop,
|
||||
"parity": parity, "baud": baud, "data": data, "endianess": endianness})
|
||||
|
||||
|
||||
def mqtt_node_setting(node):
|
||||
return node_setting(node, json={"client-id": "neuron_aBcDeF", "qos": 0, "format": 0,
|
||||
"write-req-topic": f"/neuron/{node}/write/req", "write-resp-topic": f"/neuron/{node}/write/resp",
|
||||
|
||||
@@ -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
|
||||
@@ -68,6 +68,11 @@ NEU_DATA_6 = 1
|
||||
NEU_DATA_7 = 2
|
||||
NEU_DATA_8 = 3
|
||||
|
||||
ENDIAN_ABCD = 1,
|
||||
ENDIAN_BADC = 2,
|
||||
ENDIAN_DCBA = 3,
|
||||
ENDIAN_CDAB = 4,
|
||||
|
||||
PLUGIN_MODBUS_TCP = "Modbus TCP"
|
||||
PLUGIN_MODBUS_RTU = "Modbus RTU"
|
||||
PLUGIN_MQTT = "MQTT"
|
||||
|
||||
@@ -53,7 +53,6 @@ NEU_ERR_TAG_ADDRESS_TOO_LONG = 2207
|
||||
NEU_ERR_TAG_DESCRIPTION_TOO_LONG = 2208
|
||||
NEU_ERR_TAG_PRECISION_INVALID = 2209
|
||||
NEU_ERR_TAG_EXIST = 2210
|
||||
NEU_ERR_TAG_VALUE_INVALID = 2211
|
||||
|
||||
NEU_ERR_LIBRARY_NOT_FOUND = 2301
|
||||
NEU_ERR_LIBRARY_INFO_INVALID = 2302
|
||||
@@ -71,6 +70,7 @@ NEU_ERR_LIBRARY_MODULE_KIND_NOT_SUPPORT = 2313
|
||||
NEU_ERR_LIBRARY_MODULE_VERSION_NOT_MATCH = 2314
|
||||
NEU_ERR_LIBRARY_NAME_NOT_CONFORM = 2315
|
||||
NEU_ERR_LIBRARY_CLIB_NOT_MATCH = 2316
|
||||
NEU_ERR_LIBRARY_UPDATE_FAIL = 2317
|
||||
|
||||
NEU_ERR_LICENSE_NOT_FOUND = 2400
|
||||
NEU_ERR_LICENSE_INVALID = 2401
|
||||
|
||||
@@ -200,7 +200,7 @@ class TestPlugin:
|
||||
response = api.updata_plugin(
|
||||
library_name=plugin_data['library'], so_file=plugin_data['so_file'], schema_file=plugin_data['schema_file'])
|
||||
assert 400 == response.status_code
|
||||
assert NEU_ERR_LIBRARY_MODULE_NOT_EXISTS == response.json().get("error")
|
||||
assert NEU_ERR_LIBRARY_UPDATE_FAIL == response.json().get("error")
|
||||
|
||||
@description(given="incorrect configuration", when="update plugin", then="fail")
|
||||
def test_08_update_plugin_fail1(self):
|
||||
@@ -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.8.99'
|
||||
|
||||
@description(given="incorrect configuration", when="update plugin", then="fail")
|
||||
def test_10_update_plugin_fail3(self):
|
||||
|
||||
@@ -9,7 +9,7 @@ class TestLog:
|
||||
@description(given="multiple non-existing groups and multiple correct tags",
|
||||
when="adding",
|
||||
then="successfully added")
|
||||
def test_adding_correct_gtags_nonexisting_groups(self):
|
||||
def test_adding_correct_gtags_nonexisting_groups(self, class_setup_and_teardown):
|
||||
response = api.add_node(node='modbus-tcp-tag-test', plugin=PLUGIN_MODBUS_TCP)
|
||||
assert 200 == response.status_code
|
||||
assert 0 == response.json()['error']
|
||||
@@ -63,6 +63,9 @@ class TestLog:
|
||||
assert 200 == response.status_code
|
||||
assert NEU_ERR_SUCCESS == response.json()['error']
|
||||
|
||||
# check data persisted
|
||||
class_setup_and_teardown.restart()
|
||||
|
||||
response = api.get_group()
|
||||
assert 200 == response.status_code
|
||||
assert 'group_1' == response.json()['groups'][0]['group']
|
||||
|
||||
@@ -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, 8, 99),
|
||||
.schema = "c1",
|
||||
.module_name = "c1",
|
||||
.module_descr = "c1 v2",
|
||||
|
||||
@@ -64,6 +64,13 @@ target_include_directories(rolling_counter_test PRIVATE
|
||||
)
|
||||
target_link_libraries(rolling_counter_test neuron-base gtest_main gtest)
|
||||
|
||||
add_executable(mqtt_client_test mqtt_client_test.cc)
|
||||
target_include_directories(mqtt_client_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(mqtt_client_test neuron-base gtest_main gtest)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(json_test)
|
||||
gtest_discover_tests(http_test)
|
||||
@@ -73,3 +80,4 @@ gtest_discover_tests(tag_sort_test)
|
||||
gtest_discover_tests(modbus_test)
|
||||
gtest_discover_tests(async_queue_test)
|
||||
gtest_discover_tests(rolling_counter_test)
|
||||
gtest_discover_tests(mqtt_client_test)
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "connection/mqtt_client.h"
|
||||
#include "utils/log.h"
|
||||
|
||||
zlog_category_t *neuron = NULL;
|
||||
|
||||
TEST(MQTTClientTest, test_topic_filter_is_valid)
|
||||
{
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid(NULL));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid(""));
|
||||
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid("sport/tennis#"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid("sport/tennis/#/ranking"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("#"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport/#"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport/tennis/player/#"));
|
||||
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid("sport+"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_valid("sport/+player"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("+"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("+/+"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport/+/player"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("+/tennis/#"));
|
||||
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("$SYS"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("$SYS/#"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport/tennis"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_valid("sport/tennis/player"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_valid("sport/tennis/player/ranking"));
|
||||
}
|
||||
|
||||
TEST(MQTTClientTest, test_topic_filter_is_match)
|
||||
{
|
||||
const char *filter = "#";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "$sport"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player"));
|
||||
|
||||
filter = "sport/tennis/player/#";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/play"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/"));
|
||||
ASSERT_EQ(
|
||||
true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/ranking"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(
|
||||
filter, "sport/tennis/player/ranking/score/wimbledon"));
|
||||
|
||||
filter = "+";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "$finance"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "/finance"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "finance"));
|
||||
|
||||
filter = "/+";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "finance"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "/finance"));
|
||||
|
||||
filter = "+/+";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "$finance"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "finance"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "/finance"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
|
||||
filter = "sport/+";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/tennis/"));
|
||||
ASSERT_EQ(false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/ranking"));
|
||||
|
||||
filter = "sport/tennis/+";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(
|
||||
false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/ranking"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player1"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player2"));
|
||||
|
||||
filter = "sport/+/player";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/tennis/"));
|
||||
ASSERT_EQ(false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/ranking"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player"));
|
||||
ASSERT_EQ(false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/"));
|
||||
ASSERT_EQ(
|
||||
false,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/ranking"));
|
||||
|
||||
filter = "+/tennis/#";
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/"));
|
||||
ASSERT_EQ(false, neu_mqtt_topic_filter_is_match(filter, "sport/baseball"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/tennis"));
|
||||
ASSERT_EQ(true, neu_mqtt_topic_filter_is_match(filter, "sport/tennis/"));
|
||||
ASSERT_EQ(true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player"));
|
||||
ASSERT_EQ(
|
||||
true,
|
||||
neu_mqtt_topic_filter_is_match(filter, "sport/tennis/player/ranking"));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
zlog_init("./config/dev.conf");
|
||||
neuron = zlog_get_category("neuron");
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user