使用 JStruct 建模

更新时间:
2023-12-21
下载文档

使用 JStruct 建模

本节以使用 JStruct 工具对云原生验证平台中陀螺仪功能进行微服务建模为例介绍 JStruct 的使用方法。JStruct 工具的详细使用方法可以参考 JStruct 用户手册

建立数据模型

首先需要将陀螺仪提供的数据定义为 axis 结构体,该步骤可以使用 JStruct 工具进行建模,具体方法如下:

步骤 1:编写配置文件

JStruct 的配置文件支持使用 conf.json 或 YAML 文件的方式。

注意:

  • conf.json 可以直接在已部署了 JSRE 运行环境的 SylixOS 设备上使用,也可以在 Windows 或 Linux 系统的 Node.js 的环境下使用。
  • YAML 只能在安装有 yaml 解析库的 Node.js 环境下使用。

通过 conf.json 或 YAML 文件定义 axis 结构体的示例如下:

  • conf_axis.json 文件示例:
{
  "name": "axis",
  "struct": {
    "name": "axis",
    "member": [
      { "key": "roll", "type": "int", "req": true },
      { "key": "pitch", "type": "int", "req": true },
      { "key": "yaw", "type": "int", "req": true }
    ]
  }
}
  • conf_axis.yaml 文件示例:
name: axis
struct:
  name: axis
  member:
    -
      key: roll
      type: int
      req: true
    -
      key: pitch
      type: int
      req: true
    -
      key: yaw
      type: int
      req: true

详细的字段说明以及支持的数据类型请参考 JStruct 用户手册

步骤 2:使用 JStruct 工具

JStruct 可以在支持云原生 SDK 的 SylixOS 系统或 Node.js 环境中运行,下面分别介绍 JStruct 在两种环境的使用方法:

  • SylixOS 环境

    在 SylixOS 环境中使用 JStruct 工具时,只能使用 conf_axis.json 配置文件。

    1. 参考 上传镜像包 将 jstruct.js、file.js、func.js 与 conf_axis.json 文件上传至 SylixOS 系统。

    2. 在命令行执行如下命令,即可得到 axis_jstruct.c 和 axis_jstruct.h 文件。

    [root@sylixos:/apps]# javascript -a conf_axis.json jstruct.js
    
  • Node.js 环境

    • 若使用 conf_axis.json 配置文件,则在命令行执行如下命令(以 Windows 下 Node.js 环境为例),即可得到 axis_jstruct.c 和 axis_jstruct.h 文件。
    PS C:\> node jstruct.js conf_axis.json
    
    • 若使用 conf_axis.yaml 配置文件,则在命令行执行如下命令(以 Windows 下 Node.js 环境为例),即可得到 axis_jstruct.c 和 axis_jstruct.h 文件。
    PS C:\> node jstruct.js conf_axis.yaml
    

步骤 3:自动生成代码

JStruct 可以自动生成如下代码:

struct axis {
    int   roll;  /* roll angle */
    int   pitch; /* pitch angle */
    int   yaw;   /* yaw angle */
    void *json;
};

自动生成序列化与反序列化代码:

/* Deserialize the JSON string into a structure 'axis' */
bool axis_json_parse(struct axis *, const char *, size_t);

/* Free axis_json_parse() buffer, */
/* Warning: string type member can no longer be used */
void axis_json_parse_free(struct axis *);

/* Serialize the structure 'axis' into a JSON string */
char *axis_json_stringify(const struct axis *);

/* Free axis_json_stringify() return value */
void axis_json_stringify_free(char *);

验证数据模型

通过以下范例对 JStruct 自动生成的代码进行验证。

使用 RPC 宏验证

结合 JStruct 自动生成的代码,在实现 RPC 时可以使用 VSOA_PARAM_SYNCER_RPC 宏,此宏实现了对 struct axis 结构体的读取、赋值等操作。请参考如下代码片段:

/*
 * Command '/axis' routine
 */
static void command_axis (void *arg, vsoa_server_t *server, vsoa_cli_id_t cid,
                          vsoa_header_t *vsoa_hdr, vsoa_url_t *url,
                          vsoa_payload_t *payload)
{
    VSOA_PARAM_SYNCER_RPC(server, cid, axis, &my_server.data.axis, vsoa_hdr,
                          payload, NULL, NULL);
}

使用发布订阅宏验证

结合 JStruct 自动生成的代码,在实现发布订阅时可以使用 VSOA_PARAM_SYNCER_PUBLISH 宏直接将 /axis 的资源发布出去。请参考如下代码片段:

url.url     = "/axis";
url.url_len = strlen(url.url);
VSOA_PARAM_SYNCER_PUBLISH(server.server, &url, axis, &server.data.axis,
                          NULL, 0);

RPC 与发布订阅完整验证

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "vsoa_server.h"
#include "vsoa_syncer.h"
#include "vsoa_platform.h"
#include "axis_jstruct.h"

/* My server remote client keep alive */
#define MY_SERVER_CLI_KEEPALIVE true

/* My server password */
#define MY_SERVER_PASSWD "123456"

/* My server type */
typedef struct {
    vsoa_server_t *server;
    struct axis    data;
} my_server_t;

/* My server */
static my_server_t my_server;

/*
 * Command '/axis' routine
 */
static void command_axis (void *arg, vsoa_server_t *server, vsoa_cli_id_t cid,
                          vsoa_header_t *vsoa_hdr, vsoa_url_t *url,
                          vsoa_payload_t *payload)
{
    VSOA_PARAM_SYNCER_RPC(server, cid, axis, &my_server.data, vsoa_hdr,
                          payload, NULL, NULL);
}

#if MY_SERVER_CLI_KEEPALIVE
/*
 * Remote client connect keep alive
 */
static void on_cli (void *arg, vsoa_server_t *server, vsoa_cli_id_t id,
                    bool connect)
{
    if (connect) {
        vsoa_server_cli_keepalive(server, id, 5);
    }
}
#endif /* MY_SERVER_CLI_KEEPALIVE */

/*
 * main function
 */
int main (int argc, char **argv)
{
    int  cnt;
    int  max_fd;
    fd_set   fds;
    vsoa_url_t  url;

    struct sockaddr_in addr;
    struct timespec timeout = { 1, 0 };

    my_server.data.roll  = 30;
    my_server.data.pitch = 40;
    my_server.data.yaw   = 50;

    bzero(&addr, sizeof(struct sockaddr_in));
    addr.sin_family      = AF_INET;
    addr.sin_port        = htons(3002);
    addr.sin_addr.s_addr = INADDR_ANY;

#ifdef VSOA_HAS_SIN_LEN
    addr.sin_len = sizeof(struct sockaddr_in);
#endif

    my_server.server = vsoa_server_create("{\"name\":\"axis_server\"}");
    if (!my_server.server) {
        fprintf(stderr, "Can not create VSOA server!\n");
        return    (-1);
    }

#if MY_SERVER_CLI_KEEPALIVE
    vsoa_server_on_cli(my_server.server, on_cli, NULL);
#endif

#ifdef MY_SERVER_PASSWD
    vsoa_server_passwd(my_server.server, MY_SERVER_PASSWD);
#endif

    url.url     = "/axis";
    url.url_len = strlen(url.url);
    vsoa_server_add_listener(my_server.server, &url, command_axis, NULL);

    if (!vsoa_server_start(my_server.server,
                           (struct sockaddr *)&addr,
                           sizeof(struct sockaddr_in))) {
        vsoa_server_close(my_server.server);
        fprintf(stderr, "Can not start VSOA server!\n");
        return    (-1);
    }

    while (1) {
        FD_ZERO(&fds);
        max_fd = vsoa_server_fds(my_server.server, &fds);

        cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL);
        if (cnt > 0) {
            vsoa_server_input_fds(my_server.server, &fds);
        }

        url.url     = "/axis";
        url.url_len = strlen(url.url);
        VSOA_PARAM_SYNCER_PUBLISH(my_server.server, &url, axis,
                                  &my_server.data, NULL, 0);
    }

    return    (0);
}

注意

  • JStruct 工具自动生成的结构体中不带有对应的初始化或构造函数。因此,在 C 语言程序开发过程中,需要对创建的结构体对象中的每一个字段进行初始化,以免使用了错误的数据。
  • 特别的,对于数据类型是 char * 类型的字段,在使用过程中需要将其置空或者赋值。
文档内容是否对您有所帮助?
有帮助
没帮助