未验证 提交 3f659d27 编写于 作者: Y Yang Zhao 提交者: GitHub

fix: shell exit while ws rev is 0 (#13992)

* fix: taos shell support ws client

* fix: ping/pong

* fix: shell ctrl c stop query

* fix: shell exit while ws recv 0

* fix: remove magic number

* fix: handle error

* fix: handle sigpipe

* fix: change return error number

* fix: remove useless print msg

* fix: remove unused variable
上级 e165a862
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define MAX_COMMAND_SIZE 1048586 #define MAX_COMMAND_SIZE 1048586
#define HISTORY_FILE ".taos_history" #define HISTORY_FILE ".taos_history"
#define DEFAULT_RES_SHOW_NUM 100 #define DEFAULT_RES_SHOW_NUM 100
#define TEMP_RECV_BUF 1024
typedef struct SShellHistory { typedef struct SShellHistory {
char* hist[MAX_HISTORY_SIZE]; char* hist[MAX_HISTORY_SIZE];
......
...@@ -1136,7 +1136,7 @@ int taos_base64_encode(unsigned char *source, size_t sourcelen, char *target, si ...@@ -1136,7 +1136,7 @@ int taos_base64_encode(unsigned char *source, size_t sourcelen, char *target, si
int parse_cloud_dsn() { int parse_cloud_dsn() {
if (args.cloudDsn == NULL) { if (args.cloudDsn == NULL) {
fprintf(stderr, "Cannot read cloud service info\n"); fprintf(stderr, "Cannot read cloud service info\n");
return 1; return -1;
} else { } else {
char *start = strstr(args.cloudDsn, "http://"); char *start = strstr(args.cloudDsn, "http://");
if (start != NULL) { if (start != NULL) {
...@@ -1152,7 +1152,7 @@ int parse_cloud_dsn() { ...@@ -1152,7 +1152,7 @@ int parse_cloud_dsn() {
char *port = strstr(args.cloudHost, ":"); char *port = strstr(args.cloudHost, ":");
if ((port == NULL) || (port + strlen(":")) == NULL) { if ((port == NULL) || (port + strlen(":")) == NULL) {
fprintf(stderr, "Invalid format in TDengine cloud dsn: %s\n", args.cloudDsn); fprintf(stderr, "Invalid format in TDengine cloud dsn: %s\n", args.cloudDsn);
return 1; return -1;
} }
char *token = strstr(port + strlen(":"), "?token="); char *token = strstr(port + strlen(":"), "?token=");
if ((token == NULL) || (token + strlen("?token=")) == NULL || if ((token == NULL) || (token + strlen("?token=")) == NULL ||
...@@ -1272,7 +1272,9 @@ int wsclient_send(char *strdata, WebSocketFrameType frame) { ...@@ -1272,7 +1272,9 @@ int wsclient_send(char *strdata, WebSocketFrameType frame) {
sent += i; sent += i;
} }
if (i < 0) { if (i < 0) {
fprintf(stderr, "websocket send data error\n"); fprintf(stderr, "websocket send data error, please check the server\n");
free(data);
return -1;
} }
free(data); free(data);
return 0; return 0;
...@@ -1353,7 +1355,6 @@ int wsclient_conn() { ...@@ -1353,7 +1355,6 @@ int wsclient_conn() {
} else { } else {
fprintf(stdout, "Successfully connect to %s:%d in restful mode\n\n", args.host, args.port); fprintf(stdout, "Successfully connect to %s:%d in restful mode\n\n", args.host, args.port);
} }
return 0; return 0;
} else { } else {
cJSON *message = cJSON_GetObjectItem(root, "message"); cJSON *message = cJSON_GetObjectItem(root, "message");
...@@ -1406,10 +1407,10 @@ void wsclient_parse_frame(SWSParser * parser, uint8_t * recv_buffer) { ...@@ -1406,10 +1407,10 @@ void wsclient_parse_frame(SWSParser * parser, uint8_t * recv_buffer) {
} }
char *wsclient_get_response() { char *wsclient_get_response() {
uint8_t recv_buffer[1024]= {0}; uint8_t recv_buffer[TEMP_RECV_BUF]= {0};
int received = 0; int received = 0;
SWSParser parser; SWSParser parser;
int bytes = recv(args.socket, recv_buffer + received, 1023, 0); int bytes = recv(args.socket, recv_buffer + received, TEMP_RECV_BUF - 1, 0);
if (bytes <= 0) { if (bytes <= 0) {
fprintf(stderr, "websocket recv failed with bytes: %d\n", bytes); fprintf(stderr, "websocket recv failed with bytes: %d\n", bytes);
return NULL; return NULL;
...@@ -1429,80 +1430,56 @@ char *wsclient_get_response() { ...@@ -1429,80 +1430,56 @@ char *wsclient_get_response() {
pos += bytes; pos += bytes;
} }
response[pos] = '\0'; response[pos] = '\0';
if (NULL != strstr(response, "unexpected")) {
printf("motherfucker");
}
return response; return response;
} }
TAOS_FIELD *wsclient_print_header(cJSON *query, int *pcols, int *pprecison) { int wsclient_fetch_fields(cJSON *query, TAOS_FIELD * fields, int cols) {
TAOS_FIELD *fields = NULL; cJSON *fields_names = cJSON_GetObjectItem(query, "fields_names");
cJSON *fields_count = cJSON_GetObjectItem(query, "fields_count"); cJSON *fields_types = cJSON_GetObjectItem(query, "fields_types");
if (cJSON_IsNumber(fields_count)) { cJSON *fields_lengths = cJSON_GetObjectItem(query, "fields_lengths");
*pcols = (int)fields_count->valueint; if (!cJSON_IsArray(fields_names) || !cJSON_IsArray(fields_types) || !cJSON_IsArray(fields_lengths)) {
fields = calloc((int)fields_count->valueint, sizeof(TAOS_FIELD)); fprintf(stderr, "Invalid or miss 'fields_names'/'fields_types'/'fields_lengths' key in response\n");
cJSON *fields_names = cJSON_GetObjectItem(query, "fields_names"); return -1;
cJSON *fields_types = cJSON_GetObjectItem(query, "fields_types");
cJSON *fields_lengths = cJSON_GetObjectItem(query, "fields_lengths");
if (cJSON_IsArray(fields_names) && cJSON_IsArray(fields_types) && cJSON_IsArray(fields_lengths)) {
for (int i = 0; i < (int)fields_count->valueint; i++) {
strncpy(fields[i].name, cJSON_GetArrayItem(fields_names, i)->valuestring, 65);
fields[i].type = (uint8_t)cJSON_GetArrayItem(fields_types, i)->valueint;
fields[i].bytes = (int16_t)cJSON_GetArrayItem(fields_lengths, i)->valueint;
}
cJSON *precision = cJSON_GetObjectItem(query, "precision");
if (cJSON_IsNumber(precision)) {
*pprecison = (int)precision->valueint;
int width[TSDB_MAX_COLUMNS];
for (int col = 0; col < (int)fields_count->valueint; col++) {
width[col] = calcColWidth(fields + col, (int)precision->valueint);
}
printHeader(fields, width, (int)fields_count->valueint);
return fields;
} else {
fprintf(stderr, "Invalid precision key in json\n");
}
} else {
fprintf(stderr, "Invalid fields_names/fields_types/fields_lengths key in json\n");
}
} else {
fprintf(stderr, "Invalid fields_count key in json\n");
} }
if (fields != NULL) { for (int i = 0; i < cols; i++) {
free(fields); cJSON* field_name = cJSON_GetArrayItem(fields_names, i);
cJSON* field_type = cJSON_GetArrayItem(fields_types, i);
cJSON* field_length = cJSON_GetArrayItem(fields_lengths, i);
if (!cJSON_IsString(field_name) || !cJSON_IsNumber(field_type) || !cJSON_IsNumber(field_length)) {
fprintf(stderr, "Invalid or miss 'field_name'/'field_type'/'field_length' in query response");
return -1;
}
strncpy(fields[i].name, field_name->valuestring, 65);
fields[i].type = (uint8_t)field_type->valueint;
fields[i].bytes = (int16_t)field_length->valueint;
} }
return NULL; return 0;
} }
int wsclient_check(cJSON *root, int64_t st, int64_t et) { int wsclient_check(cJSON *root, int64_t st, int64_t et) {
cJSON *code = cJSON_GetObjectItem(root, "code"); cJSON *code = cJSON_GetObjectItem(root, "code");
if (cJSON_IsNumber(code)) { cJSON *message = cJSON_GetObjectItem(root, "message");
if (code->valueint == 0) { if (!cJSON_IsNumber(code) || !cJSON_IsString(message)) {
return 0; fprintf(stderr, "Invalid or miss 'code'/'message' in response\n");
} else { return -1;
cJSON *message = cJSON_GetObjectItem(root, "message");
if (cJSON_IsString(message)) {
fprintf(stderr, "\nDB error: %s (%.6fs)\n", message->valuestring, (et - st) / 1E6);
} else {
fprintf(stderr, "Invalid message key in json\n");
}
}
} else {
fprintf(stderr, "Invalid code key in json\n");
} }
return -1; if (code->valueint != 0) {
fprintf(stderr, "\nDB error: %s (%.6fs)\n", message->valuestring, (et - st) / 1E6);
return -1;
}
return 0;
} }
int wsclient_print_data(int rows, TAOS_FIELD *fields, int cols, int64_t id, int precision, int* pshowed_rows) { int wsclient_print_data(int rows, TAOS_FIELD *fields, int cols, int64_t id, int precision, int* pshowed_rows) {
char* response = wsclient_get_response(); char* response = wsclient_get_response();
if (response == NULL) { if (response == NULL) {
return 0; return -1;
} }
if (*(int64_t *)response != id) { if (*(int64_t *)response != id) {
fprintf(stderr, "Mismatch id with %"PRId64" expect %"PRId64"\n", *(int64_t *)response, id); fprintf(stderr, "Mismatch id with %"PRId64" expect %"PRId64"\n", *(int64_t *)response, id);
free(response); free(response);
return 0; return -1;
} }
int pos; int pos;
int width[TSDB_MAX_COLUMNS]; int width[TSDB_MAX_COLUMNS];
...@@ -1549,106 +1526,129 @@ void wsclient_query(char *command) { ...@@ -1549,106 +1526,129 @@ void wsclient_query(char *command) {
if (wsclient_send_sql(command, WS_QUERY, 0)) { if (wsclient_send_sql(command, WS_QUERY, 0)) {
return; return;
} }
char *query_buffer = wsclient_get_response(); char *query_buffer = wsclient_get_response();
if (query_buffer == NULL) { if (query_buffer == NULL) {
return; return;
} }
cJSON* query = cJSON_Parse(query_buffer); cJSON* query = cJSON_Parse(query_buffer);
if (query == NULL) { if (query == NULL) {
free(query_buffer);
fprintf(stderr, "Failed to parse response into json: %s\n", query_buffer); fprintf(stderr, "Failed to parse response into json: %s\n", query_buffer);
free(query_buffer);
return; return;
} }
et = taosGetTimestampUs();
free(query_buffer); free(query_buffer);
et = taosGetTimestampUs();
if (wsclient_check(query, st, et)) { if (wsclient_check(query, st, et)) {
goto OVER; cJSON_Delete(query);
return; return;
} }
cJSON *is_update = cJSON_GetObjectItem(query, "is_update"); cJSON *is_update = cJSON_GetObjectItem(query, "is_update");
if (cJSON_IsBool(is_update)) { cJSON *fields_count = cJSON_GetObjectItem(query, "fields_count");
if (is_update->valueint) { cJSON *precisionObj = cJSON_GetObjectItem(query, "precision");
cJSON *affected_rows = cJSON_GetObjectItem(query, "affected_rows"); cJSON *id = cJSON_GetObjectItem(query, "id");
if (cJSON_IsNumber(affected_rows)) { if (!cJSON_IsBool(is_update) ||
et = taosGetTimestampUs(); !cJSON_IsNumber(fields_count) ||
printf("Update OK, %d row(s) in set (%.6fs)\n\n", (int)affected_rows->valueint, (et - st) / 1E6); !cJSON_IsNumber(precisionObj) ||
} else { !cJSON_IsNumber(id)) {
fprintf(stderr, "Invalid affected_rows key in json\n"); fprintf(stderr, "Invalid or miss 'is_update'/'fields_count'/'precision'/'id' in query response\n");
} cJSON_Delete(query);
return;
}
if (is_update->valueint) {
cJSON *affected_rows = cJSON_GetObjectItem(query, "affected_rows");
if (cJSON_IsNumber(affected_rows)) {
et = taosGetTimestampUs();
printf("Update OK, %d row(s) in set (%.6fs)\n\n", (int)affected_rows->valueint, (et - st) / 1E6);
} else { } else {
int cols = 0; fprintf(stderr, "Invalid or miss 'affected_rows' key in response\n");
int precision = 0; }
int64_t total_rows = 0; cJSON_Delete(query);
int showed_rows = 0; return;
TAOS_FIELD *fields = wsclient_print_header(query, &cols, &precision); }
if (fields != NULL) { ws_id = id->valueint;
cJSON *id = cJSON_GetObjectItem(query, "id"); int cols = (int)fields_count->valueint;
if (cJSON_IsNumber(id)) { int precision = (int)precisionObj->valueint;
ws_id = id->valueint; int64_t total_rows = 0;
bool completed = false; int showed_rows = 0;
while (!completed && !stop_fetch) { bool completed = false;
if (wsclient_send_sql(NULL, WS_FETCH, id->valueint) == 0) { TAOS_FIELD fields[cols];
char *fetch_buffer = wsclient_get_response(); if (wsclient_fetch_fields(query, fields, cols)) {
cJSON* fetch = cJSON_Parse(fetch_buffer); cJSON_Delete(query);
if (fetch != NULL) { return;
free(fetch_buffer); }
if (wsclient_check(fetch, st, et) == 0) { int width[cols];
cJSON *_completed = cJSON_GetObjectItem(fetch, "completed"); for (int i = 0; i < cols; ++i) {
if (cJSON_IsBool(_completed)) { width[i] = calcColWidth(fields + i, precision);
if (_completed->valueint) { }
cJSON_Delete(fetch); printHeader(fields, width, cols);
completed = true;
continue; cJSON_Delete(query);
}
cJSON *rows = cJSON_GetObjectItem(fetch, "rows"); while (!completed && !stop_fetch) {
if (cJSON_IsNumber(rows)) { if (wsclient_send_sql(NULL, WS_FETCH, ws_id)) {
total_rows += rows->valueint; return;
cJSON *lengths = cJSON_GetObjectItem(fetch, "lengths"); }
if (cJSON_IsArray(lengths)) { char *fetch_buffer = wsclient_get_response();
for (int i = 0; i < cols; i++) { if (fetch_buffer == NULL) {
fields[i].bytes = (int16_t)(cJSON_GetArrayItem(lengths, i)->valueint); return;
} }
if (showed_rows < DEFAULT_RES_SHOW_NUM) { cJSON *fetch = cJSON_Parse(fetch_buffer);
if (wsclient_send_sql(NULL, WS_FETCH_BLOCK, id->valueint) == 0) { if (fetch == NULL) {
wsclient_print_data((int)rows->valueint, fields, cols, id->valueint, precision, &showed_rows); fprintf(stderr, "failed to parse response into json: %s\n", fetch_buffer);
} free(fetch_buffer);
} return;
cJSON_Delete(fetch); }
continue; free(fetch_buffer);
} else { if (wsclient_check(fetch, st, et)) {
fprintf(stderr, "Invalid lengths key in json\n"); cJSON_Delete(fetch);
} return;
} else { }
fprintf(stderr, "Invalid rows key in json\n"); cJSON *completedObj = cJSON_GetObjectItem(fetch, "completed");
} cJSON *rows = cJSON_GetObjectItem(fetch, "rows");
} else { cJSON *lengths = cJSON_GetObjectItem(fetch, "lengths");
fprintf(stderr, "Invalid completed key in json\n"); if (!cJSON_IsBool(completedObj) || !cJSON_IsNumber(rows)) {
} fprintf(stderr, "Invalid or miss 'completed'/'rows' in fetch response\n");
} cJSON_Delete(fetch);
cJSON_Delete(fetch); return;
} else { }
fprintf(stderr, "failed to parse response into json: %s\n", fetch_buffer); if (completedObj->valueint) {
free(fetch_buffer); cJSON_Delete(fetch);
break; completed = true;
} continue;
} }
fprintf(stderr, "err occured in fetch/fetch_block ws actions\n"); total_rows += rows->valueint;
break; if (!cJSON_IsArray(lengths)) {
} fprintf(stderr, "Invalid or miss 'lengths' in fetch response\n");
et = taosGetTimestampUs(); cJSON_Delete(fetch);
printf("Query OK, %" PRId64 " row(s) in set (%.6fs)\n\n", total_rows, (et - st) / 1E6); return;
stop_fetch = false; }
} else { for (int i = 0; i < cols; i++) {
fprintf(stderr, "Invalid id key in json\n"); cJSON* length = cJSON_GetArrayItem(lengths, i);
} if (!cJSON_IsNumber(length)) {
free(fields); fprintf(stderr, "Invalid or miss 'lengths' key in fetch response\n");
cJSON_Delete(fetch);
return;
} }
fields[i].bytes = (int16_t)(length->valueint);
} }
if (showed_rows < DEFAULT_RES_SHOW_NUM) {
if (wsclient_send_sql(NULL, WS_FETCH_BLOCK, ws_id)) {
cJSON_Delete(fetch);
return;
}
if (wsclient_print_data((int)rows->valueint, fields, cols, ws_id, precision, &showed_rows)) {
cJSON_Delete(fetch);
return;
}
cJSON_Delete(fetch);
continue;
}
}
et = taosGetTimestampUs();
if (stop_fetch) {
printf("Query interrupted, %" PRId64 " row(s) in set (%.6fs)\n\n", total_rows, (et - st) / 1E6);
stop_fetch = false;
} else { } else {
fprintf(stderr, "Invalid is_update key in json\n"); printf("Query OK, %" PRId64 " row(s) in set (%.6fs)\n\n", total_rows, (et - st) / 1E6);
} }
OVER:
cJSON_Delete(query);
return;
} }
\ No newline at end of file
...@@ -27,6 +27,8 @@ void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context) { ...@@ -27,6 +27,8 @@ void shellQueryInterruptHandler(int32_t signum, void *sigInfo, void *context) {
tsem_post(&cancelSem); tsem_post(&cancelSem);
} }
void shellRestfulSendInterruptHandler(int32_t signum, void *sigInfo, void *context) {}
void *cancelHandler(void *arg) { void *cancelHandler(void *arg) {
setThreadName("cancelHandler"); setThreadName("cancelHandler");
...@@ -167,6 +169,9 @@ int main(int argc, char* argv[]) { ...@@ -167,6 +169,9 @@ int main(int argc, char* argv[]) {
taosSetSignal(SIGINT, shellQueryInterruptHandler); taosSetSignal(SIGINT, shellQueryInterruptHandler);
taosSetSignal(SIGHUP, shellQueryInterruptHandler); taosSetSignal(SIGHUP, shellQueryInterruptHandler);
taosSetSignal(SIGABRT, shellQueryInterruptHandler); taosSetSignal(SIGABRT, shellQueryInterruptHandler);
if (args.restful || args.cloud) {
taosSetSignal(SIGPIPE, shellRestfulSendInterruptHandler);
}
/* Get grant information */ /* Get grant information */
shellGetGrantInfo(args.con); shellGetGrantInfo(args.con);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册