# yutWebsAgent
**Repository Path**: cmajor-cd/yutWebsAgent
## Basic Information
- **Project Name**: yutWebsAgent
- **Description**: Customization guide demo(ajax/goAction), based on goAhead project.
- **Primary Language**: C
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2020-01-03
- **Last Updated**: 2021-11-23
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
[TOC]
# 项目情况简介
* 本项目是基于 goAhead 开源 web server。goAhead官方文档 https://www.embedthis.com/goahead/doc/ref/api/goahead.html
* 本项目以 ***makefile*** 方式构建项目,同时相关脚本文件以 ***`bash`*** 编写,所以代码最好在 ***`Linux`*** 下进行编译调试或者 ***`Windows10-WSL`*** 方式运行。
* 本项目对goAhead 进行了解耦封装,您只需要 6 步 就可以完成自己的定制工作。细节见 ***`B. 如何定制自己的 server `***
# A. Demo使用方法
## A.1. 准备环境
1. 准备Linux环境
* **方法一Linux**:准备好Linux下的工作目录
* **方法二Windows**:打开Windows10-WSL Ubuntu环境并准备好工作目录
2. clone代码
```
https://gitee.com/cmajor-cd/yutWebsAgent.git
https://github.com/cmajor-cd/yutWebsAgent.git
```
## A.2.体验demo
1. 进入 main 目录
2. 编译
3. 发布/安装bin文件
4. 运行 server
5. 运行 web client: 打开浏览器输入 http://127.0.0.1:8080/index.html
```
$ cd ./yut_webs_agent_src
(如果要体验 goAhead 原生非解耦 demo 则:cd demo_howto_customize_by_goahead_mk/)
$ sudo ./build.sh
$ sudo ./releaseGo.sh
goahead: 2: Configuration for Embedthis GoAhead Community Edition
goahead: 2: ---------------------------------------------
goahead: 2: Version: 5.1.0
goahead: 2: BuildType: Release
goahead: 2: CPU: x64
goahead: 2: OS: linux
goahead: 2: Host: 127.0.1.1
goahead: 2: Directory: /mnt/d/workspace/VS/yutWebsAgent/release/webserver
goahead: 2: Documents: /mnt/d/workspace/VS/yutWebsAgent/yut_webs_agent_src/../release/webroot
goahead: 2: Configure: me -d -q -platform linux-x86-default -configure . -gen make
goahead: 2: ---------------------------------------------
goahead: 2: Started http://0.0.0.0:8080
```
# B. 如何定制自己的 server
1. 规划定义接口API命令和处理函数(即:路由)
* goAhead 缺省定义根路由为 '/action/';用户自己定义的路由连接到根路由后面,e.g. '/action/my_req_path'
* demo 假设用户定义了API命令 'setCfgInfor'、对应处理函数为 'func_SET_CFG_INFOR(cJSON *json_in, cJSON *json_out);'
* 注意:处理函数的参数必须为(cJSON *json_in, cJSON *json_out)
* 如果您想注册不同输入参数,请修改 file:webs_agent_main.c / line239.
2. 注册API命令到系统回调表中(file:regist_router_api.h)
* 添加命令字到枚举类型 enum t_regist_router_api_number 中, e.g. '_setCfgInfor'
* 添加命令字 vs 处理函数 到 m_api_callback[] 中, e.g. {"setCfgInfor", func_SET_CFG_INFOR}
3. 实现API函数
* ./api/api.c 和 ./hal/hal.c 中demo了如何实现API函数以及其可能所需的访问硬件的hal层代码
* 如果您要在自己定义的目录中实现API,请注意参考./api/makefile 定义。
4. 编译/运行
* 确定运行平台:在 'webs_agent_gohead_cust.mk' 中配置 ARCH 和 CC
* build.sh / releaseGo.sh
5. web client 的代码如何处理
* 可以将开发好的 web client 代码放在 ./demo_ajax_websrc 中,运行 source ./releaseGo.sh 时会自动部署
* 如果您要放到您自己的目录,请修改 releaseGo.sh 脚本中的 $build_webs_root_dir
* 如果不需要自动部署web代码,您可以自行将web代码拷贝到 ./release/webroot
6. 运行调试 web client: 打开浏览器输入 http://127.0.0.1:8080/index.html
--------------------
--------------------
# 了解更多细节
如果需要了解具体代码的处理细节和makefile的修改细节,请参考以下章节:
## 子项目1:yutWebsAgentDemo
直接基于goAhead的代码和 makefile 的定制指南。
此子项目 demo 了如何直接从 goAhead 的源代码和 makefile 基础上进行定制的方法。
使用这种方法可以保持 goAhead 的原始做法,相对简单,但不利之处是对自己的定制代码与 goAhead 相互侵入,不利于维护。
此子项目所有代码和 makefile 文件在目录 ***`./demo_howto_customize_by_goahead_mk`***中。
代码中所有重要的修改处都以 ***yutWebsAgentDemo*** 作为标记以方便大家阅读比较。
* #### 详细内容=> [yutWebsAgentDemo定制细节](#Project_yutWebsAgentDemo)
## 子项目2:yut_webs_agent
此项目将定制代码与 goAhead 代码进行了解耦。
对goAhead的 makefile 进行了较多改造,集成了 ajax 交互方式的所有 web/api/hal 层的演示。您可以直接将其替换为自己的 web 和 api/hal 代码实现一个完整的嵌入式 wesAgent服务。
此子项目所有代码和 makefile 文件在目录 ***`./yut_webs_agent_src 和 ./ yut_webs_agent_websrc`*** 中。
代码中所有重要的修改处都以 ***yut_webs_agent*** 作为标记以方便大家阅读比较。
* #### 详细内容=> [yut_webs_agent定制细节](#Project_yut_webs_agent)
------------------------
# demo代码如何运行
1. 准备环境
* **方法一Linux**:准备好Linux下的工作目录
* **方法二Windows**:打开Windows10-WSL Ubuntu环境并准备好工作目录
2. clone代码
```
https://gitee.com/cmajor-cd/yutWebsAgent.git
https://github.com/cmajor-cd/yutWebsAgent.git
```
3. 进入源码目录并运行编译和发布脚本
```
$ cd demo_howto_customize_by_goahead_mk/
$ ./build.sh
$ ./releaseGo.sh or sudo ./releaseGo.sh
```
系统显示处如下log意味着运行成功。
```
yangyt@DESKTOP-MI7438E:/mnt/d/workspace/demo_howto_customize_by_goahead_mk$ ./releaseGo.sh
[sudo] password for yangyt:
goahead: 2: Configuration for Embedthis GoAhead Community Edition
goahead: 2: ---------------------------------------------
goahead: 2: Version: 5.1.0
goahead: 2: BuildType: Debug
goahead: 2: CPU: x64
goahead: 2: OS: linux
goahead: 2: Host: 127.0.1.1
goahead: 2: Directory: /mnt/d/workspace/VS/yutWebsAgent/release/webserver
goahead: 2: Documents: /mnt/d/workspace/VS/yutWebsAgent/demo_howto_customize_by_goahead_mk/../release/webroot
goahead: 2: Configure: me -d -q -platform linux-x86-default -configure . -gen make
goahead: 2: ---------------------------------------------
goahead: 2: Started http://0.0.0.0:8080
```
4. 检查web运行情况。
* 打开浏览器并输入地址: `http://127.0.0.1:8080/demo.html`
* 显示demo页面
用form提交数据=>form
用ajax刷新=>触发getNetworkCfgInfor()
------------------------
# 目录说明
```
yutWebsAgent
├── build
│ ├── bin
│ ├── inc
│ └── obj
├── demo_howto_customize_by_goahead_mk
│ ├── build.sh
│ ├── releaseGo.sh
│ ├── webroot
│ │ ├── demo.html
│ │ ├── demo.js
│ ├── yut_webs_agentdemo.c
│ └── yut_webs_agentdemo.mk
├── goahead_src
│ ├── projects
│ │ ├── goahead-linux-default-me.h
│ │ ├── goahead-linux-default.mk
├── libs
├── release
│ ├── webroot
│ └── webserver
├── yut_webs_agent_src
│ ├── api
│ ├── hal
└── yut_webs_agent_websrc
```
1. **goahead_src**
* goahead的官方源代码。
* 该目录被 build.sh 引用。
* 如果要改动需要同步变更 build.sh 脚本中定义的:```$goahead_src_dir / $goahead_src_projects_dir```
2. **demo_howto_customize_by_goahead_mk**
* ***子项目1*** 的演示代码目录
* 移植定制文件目录,您可以变更为您自己的目录名。
* 如果要改动 **该目录名** 需要同步变更同级目录下的makefile文件``yut_webs_agentdemo.mk`` 脚本中的```SRC_CODE_DIR```定义。
* 该目录包含的文件
* source files
* makefile文件: 缺省的mk文件名为```yut_webs_agentdemo.mk```,该文件需与`build.sh`脚本中的``$mk_filename``定义保持一致。
* build.sh编译脚本文件,该脚本定义了build-make方法,请注意定制是保证以下内容正确:
```
goahead_src_dir="../goahead_src"
goahead_src_projects_dir="../goahead_src/projects"
build_dir="../build"
mk_filename="yut_webs_agentdemo.mk"
```
* releaseGo.sh调试发布脚本文件,该脚本将自定义的源文件编译完成并将最终的bin文件和相关文件+web app代码发布到``./release``目录下,请注意定制是保证以下内容正确:
```
rel_webs_bin_dir="../release/webserver"
rel_webs_root_dir="../release/webroot"
build_bin_dir="../build/bin"
build_webs_root_dir="./webroot"
build_bin_filename="yut_webs_agentdemo.bin"
goahead_src_dir="../goahead_src"
```
* 该目录中的子目录
* webroot: web app的源代码目录,请保证**该子目录名**与`releaseGo.sh`脚本中的``$build_webs_root_dir``保持一致。
3. **yut_webs_agent_src**
* ***子项目2*** ***yut_webs_agent*** 的 .c / makefile 代码演示代码目录。
* 其文件组成与***子项目1***类似。
4. yut_webs_agent_websrc
* ***子项目2*** ***yut_webs_agent*** 的 web 代码演示代码目录。
5. libs
* 3方库文件存放目录。
* 该**目录名**需要与``yut_webs_agentdemo.mk/webs_agent.mk`` 脚本中的```LIBS_3rd```定义保持一致。
6. build
build.sh编译脚本,编译定制代码后的输出文件存放目录。
7. release
`releaseGo.sh`发布编译结果所在的文件目录。
注意:如果是最终发布,需要确保``./release/webroot/``中的web app代码已经编译过。因为```releaseGo.sh```没有检查本web app的代码是否已经编译过!
------------------------
# 子项目yutWebsAgentDemo定制说明
此子项目 demo 了如何直接从 goAhead 的源代码和 makefile 基础上进行定制的方法。
使用这种方法可以保持 goAhead 的原始做法,相对简单,但不利之处是对自己的定制代码与 goAhead 相互侵入,不利于维护。
## 1.构建项目定制源代码目录
* 按照demo的目录结构构建自己的目录
* 可以简单的 ``git clone``,也可以手工构建。
* 将子目录名 ``yut_webs_agentdemo`` 改为自己的目录名,该目录存放自己的代码文件。
* 构建自己的makefile文件
* 参考demo中的 ``yut_webs_agentdemo.mk`` 创建自己的makefile文件。请注意该makefile文件的模板来自于``../goahead/projects``,您可以直接copy其中合适的mk文件过来并修改为**自定义文件名**。
* 修改`build.sh`文件
* 修改 ``build.sh`` 脚本中的 ``$mk_filename`` 为与上一节相同的**自定义文件名**。
* 以本目录为base确保以下路径和目录名定义正确。
```
goahead_src_dir="../goahead_src"
goahead_src_projects_dir="../goahead_src/projects"
```
* 修改``releaseGo.sh``文件,请注意定制是保证以下内容正确:
* 修改 ``releaseGo.sh`` 脚本中的 ``$build_bin_filename`` 为与希望生成的最终bin文件的**自定义文件名**相同。
* 以本目录为base确保以下路径和目录名定义正确。
```
rel_webs_bin_dir="../release/webserver"
rel_webs_root_dir="../release/webroot"
build_bin_dir="../build/bin"
build_webs_root_dir="./webroot"
build_bin_filename="yut_webs_agentdemo.bin"
goahead_src_dir="../goahead_src"
```
## 2.定制makefile文件
### 2.1.行为说明
编译中 ``build.sh`` 脚本会将makefile文件拷贝到 ``$goahead_src_projects_dir`` 中,并执行make。
### 2.1.定制方法
* **PROFILE**
如果是按照goahead官方的方法定制, build目录将在goahead目录下,该参数将影响**$CONFIG**,最终决定了build的目录位置。
在使用本方法定制时,我们更改了build目录位置到父一级目录,所以该参数无意义。
* **ARCH**
根据具体的情况来定义,比如:`ARCH ?=arm`
* **CC**
根据具体的情况来定义。
* 比如,在Ubuntu下调试可以设置为:`CC ?= gcc`
* 比如,在ARM下调试可以设置交叉编译环境为:`CC ?=arm-fsl-linux-gnueabi-gcc`
* **BUILD**
为了方便组织代码和调试,我们将 `$BUILD` 设置到父一级目录,同时为了添加**三方库**和方便组织**定制源码**需要增加两个变量 `$LIBS_3rd / $SRC_CODE_DIR`。
```
BUILD ?= ../build
LIBS_3rd ?= ../libs
SRC_CODE_DIR ?= ../yut_webs_agentdemo
```
***注意***:`$SRC_CODE_DIR` 需要与您的**定制源码子目录**保持一致!
* **开放和关闭官方模块**
可以通过设置相应的项为``1/0``来开放或关闭官方提供的独立模块。
比如:关闭SSL模块
``ME_COM_SSL ?= 0``
* **TARGETS**
根据自己的规划定义build输出bin文件信息:
```
TARGETS += $(BUILD)/bin/yut_webs_agentdemo.bin
```
***注意***:`yut_webs_agentdemo.bin` 需要与您在后面设置的**link输出bin文件名**保持一致!
* **clean:**
将自己添加的`libs`以及`定制源文件`编译的中间文件和输出文件名加入`clean`中,以达成`make clean`操作时能够清理相关文件。
```
rm -f "$(BUILD)/obj/yut_webs_agentdemo.o"
rm -f "$(BUILD)/obj/cJSON.o"
rm -f "$(BUILD)/bin/yut_webs_agentdemo.bin"
```
* **compile lib / source files**
仿照mk文件中其他`lib`和`source files`的编写方式编写新的`lib`和`soure files`编译脚本。
***注意:***
* mk变量定义要唯一,如:`DEPS_yut_cjson_1` 和 `DEPS_yut_main_1`
* lib库路径和soure files路径要正确,如:`$(LIBS_3rd)` 和 `$(SRC_CODE_DIR)`
* **link lib / source files**
仿照mk文件中其他`goahead-test`的编写方式编写新的`TARGETS`链接输出脚本。
***注意:***
* mk变量定义要唯一,如:`DEPS_yut_main_x`
* TARGETS的名字要正确,如:`yut_webs_agentdemo.bin`
* **other link output**
对官方提供其他 features 的链接输出配置,可以根据具体的需求保留相关配置或者注释掉。
比如,样例mk中将 `gopass` 注释掉后,该模块不再 `link` 出目标bin文件。
## 3.定制 main.c(goAction方式)的功能代码
作为样例的main.c文件 yut_webs_agentdemo.c,来自于goAhead官方的样例文件 ./goahead_src/test.c。其中有一些不需要内容已经删除,保留了主要的、与goAction编程相关的以便于作为demo阅读。
### 3.1.action处理函数声明和注册
* **声明action处理函数**
在文件头部声明action处理函数,如:
```
static void actionWebsAgentDemoEntry(Webs *wp);
```
* **注册action处理函数**
在`main()`函数中注册action处理函数,如:
```
websDefineAction("yutWebsAgentDemoEntry", actionWebsAgentDemoEntry);
```
* **action函数编写样例**
```
//yutWebsAgentDemo
//static void actionTest(Webs *wp);
static void actionWebsAgentDemoEntry(Webs *wp);
/****** Code *******/
MAIN(goahead, int argc, char **argv, char **envp)
{
/*argc 处理过程略... */
/*initPlatform() 处理过程略.. */
//yutWebsAgentDemo
//1. regist the yutWebsAgentDemoEntry in web url
//2. define the function for this entry
websDefineAction("yutWebsAgentDemoEntry", actionWebsAgentDemoEntry);
//
if (duration) {
printf("Running for %d secs\n", duration);
websStartEvent(duration * 1000, (WebsEventProc) exitProc, 0);
}
websServiceEvents(&finished);
logmsg(1, "Instructed to exit\n");
websClose();
return 0;
}
```
### 3.2.action处理函数实现(form提交方式)
#### 3.2.1.FORM技术特点
form data 是html技术中常用的数据提交和刷新方式,它的主要特点如下:
* ***全页面*** 刷新。
* 它的html代码形态,样例:
```
```
* 它的http数据格式,样例:```command=submitNameValue&name=&address=&submit=submit```
#### 3.2.1.goAction处理方式
goAction提供了API函数可以直接处理FORM样式数据。样例如下:
```
int SUBMIT_NAME_VALUE_func(Webs *wp){
cchar *name, *address;
name = websGetVar(wp, "name", NULL);
address = websGetVar(wp, "address", NULL);
websSetStatus(wp, 200);
websWriteHeaders(wp, -1, 0);
websWriteEndHeaders(wp);
websWrite(wp, "demo name: %s, demo address: %s
\n", name, address);
websFlush(wp, 0);
websDone(wp);
}
```
### 3.3.action处理函数实现(ajax提交方式)
大多数web页面都要求进行局部刷新,所以处理ajax是必不可少的能力。goAhead官方没有提供直接的API来处理ajax。但它的API结构中有名为`Webs`的数据结构,其保存了所有的`http消息`信息,我们可以通过Webs中的数据来处理ajax请求。
#### 3.3.1.导入cJSON库
外部三方库的引入方式前面章节已经详细讲解,请直接参考前面章节。
#### 3.3.2.获取输入数据buff
我们可以通过goAction提供的API函数 `bufLen() / bufGetBlk() `来获取Webs中原始数据。
* 获取输入http数据缓冲区:`wp->input`
* 获取缓冲区数据用于后续处理: buff中即是获取的`json`数据包。
```
//* get input buff
char buff[MAX_INPUT_BUFF];
int len = bufGetBlk(&(wp->input), buff, bufLen(&(wp->input)));
buff[len] = '\0'; //插入结束符
```
#### 3.3.3.转换json数据到value
我们使用`cJSON`的API函数来完成转换工作。
```
cJSON* p_json_root = NULL;
cJSON* p_json_node = NULL;
char* p_json_node_value;
//
/* get input buff
* => buff[len] 已经就绪
*/
//* decode json object by cJSON libs' api
p_json_root = cJSON_Parse(buff);
if(!p_json_root)
{
printf("Error[actionWebsAgentDemoEntry] : [%s]\n", cJSON_GetErrorPtr());
return;
}
else
{
p_json_node = cJSON_GetObjectItem(p_json_root, JSON_COMMAND);
p_json_node_value = cJSON_GetStringValue(p_json_node);
printf("Log[ajax-command] : [%s]\n", p_json_node_value);
/* p_json_node_value 中即为与 JSON_COMMAND 对应的Value //#define JSON_COMMAND "command"
*/
...后续处理代码
}
```
#### 3.3.4.打包json数据回传web app
* **构建 response json包**
* response包的格式定义如下:
```
//echo result JSON格式:
{ "rc: 0/1,
"errCode: "error msg txt",
"dat:{"key1":"xxValue"}
}
```
* 利用cJSON库的API打包
```
#define JSON_DAT "dat"
#define JSON_ERRCODE "errCode"
#define JSON_RC "rc"
#define KEY_NAME "name"
#define KEY_PWD "pwd"
...
cJSON* _root = cJSON_CreateObject(); // create the root
cJSON* _next = cJSON_CreateObject();
cJSON_AddItemToObject(_root, JSON_DAT, _next); //create the node. "dat"
// write the echo result
// 1. fill the "dat".
cJSON_AddItemToObject(_next, KEY_NAME, cJSON_CreateString("demo value"));
cJSON_AddItemToObject(_next, KEY_PWD, cJSON_CreateString("demo pwd"));
// 2. fill the "rc"
int rc = 0; // success rc
cJSON_AddItemToObject(_root, JSON_RC, cJSON_CreateNumber(rc));
// 3. fill the "errCode"
strcat(errCode, "no error!");
cJSON_AddItemToObject(_root, JSON_ERRCODE, cJSON_CreateString(errCode));
printf("Log[ajax-ret] : [%s]\n", cJSON_Print(_root));
```
* **打包到 http 消息中回传**
此处利用goAction的API函数完成打包http并回传。
```
...
printf("Log[ajax-ret] : [%s]\n", cJSON_Print(_root));
// 4. fill the goAction webs return.
websSetStatus(wp, 200);
websWriteHeaders(wp, -1, 0);
websWriteEndHeaders(wp);
websWrite(wp, "%s", cJSON_Print(_root));
websFlush(wp, 0);
websDone(wp);
```
* **完整处理代码**
```
//-- define the json dat, key name.
#define KEY_NAME "name"
#define KEY_PWD "pwd"
int GET_NET_CFG_func(cJSON* json_node, Webs *wp){
cJSON* _root = cJSON_CreateObject(); // create the root
cJSON* _next = cJSON_CreateObject();
cJSON_AddItemToObject(_root, JSON_DAT, _next); //create the node. "dat"
int rc = 0;
char errCode[100] = "";
char* value;
// write the echo result
// 1. fill the "dat".
cJSON_AddItemToObject(_next, KEY_NAME, cJSON_CreateString("demo value"));
cJSON_AddItemToObject(_next, KEY_PWD, cJSON_CreateString("demo pwd"));
cJSON_AddItemToObject(_next, JSON_COMMAND, cJSON_CreateString(_json_node_value));
// 2. fill the "rc"
rc = 0; // success rc
cJSON_AddItemToObject(_root, JSON_RC, cJSON_CreateNumber(rc));
// 3. fill the "errCode"
strcat(errCode, "no error!");
cJSON_AddItemToObject(_root, JSON_ERRCODE, cJSON_CreateString(errCode));
printf("Log[ajax-ret] : [%s]\n", cJSON_Print(_root));
// 4. fill the goAction webs return.
websSetStatus(wp, 200);
websWriteHeaders(wp, -1, 0);
websWriteEndHeaders(wp);
websWrite(wp, "%s", cJSON_Print(_root));
websFlush(wp, 0);
websDone(wp);
}
```
## 4.定制web app内容
web app定制主要在demo.js中完成,有以下要点。
### 4.1. 格式化json传输格式
需要打包json数据为json字符串形式以方便http传输。
```
var str = {
"command":"getNetworkCfgInfor"
}
parameters = JSON.stringify(str);
```
### 4.2. 定义正确的ajax接收格式
需要定义为`dataType: 'json'`。
在调试时如果出现问题,可以尝试将其改为`dataType: 'text'`,以便查看返回的具体内容。
### 4.3. 定义正确的action处理url地址
此处需要与您在`main()`中注册的地址完全一致,ajax包才能被正确的路由到goAction注册函数处理。例如我们样例代码中的 ***yutWebsAgentDemoEntry***
```
//yutWebsAgentDemo
//1. regist the yutWebsAgentDemoEntry in web url
//2. define the function for this entry
websDefineAction("yutWebsAgentDemoEntry", actionWebsAgentDemoEntry);
```
### 4.4. 完整的ajax处理函数样例
```
function getNetworkCfgInfor(){
var str = {
"command":"getNetworkCfgInfor"
}
parameters = JSON.stringify(str);
$.ajax({
type:"POST",
url: "/action/yutWebsAgentDemoEntry",
data: parameters,
contentType: 'application/json',
dataType: 'json',//'text'
success: function(res){
var data = res;
if(0 == data.rc){
let textDiv = 'SUCCESS!!
'+' DemoCommand:'+ data.dat.command+'
DemoName:'+ data.dat.name+'
DemoPwd:'+data.dat.pwd+'
';
console.log('getNetworkCfgInfor, succ.=>'+textDiv);
$("#myDemoText").append(textDiv);
}
else{
console.log('data.errCode::'+data.errCode);
}
},
error: function (errorThrown) {
console.log('ajax error');
console.log(errorThrown);
}
});
}
```
------------------------
# 子项目yut_webs_agent定制说明
此项目将定制代码与 goAhead 代码进行了解耦。
对goAhead的 makefile 进行了较多改造,集成了 ajax 交互方式的所有 web/api/hal 层的演示。您可以直接将其替换为自己的 web 和 api/hal 代码实现一个完整的嵌入式 wesAgent服务。
此子项目所有代码和 makefile 文件在目录 ***`./yut_webs_agent_src 和 ./ yut_webs_agent_websrc`*** 中。
#### ***注意:*** 所有需要您关注的关键定制点都以 ***`TODO`*** 标记了出来!
## 1. 数据流图
```mermaid
graph LR;
a[web ajax]-->b{goAhead};
b-->|http service|c(goAhead http);
b-->|api service|d(websAgent);
d-->e(api layer);
d-->f(hal layer);
f-->g(bsp driver)
```
## 2. 构建项目定制源代码目录
* 构建自己的 webs_agent_src 框架源码**主目录`./yut_webs_agent_src`**,可直接参照本项目的目录结构。主目录内存放以下内容:
* main.c 文件(```webs_agent_main.c```)和它的 .h 头文件。该文件名如果与缺省不一致,请对应修改makefile文件中***对应的文件/目标名***。
* makefile文件(```webs_agent.mk```),该文件名可以自己定义。
* 框架子目录
* ```api```应用接口层:该目录存放api层代码,该层从硬件驱动(通过```hal层```)获取/操作硬件数据,用于完成对 ajax 请求中个各条命令的一一响应。
* ```hal```设备抽象层:该目录存放hal层代码,该层通过硬件驱动获取/操作底层硬件,提供给 api 层访问设备硬件的能力。
* `build.sh`文件
* 本脚本运行时会将定制好的 goAhead makefile 文件拷贝到 `goAhead_src/projects`,然后在本目录运行自己的 makefile 文件``webs_agent.mk``。
* 脚本中的路径定义都是以本目录(`./yut_webs_agent_src`)为base来确定的,请确保各路径和目录名定义正确。
* ``releaseGo.sh``文件
* 本脚本运行时会构建 `release 目录`,并将 `build 目录` 中必须文件拷贝到 `release 目录` 中。然后启动bin文件运行并监听本地 8080 端口用于测试。
* 以本目录为base确保以下路径和目录名定义正确。
```
rel_webs_bin_dir="../release/webserver"
rel_webs_root_dir="../release/webroot"
build_bin_dir="../build/bin"
build_webs_root_dir="../yut_webs_agent_websrc"
build_bin_filename="yut_webs_agent.bin"
goahead_src_dir="../goahead_src"
```
## 3. 构建 api/hal 层代码
目录结构参考**主目录`./yut_webs_agent_src/api 和 hal`**。
本层的代码可以自由组织,需要注意的是子目录下的 makefile 的组织:
* makefile的文件名必须是`makefile`,以便于上一级makefile自动调用。
* 本级 makefile 中的 `.h` 会被 `build.sh` 脚本自动拷贝到 `../build/inc` 中。
* 本机的所有 `.c` 文件及其对应的 `.o` 文件需要手工添加到 makefile 的依赖列表中。
## 4. 构建 webs_agent_main.c 代码
本文件的来源细节可以查看 [子项目1:yutWebsAgentDemo`](#Project_yutWebsAgentDemo_main_c) 中的说明。
该文件主要的定制处以 `TODO` 标记,完成以下工作:
* 定义goAction回调函数 `static void action_webs_agent(Webs *wp);`
* 注册回调函数 `websDefineAction("webs_agent", action_webs_agent);`
* 定制回调函数,将自己的 `api` ajax接口处理函数添加进去。
```
if(!strcasecmp(p_json_node_value, SET_CFG_INFOR)){
func_SET_CFG_INFOR(p_json_in, p_json_out);
}else if(!strcasecmp(p_json_node_value, GET_CFG_INFOR)){
func_GET_CFG_INFOR(p_json_in, p_json_out);
}
```
* goAction 相关的调用方法和 `cJson` 数据的处理细节可以参考 [子项目1:yutWebsAgentDemo`](#Project_yutWebsAgentDemo_cjson) 中对 `ajax cjson` 数据处理的说明。
## 5. 构建 web 代码
目录结构参考**主目录`./yut_webs_agent_websrc`**。
该目录中包括了所有的 webapp 内容,可以自由组织,该目录的编写需要注意以下问题:
* `webapp`编译发布目录如果有自己定制,请对应修改 `releaseGo.sh` 中的宏定义 `$build_webs_root_dir`,该脚本会将最终编译出的 `webapp` 代码发布到最终发布目录。
## 6. 构建 makefile
### 6.1 本项目 makefile 文件
* 主控makefile位于目录 `./yut_webs_agent_src`,文件名为 `webs_agent_main.mk` 该文件名可以自己定义。
* 主控makefile运行中调用每个子目录下的子makefile。调用过程是自动的,所以子目录下的makefile文件的文件名必须是 ***`makefile`***
* 主控makefile的内容定制方法主要点都以 `TODO` 进行了标记。
* 根据需要定制编译平台和编译选项 `1. TODO`
* 根据需要定制/添加其他外部模块,包括三方 Liabs 的路径 `2. TODO`
* 根据需要定制/修改需要链接的 .o/.a 目标和库文件名 `3. TODO`
### 6.2 定制 goAhead makefile 文件
* 文件名 `webs_agent_gohead_cust.mk`,该文件会在编译时由 `build.sh` 拷贝到 `../goahead_src/projects` 中并改名为 `makefile`。
* 因为本项目框架对 goAhead 的代码和 makefile 进行了解耦,所以一般情况不需要再次定制 goAhead 的 makefile。该文件必须的定制处已经做了必要的定制,如需修改请对照 goAhead 的官方 makefile 进行修改。