From 5fdfc0434957ba70b8b4ce983b873ef6b047b375 Mon Sep 17 00:00:00 2001 From: Yu Sun Date: Mon, 11 Jul 2022 23:58:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=B1=BB=E5=9E=8B=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=EF=BC=8C=E4=B8=94=E5=85=81=E8=AE=B8=E6=B7=B7=E5=90=88?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- EdgeManager.php | 231 +++++++++++++++++----------- README.md | 35 ++++- app/EDataCapture/EDataCapture.php | 91 ++++++++--- app/EDataCapture/ENodeConfigure.php | 4 +- 4 files changed, 244 insertions(+), 117 deletions(-) diff --git a/EdgeManager.php b/EdgeManager.php index 9e4201f..8aca6c6 100644 --- a/EdgeManager.php +++ b/EdgeManager.php @@ -24,43 +24,83 @@ $worker -> onWorkerStart = function(Worker $worker) { $worker -> onMessage = function(TcpConnection $connection, Request $request) { global $options, $dbconn; - // 仅供Axios使用 + // 先预处理POST内容 if ($request->header('content-type') === 'application/json') { $post = $request -> post(); - if (isset($post['action']) and str_contains($post['action'], 'node')) { - $action = $post['action']; - unset($post['action']); - $enode_configure = new ENodeConfigure($dbconn, post: $post); - $res = $enode_configure -> $action(); - if ($res === true) - $connection -> send(json_encode(array( - 'code' => 0, - 'msg' => 'Success' - ))); - else if ($res === "REPLICATED") - $connection -> send(json_encode(array( - 'code' => 1, - 'msg' => '节点编码不可重复!' - ))); - else if ($res === false) { - $connection -> send(json_encode(array( - 'code' => 1, - 'msg' => '服务器内部逻辑错误,请联系开发者!' + } else { + $body = $request -> rawBody(); + if ($body === "") { + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], "空请求!"); + $connection -> send($response); + } else { + $post = json_decode($request -> rawBody()); + if (json_last_error() !== JSON_ERROR_NONE) { + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], json_encode(array( + 'action' => '错得太离谱以至于我也不知道这是什么动作', + 'errcode' => 4001, + 'errmsg' => 'POST的内容不是JSON,也并非可按照JSON解析的字符串!或者检查一下你的JSON是不是有注释?' ))); + $connection -> send($response); } } - } else { - $post = json_decode($request -> rawBody()); - if (json_last_error() !== JSON_ERROR_NONE) - dump('fuck'); - $connection -> send(json_encode(array( - 'action' => '错得太离谱以至于我也不知道这是什么动作', - 'errcode' => 4001, - 'errmsg' => 'POST的内容不是JSON,也并非可按照JSON解析的字符串!' - ))); - dump($post); + } + + if (is_array($post)) { + if (count($post) !== 0) { + // Axios:发送的POST是array + if (is_array($post) and isset($post['action'])) { + if (str_ends_with($post['action'], 'node')) { + // 用这种方式自动匹配调用和action相对应的方法 + $action = $post['action']; + unset($post['action']); + $enode_configure = new ENodeConfigure($dbconn, post: $post); + $res = $enode_configure -> $action(); + if ($res === true) + $connection -> send(json_encode(array( + 'code' => 0, + 'msg' => 'Success' + ))); + else if ($res === "REPLICATED") + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => '节点编码不可重复!' + ))); + else if ($res === false) { + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => '服务器内部逻辑错误,请联系开发者!' + ))); + } + } + } + } + } else if (isset($post -> action)) { if ($post -> action === 'set_node_data') { $data_capture = new EDataCapture($dbconn, post: $post); + if ($data_capture -> check_res === 'WRONG_WORKING_SUBCLASS') { + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], json_encode(array( + 'action' => 'result_set_node_data', + 'errcode' => 4002, + 'errmsg' => '未登记过的工序单元!' + ))); + $connection -> send($response); + } + if ($data_capture -> check_res === 'MISMATCH_TYPE') { + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], json_encode(array( + 'action' => 'result_set_node_data', + 'errcode' => 4002, + 'errmsg' => '节点编码和数值类型不匹配!' + ))); + $connection -> send($response); + } $res = $data_capture -> set_node_data(); if ($res === true) { $connection -> send(json_encode(array( @@ -76,74 +116,89 @@ $worker -> onMessage = function(TcpConnection $connection, Request $request) { ))); } } else { - $connection -> send(json_encode(array( + // 有action,但是不知道是什么鬼动作 + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], json_encode(array( 'action' => $post -> action, 'errcode' => 4002, - 'errmsg' => '请检查传入的字段值!' + 'errmsg' => '同朕check check佢' ))); + $connection -> send($response); } + } else { + // action都无 + $response = new Response(200, [ + 'Content-Type' => 'application/json;charset=utf-8', + ], json_encode(array( + 'action' => '缺少action字段', + 'errcode' => 4001, + 'errmsg' => '你请求紧乜撚动作吖?' + ))); + $connection -> send($response); } $get = $request -> get(); - if (isset($get['query']) and $get['query'] == 'nodes') { - $enode_configure = new ENodeConfigure($dbconn, get: $get); - $nodes = $enode_configure -> get_nodes(); - if (is_null($nodes)) + if (isset($get['query'])) { + if ($get['query'] == 'nodes') { + $enode_configure = new ENodeConfigure($dbconn, get: $get); + $nodes = $enode_configure -> get_nodes(); + if (is_null($nodes)) + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => 'no node data yet' + ))); + else + $connection -> send(json_encode(array( + 'code' => 0, + 'data' => $nodes + ))); + } else if ($get['query'] == 'working_subclasses') { + $enode_configure = new ENodeConfigure($dbconn, get: $get); + $working_subclasses = $enode_configure -> get_working_subclasses($dbconn); + if (is_null($working_subclasses)) + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => '还没有工序单元!' + ))); + else + $connection -> send(json_encode(array( + 'code' => 0, + 'data' => $working_subclasses + ))); + } else if ($get['query'] == 'codes') { + $enode_configure = new ENodeConfigure($dbconn, get: $get); + $codes = $enode_configure -> get_codes_by_working_subclasses(); + if (is_null($codes)) + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => '服务器内部逻辑错误,请联系开发者!' + ))); + else + $connection -> send(json_encode(array( + 'code' => 0, + 'data' => $codes + ))); + } else if ($get['query'] == 'node_data') { + $data_capture = new EDataCapture($dbconn, get: $get); + $data = $data_capture -> get_node_data(); + if (is_null($data)) + $connection -> send(json_encode(array( + 'code' => 1, + 'msg' => '服务器内部逻辑错误,请联系开发者!' + ))); + else + $connection -> send(json_encode(array( + 'code' => 0, + 'data' => $data + ))); + } else { $connection -> send(json_encode(array( 'code' => 1, - 'msg' => 'no node data yet' + 'msg' => '你请求紧乜撚嘢啊?' ))); - else - $connection -> send(json_encode(array( - 'code' => 0, - 'data' => $nodes - ))); - } - - if (isset($get['query']) and $get['query'] == 'working_subclasses') { - $enode_configure = new ENodeConfigure($dbconn, get: $get); - $working_subclasses = $enode_configure -> get_working_subclasses(); - if (is_null($working_subclasses)) - $connection -> send(json_encode(array( - 'code' => 1, - 'msg' => '还没有工序单元!' - ))); - else - $connection -> send(json_encode(array( - 'code' => 0, - 'data' => $working_subclasses - ))); - } - - if (isset($get['query']) and $get['query'] == 'codes') { - $enode_configure = new ENodeConfigure($dbconn, get: $get); - $codes = $enode_configure -> get_codes_by_working_subclasses(); - if (is_null($codes)) - $connection -> send(json_encode(array( - 'code' => 1, - 'msg' => '服务器内部逻辑错误,请联系开发者!' - ))); - else - $connection -> send(json_encode(array( - 'code' => 0, - 'data' => $codes - ))); - } - - if (isset($get['query']) and $get['query'] == 'node_data') { - $data_capture = new EDataCapture($dbconn, get: $get); - $data = $data_capture -> get_node_data(); - if (is_null($data)) - $connection -> send(json_encode(array( - 'code' => 1, - 'msg' => '服务器内部逻辑错误,请联系开发者!' - ))); - else - $connection -> send(json_encode(array( - 'code' => 0, - 'data' => $data - ))); - } + } + } }; Worker::runAll(); diff --git a/README.md b/README.md index 26fe73a..118cbe3 100644 --- a/README.md +++ b/README.md @@ -18,18 +18,17 @@ **请求** -> 需保证每次传入数据的**工序单元(working subclass)和数值类型(type)** 一致。 -> -> 在此基础上尽量单次传入尽量多数据使得性能最大化。 +> 上位机程序中请单次传入尽量多的数据使得性能最大化。 > > 但仍需兼顾传输速率和超时时间。 +> +> 无需指定数值类型,服务端会自动根据已添加的节点信息检查,若不符则会报错。 ```json { "action": "set_node_data", "param": { "working_subclass": , - "type": "string" | "int" | "float" | "bool", "data": [ { "code": , @@ -56,17 +55,37 @@ ```json { - "action": "result_set_data", + "action": "result_set_node_data", "errcode": 0, "errmsg": "" } ``` -操作失败: +操作失败(**工序单元尚未登记**): ```json { - "action": "result_set_data", + "action": "result_set_node_data", + "errcode": 4002, + "errmsg": "未登记过的工序单元!" +} +``` + +操作失败(**数值类型错误**): + +```json +{ + "action": "result_set_node_data", + "errcode": 4002, + "errmsg": "节点编码和数值类型不匹配!" +} +``` + +操作失败(不明原因): + +```json +{ + "action": "result_set_node_data", "errcode": 4002, "errmsg": "ROLLBACKed: Bad data received (structure and/or values)" } @@ -115,7 +134,7 @@ yarn serve 客户端连接: ```bash -sudo apt install postgresql-client +# sudo apt install postgresql-client # 登入 psql -h localhost -U postgres # 显示数据库列表 diff --git a/app/EDataCapture/EDataCapture.php b/app/EDataCapture/EDataCapture.php index 60d3dfb..decbcec 100644 --- a/app/EDataCapture/EDataCapture.php +++ b/app/EDataCapture/EDataCapture.php @@ -2,32 +2,85 @@ namespace EdgeManager\EDataCapture; class EDataCapture { - // 我不主张在构造函数内实现类型检查,因为在请求过于密集、记录较多时会严重影响性能 - // 请使用SCADA系统的开发人员自觉遵守文档内规范 function __construct( protected $dbconn, protected $post = NULL, - protected $get = NULL - ) {} + protected $get = NULL, + public $check_res = NULL, + protected $working_subclass = NULL, + protected $code_type = [], + protected $data = [] + ) { + if (!is_null($this -> post)) { + if (!in_array( + $this -> post -> param -> working_subclass, + ENodeConfigure::get_working_subclasses($this -> dbconn) + )) { + $this -> check_res = 'WRONG_WORKING_SUBCLASS'; + return; + } else { + $this -> working_subclass = $this -> post -> param -> working_subclass; + } + + $res = pg_fetch_all(pg_query($this -> dbconn, + "SELECT code, type + FROM hf_mes_scada_data_capture_node_configure" + )); + + $code_type = &$this -> code_type; + array_walk($res, function(&$v, $k) use (&$code_type) { + $code_type[$v['code']] = $v['type']; + }); + + foreach ($this -> post -> param -> data as $row) { + $check_func = 'is_' . $code_type[$row -> code]; + if (!$check_func($row -> value)) { + $this -> check_res = 'MISMATCH_TYPE'; + return; + } else { + $this -> data[$row -> code][] = [ + 'value' => $row -> value, + 'device_code' => $row -> device_code ?? NULL, + 'batch' => $row -> batch ?? NULL + ]; + } + } + unset($row); + } + } function set_node_data() { - foreach (array_chunk($this -> post -> param -> data, 6710885, true) as $chunk) { - $sql_head = sprintf( - "INSERT INTO hf_mes_scada_data_capture_node_data_%s (code, v_%s, device_code, batch) - VALUES", - $this -> post -> param -> working_subclass, - $this -> post -> param -> type - ); - foreach ($chunk as $row) { - $sql_values[] = sprintf( - "('%s', %s, %s, %s)", - $row -> code, - $row -> value, - $row -> device_code ?? 'DEFAULT', - $row -> batch ?? 'DEFAULT' + pg_query($this -> dbconn, "BEGIN"); + foreach ($this -> data as $code => $value) { + foreach (array_chunk($value, 6710885, true) as $chunk) { + $sql_head = sprintf( + "INSERT INTO hf_mes_scada_data_capture_node_data_%s (code, v_%s, device_code, batch) + VALUES", + $this -> working_subclass, + $this -> code_type[$code] ); + foreach ($chunk as $row) { + $sql_values[] = sprintf( + "('%s', '%s', %s, %s)", + $code, + $row['value'], + $row['device_code'] ?? 'DEFAULT', + $row['batch'] ?? 'DEFAULT' + ); + } + $res[] = pg_query($this -> dbconn, $sql_head . implode(',', $sql_values)); + unset($row, $sql_values); } - return pg_query($this -> dbconn, $sql_head . implode(',', $sql_values)); + unset($chunk); + } + unset($code, $value); + + if (in_array(false, $res)) { + pg_query($this -> dbconn, "ROLLBACK"); + return false; + } else { + pg_query($this -> dbconn, "COMMIT"); + return true; } } diff --git a/app/EDataCapture/ENodeConfigure.php b/app/EDataCapture/ENodeConfigure.php index 8ae4b47..a8108e7 100644 --- a/app/EDataCapture/ENodeConfigure.php +++ b/app/EDataCapture/ENodeConfigure.php @@ -106,8 +106,8 @@ class ENodeConfigure { return pg_fetch_all($res); } - function get_working_subclasses() { - $res = pg_query($this -> dbconn, "SELECT DISTINCT ON (working_subclass) working_subclass FROM hf_mes_scada_data_capture_node_configure"); + static function get_working_subclasses($dbconn) { + $res = pg_query($dbconn, "SELECT DISTINCT ON (working_subclass) working_subclass FROM hf_mes_scada_data_capture_node_configure"); return pg_fetch_all_columns($res, 0); }