mirror of
https://github.com/espressif/esp-idf.git
synced 2026-05-19 23:45:28 +02:00
Merge branch 'feature/ws_server' into 'master'
http_server: adds WebSocket support Closes IDFGH-2151 and IDFGH-2752 See merge request espressif/esp-idf!7893
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ws_echo_server)
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ws_echo_server
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
# Websocket echo server
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
This example demonstrates the HTTPD server using the WebSocket feature.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
The example starts a WS server on a local network, so a WS client is needed to interact with the server (an example test
|
||||
ws_server_example_test.py could be used as a simple WS client).
|
||||
|
||||
The server registers WebSocket handler which echoes back the received WebSocket frame. It also demonstrates
|
||||
use of asynchronous send, which is triggered on reception of a certain message.
|
||||
|
||||
### Hardware Required
|
||||
|
||||
This example can be executed on any common development board, the only required interface is WiFi or Ethernet connection to a local network.
|
||||
|
||||
### Configure the project
|
||||
|
||||
* Open the project configuration menu (`idf.py menuconfig`)
|
||||
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
```
|
||||
I (4932) example_connect: Got IPv6 event!
|
||||
I (4942) example_connect: Connected to Espressif
|
||||
I (4942) example_connect: IPv4 address: 192.168.4.2
|
||||
I (4952) example_connect: IPv6 address: fe80:xxxx
|
||||
I (4962) ws_echo_server: Starting server on port: '80'
|
||||
I (4962) ws_echo_server: Registering URI handlers
|
||||
D (4962) httpd: httpd_thread: web server started
|
||||
D (4972) httpd: httpd_server: doing select maxfd+1 = 56
|
||||
D (4982) httpd_uri: httpd_register_uri_handler: [0] installed /ws
|
||||
D (17552) httpd: httpd_server: processing listen socket 54
|
||||
D (17552) httpd: httpd_accept_conn: newfd = 57
|
||||
D (17552) httpd_sess: httpd_sess_new: fd = 57
|
||||
D (17562) httpd: httpd_accept_conn: complete
|
||||
D (17562) httpd: httpd_server: doing select maxfd+1 = 58
|
||||
D (17572) httpd: httpd_server: processing socket 57
|
||||
D (17572) httpd_sess: httpd_sess_process: httpd_req_new
|
||||
D (17582) httpd_parse: httpd_req_new: New request, has WS? No, sd->ws_handler valid? No, sd->ws_close? No
|
||||
D (17592) httpd_txrx: httpd_recv_with_opt: requested length = 128
|
||||
D (17592) httpd_txrx: httpd_recv_with_opt: received length = 128
|
||||
D (17602) httpd_parse: read_block: received HTTP request block size = 128
|
||||
D (17612) httpd_parse: cb_url: message begin
|
||||
D (17612) httpd_parse: cb_url: processing url = /ws
|
||||
D (17622) httpd_parse: verify_url: received URI = /ws
|
||||
D (17622) httpd_parse: cb_header_field: headers begin
|
||||
D (17632) httpd_txrx: httpd_unrecv: length = 110
|
||||
D (17632) httpd_parse: pause_parsing: paused
|
||||
D (17632) httpd_parse: cb_header_field: processing field = Host
|
||||
D (17642) httpd_txrx: httpd_recv_with_opt: requested length = 128
|
||||
D (17652) httpd_txrx: httpd_recv_with_opt: pending length = 110
|
||||
D (17652) httpd_parse: read_block: received HTTP request block size = 110
|
||||
D (17662) httpd_parse: continue_parsing: skip pre-parsed data of size = 5
|
||||
D (17672) httpd_parse: continue_parsing: un-paused
|
||||
D (17682) httpd_parse: cb_header_field: processing field = Upgrade
|
||||
D (17682) httpd_parse: cb_header_value: processing value = websocket
|
||||
D (17692) httpd_parse: cb_header_field: processing field = Connection
|
||||
D (17702) httpd_parse: cb_header_value: processing value = Upgrade
|
||||
D (17702) httpd_parse: cb_header_field: processing field = Sec-WebSocket-Key
|
||||
D (17712) httpd_parse: cb_header_value: processing value = gfhjgfhjfj
|
||||
D (17722) httpd_parse: cb_header_field: processing field = Sec-WebSocket-Proto
|
||||
D (17722) httpd_parse: parse_block: parsed block size = 110
|
||||
D (17732) httpd_txrx: httpd_recv_with_opt: requested length = 128
|
||||
D (17742) httpd_txrx: httpd_recv_with_opt: received length = 40
|
||||
D (17742) httpd_parse: read_block: received HTTP request block size = 40
|
||||
D (17752) httpd_parse: cb_header_field: processing field = col
|
||||
D (17752) httpd_parse: cb_header_value: processing value = echo
|
||||
D (17762) httpd_parse: cb_header_field: processing field = Sec-WebSocket-Version
|
||||
D (17772) httpd_parse: cb_header_value: processing value = 13
|
||||
D (17772) httpd_parse: cb_headers_complete: bytes read = 169
|
||||
D (17782) httpd_parse: cb_headers_complete: content length = 0
|
||||
D (17792) httpd_parse: cb_headers_complete: Got an upgrade request
|
||||
D (17792) httpd_parse: pause_parsing: paused
|
||||
D (17802) httpd_parse: cb_no_body: message complete
|
||||
D (17802) httpd_parse: httpd_parse_req: parsing complete
|
||||
D (17812) httpd_uri: httpd_uri: request for /ws with type 1
|
||||
D (17812) httpd_uri: httpd_find_uri_handler: [0] = /ws
|
||||
D (17822) httpd_uri: httpd_uri: Responding WS handshake to sock 57
|
||||
D (17822) httpd_ws: httpd_ws_respond_server_handshake: Server key before encoding: gfhjgfhjfj258EAFA5-E914-47DA-95CA-C5AB0DC85B11
|
||||
D (17842) httpd_ws: httpd_ws_respond_server_handshake: Generated server key: Jg/fQVRsgwdDzYeG8yNBHRajUxw=
|
||||
D (17852) httpd_sess: httpd_sess_process: httpd_req_delete
|
||||
D (17852) httpd_sess: httpd_sess_process: success
|
||||
D (17862) httpd: httpd_server: doing select maxfd+1 = 58
|
||||
D (17892) httpd: httpd_server: processing socket 57
|
||||
D (17892) httpd_sess: httpd_sess_process: httpd_req_new
|
||||
D (17892) httpd_parse: httpd_req_new: New request, has WS? Yes, sd->ws_handler valid? Yes, sd->ws_close? No
|
||||
D (17902) httpd_parse: httpd_req_new: New WS request from existing socket
|
||||
D (17902) httpd_txrx: httpd_recv_with_opt: requested length = 1
|
||||
D (17912) httpd_txrx: httpd_recv_with_opt: received length = 1
|
||||
D (17912) httpd_ws: httpd_ws_get_frame_type: First byte received: 0x81
|
||||
D (17922) httpd_txrx: httpd_recv_with_opt: requested length = 1
|
||||
D (17932) httpd_txrx: httpd_recv_with_opt: received length = 1
|
||||
D (17932) httpd_txrx: httpd_recv_with_opt: requested length = 4
|
||||
D (17942) httpd_txrx: httpd_recv_with_opt: received length = 4
|
||||
D (17942) httpd_txrx: httpd_recv_with_opt: requested length = 13
|
||||
D (17952) httpd_txrx: httpd_recv_with_opt: received length = 13
|
||||
I (17962) ws_echo_server: Got packet with message: Trigger async
|
||||
I (17962) ws_echo_server: Packet type: 1
|
||||
D (17972) httpd_sess: httpd_sess_process: httpd_req_delete
|
||||
D (17972) httpd_sess: httpd_sess_process: success
|
||||
D (17982) httpd: httpd_server: doing select maxfd+1 = 58
|
||||
D (17982) httpd: httpd_server: processing ctrl message
|
||||
D (17992) httpd: httpd_process_ctrl_msg: work
|
||||
D (18002) httpd: httpd_server: doing select maxfd+1 = 58
|
||||
```
|
||||
|
||||
See the README.md file in the upper level 'examples' directory for more information about examples.
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "ws_echo_server.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/* WebSocket Echo Server Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_system.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <sys/param.h>
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
/* A simple example that demonstrates using websocket echo server
|
||||
*/
|
||||
static const char *TAG = "ws_echo_server";
|
||||
|
||||
/*
|
||||
* Structure holding server handle
|
||||
* and internal socket fd in order
|
||||
* to use out of request send
|
||||
*/
|
||||
struct async_resp_arg {
|
||||
httpd_handle_t hd;
|
||||
int fd;
|
||||
};
|
||||
|
||||
/*
|
||||
* async send function, which we put into the httpd work queue
|
||||
*/
|
||||
static void ws_async_send(void *arg)
|
||||
{
|
||||
static const char * data = "Async data";
|
||||
struct async_resp_arg *resp_arg = arg;
|
||||
httpd_handle_t hd = resp_arg->hd;
|
||||
int fd = resp_arg->fd;
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
ws_pkt.payload = (uint8_t*)data;
|
||||
ws_pkt.len = strlen(data);
|
||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
|
||||
httpd_ws_send_frame_async(hd, fd, &ws_pkt);
|
||||
free(resp_arg);
|
||||
}
|
||||
|
||||
static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t *req)
|
||||
{
|
||||
struct async_resp_arg *resp_arg = malloc(sizeof(struct async_resp_arg));
|
||||
resp_arg->hd = req->handle;
|
||||
resp_arg->fd = httpd_req_to_sockfd(req);
|
||||
return httpd_queue_work(handle, ws_async_send, resp_arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* This handler echos back the received ws data
|
||||
* and triggers an async send if certain message received
|
||||
*/
|
||||
static esp_err_t echo_handler(httpd_req_t *req)
|
||||
{
|
||||
uint8_t buf[128] = { 0 };
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
ws_pkt.payload = buf;
|
||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 128);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "httpd_ws_recv_frame failed with %d", ret);
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(TAG, "Got packet with message: %s", ws_pkt.payload);
|
||||
ESP_LOGI(TAG, "Packet type: %d", ws_pkt.type);
|
||||
if (ws_pkt.type == HTTPD_WS_TYPE_TEXT &&
|
||||
strcmp((char*)ws_pkt.payload,"Trigger async") == 0) {
|
||||
return trigger_async_send(req->handle, req);
|
||||
}
|
||||
|
||||
ret = httpd_ws_send_frame(req, &ws_pkt);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "httpd_ws_send_frame failed with %d", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const httpd_uri_t ws = {
|
||||
.uri = "/ws",
|
||||
.method = HTTP_GET,
|
||||
.handler = echo_handler,
|
||||
.user_ctx = NULL,
|
||||
.is_websocket = true
|
||||
};
|
||||
|
||||
|
||||
static httpd_handle_t start_webserver(void)
|
||||
{
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
|
||||
// Start the httpd server
|
||||
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
|
||||
if (httpd_start(&server, &config) == ESP_OK) {
|
||||
// Registering the ws handler
|
||||
ESP_LOGI(TAG, "Registering URI handlers");
|
||||
httpd_register_uri_handler(server, &ws);
|
||||
return server;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Error starting server!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void stop_webserver(httpd_handle_t server)
|
||||
{
|
||||
// Stop the httpd server
|
||||
httpd_stop(server);
|
||||
}
|
||||
|
||||
static void disconnect_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
httpd_handle_t* server = (httpd_handle_t*) arg;
|
||||
if (*server) {
|
||||
ESP_LOGI(TAG, "Stopping webserver");
|
||||
stop_webserver(*server);
|
||||
*server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_handler(void* arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data)
|
||||
{
|
||||
httpd_handle_t* server = (httpd_handle_t*) arg;
|
||||
if (*server == NULL) {
|
||||
ESP_LOGI(TAG, "Starting webserver");
|
||||
*server = start_webserver();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
static httpd_handle_t server = NULL;
|
||||
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
* Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
* examples/protocols/README.md for more information about this function.
|
||||
*/
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
/* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected,
|
||||
* and re-start it upon connection.
|
||||
*/
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server));
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server));
|
||||
#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET
|
||||
|
||||
/* Start the server for the first time */
|
||||
server = start_webserver();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
@@ -0,0 +1 @@
|
||||
CONFIG_HTTPD_WS_SUPPORT=y
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
import re
|
||||
from tiny_test_fw import Utility
|
||||
import ttfw_idf
|
||||
import os
|
||||
import six
|
||||
import socket
|
||||
import hashlib
|
||||
import base64
|
||||
import struct
|
||||
|
||||
|
||||
OPCODE_TEXT = 0x1
|
||||
OPCODE_BIN = 0x2
|
||||
OPCODE_PING = 0x9
|
||||
OPCODE_PONG = 0xa
|
||||
|
||||
|
||||
class WsClient:
|
||||
def __init__(self, ip, port):
|
||||
self.port = port
|
||||
self.ip = ip
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.client_key = "abcdefghjk"
|
||||
self.socket.settimeout(10.0)
|
||||
|
||||
def __enter__(self):
|
||||
self.socket.connect((self.ip, self.port))
|
||||
self._handshake()
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.socket.close()
|
||||
|
||||
def _handshake(self):
|
||||
MAGIC_STRING = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
client_key = self.client_key + MAGIC_STRING
|
||||
expected_accept = base64.standard_b64encode(hashlib.sha1(client_key.encode()).digest())
|
||||
request = ('GET /ws HTTP/1.1\r\nHost: localhost\r\nUpgrade: websocket\r\nConnection: '
|
||||
'Upgrade\r\nSec-WebSocket-Key: {}\r\n'
|
||||
'Sec-WebSocket-Version: 13\r\n\r\n'.format(self.client_key))
|
||||
self.socket.send(request.encode('utf-8'))
|
||||
response = self.socket.recv(1024)
|
||||
ws_accept = re.search(b'Sec-WebSocket-Accept: (.*)\r\n', response, re.IGNORECASE)
|
||||
if ws_accept and ws_accept.group(1) is not None and ws_accept.group(1) == expected_accept:
|
||||
pass
|
||||
else:
|
||||
raise("Unexpected Sec-WebSocket-Accept, handshake response: {}".format(response))
|
||||
|
||||
def _masked(self, data):
|
||||
mask = struct.unpack('B' * 4, os.urandom(4))
|
||||
out = list(mask)
|
||||
for i, d in enumerate(struct.unpack('B' * len(data), data)):
|
||||
out.append(d ^ mask[i % 4])
|
||||
return struct.pack('B' * len(out), *out)
|
||||
|
||||
def _ws_encode(self, data="", opcode=OPCODE_TEXT, mask=1):
|
||||
data = data.encode('utf-8')
|
||||
length = len(data)
|
||||
if length >= 126:
|
||||
raise("Packet length of {} not supported!".format(length))
|
||||
frame_header = chr(1 << 7 | opcode)
|
||||
frame_header += chr(mask << 7 | length)
|
||||
frame_header = six.b(frame_header)
|
||||
if not mask:
|
||||
return frame_header + data
|
||||
return frame_header + self._masked(data)
|
||||
|
||||
def read(self):
|
||||
header = self.socket.recv(2)
|
||||
if not six.PY3:
|
||||
header = [ord(character) for character in header]
|
||||
opcode = header[0] & 15
|
||||
length = header[1] & 127
|
||||
payload = self.socket.recv(length)
|
||||
return opcode, payload.decode('utf-8')
|
||||
|
||||
def write(self, data="", opcode=OPCODE_TEXT, mask=1):
|
||||
return self.socket.sendall(self._ws_encode(data=data, opcode=opcode, mask=mask))
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_WIFI")
|
||||
def test_examples_protocol_http_ws_echo_server(env, extra_data):
|
||||
# Acquire DUT
|
||||
dut1 = env.get_dut("http_server", "examples/protocols/http_server/ws_echo_server", dut_class=ttfw_idf.ESP32DUT)
|
||||
|
||||
# Get binary file
|
||||
binary_file = os.path.join(dut1.app.binary_path, "ws_echo_server.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("http_ws_server_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("http_ws_server_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
|
||||
# Upload binary and start testing
|
||||
Utility.console_log("Starting ws-echo-server test app based on http_server")
|
||||
dut1.start_app()
|
||||
|
||||
# Parse IP address of STA
|
||||
Utility.console_log("Waiting to connect with AP")
|
||||
got_ip = dut1.expect(re.compile(r"(?:[\s\S]*)IPv4 address: (\d+.\d+.\d+.\d+)"), timeout=60)[0]
|
||||
got_port = dut1.expect(re.compile(r"(?:[\s\S]*)Starting server on port: '(\d+)'"), timeout=60)[0]
|
||||
|
||||
Utility.console_log("Got IP : " + got_ip)
|
||||
Utility.console_log("Got Port : " + got_port)
|
||||
|
||||
# Start ws server test
|
||||
with WsClient(got_ip, int(got_port)) as ws:
|
||||
DATA = 'Espressif'
|
||||
for expected_opcode in [OPCODE_TEXT, OPCODE_BIN, OPCODE_PING]:
|
||||
ws.write(data=DATA, opcode=expected_opcode)
|
||||
opcode, data = ws.read()
|
||||
Utility.console_log("Testing opcode {}: Received opcode:{}, data:{}".format(expected_opcode, opcode, data))
|
||||
if expected_opcode == OPCODE_PING:
|
||||
dut1.expect("Got a WS PING frame, Replying PONG")
|
||||
if opcode != OPCODE_PONG or data != DATA:
|
||||
raise RuntimeError("Failed to receive correct opcode:{} or data:{}".format(opcode, data))
|
||||
continue
|
||||
dut_data = dut1.expect(re.compile(r"Got packet with message: ([A-Za-z0-9_]*)"))[0]
|
||||
dut_opcode = int(dut1.expect(re.compile(r"Packet type: ([0-9]*)"))[0])
|
||||
if opcode != expected_opcode or data != DATA or opcode != dut_opcode or data != dut_data:
|
||||
raise RuntimeError("Failed to receive correct opcode:{} or data:{}".format(opcode, data))
|
||||
ws.write(data="Trigger async", opcode=OPCODE_TEXT)
|
||||
opcode, data = ws.read()
|
||||
Utility.console_log("Testing async send: Received opcode:{}, data:{}".format(opcode, data))
|
||||
if opcode != OPCODE_TEXT or data != "Async data":
|
||||
raise RuntimeError("Failed to receive correct opcode:{} or data:{}".format(opcode, data))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_protocol_http_ws_echo_server()
|
||||
Reference in New Issue
Block a user