add microhttpd server
This commit is contained in:
@@ -97,7 +97,7 @@ set(PIP_UTILS_LIST)
|
|||||||
set(PIP_TESTS_LIST)
|
set(PIP_TESTS_LIST)
|
||||||
set(PIP_EXPORTS)
|
set(PIP_EXPORTS)
|
||||||
|
|
||||||
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua")
|
set(PIP_SRC_MODULES "console;crypt;compress;usb;fftw;opencl;io_utils;client_server;cloud;lua;http_server")
|
||||||
foreach(_m ${PIP_SRC_MODULES})
|
foreach(_m ${PIP_SRC_MODULES})
|
||||||
set(PIP_MSG_${_m} "no")
|
set(PIP_MSG_${_m} "no")
|
||||||
endforeach()
|
endforeach()
|
||||||
@@ -481,6 +481,33 @@ if (NOT CROSSTOOLS)
|
|||||||
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
|
list(APPEND HDR_DIRS "${_lua_bri_dir}/LuaBridge")
|
||||||
list(APPEND HDRS ${_lua_src_hdr})
|
list(APPEND HDRS ${_lua_src_hdr})
|
||||||
|
|
||||||
|
# libmicrohttpd
|
||||||
|
find_library(microhttpd_LIBRARIES microhttpd HINTS "${MINGW_LIB}")
|
||||||
|
if (microhttpd_LIBRARIES)
|
||||||
|
set(_microhttpd_add_libs)
|
||||||
|
if(WIN32)
|
||||||
|
if("${C_COMPILER}" STREQUAL "cl.exe")
|
||||||
|
else()
|
||||||
|
list(APPEND _microhttpd_add_libs ws2_32)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
list(APPEND _microhttpd_add_libs dl)
|
||||||
|
find_library(tls_lib gnutls)
|
||||||
|
if (tls_lib)
|
||||||
|
list(APPEND _microhttpd_add_libs ${tls_lib})
|
||||||
|
endif()
|
||||||
|
if(DEFINED ENV{QNX_HOST})
|
||||||
|
list(APPEND _microhttpd_add_libs socket)
|
||||||
|
else()
|
||||||
|
if (NOT DEFINED ANDROID_PLATFORM)
|
||||||
|
list(APPEND _microhttpd_add_libs pthread util)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
list(APPEND microhttpd_LIBRARIES "${_microhttpd_add_libs}")
|
||||||
|
pip_module(http_server "${microhttpd_LIBRARIES}" "PIP HTTP server" "" "" "")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Test program
|
# Test program
|
||||||
if(PIP_UTILS)
|
if(PIP_UTILS)
|
||||||
|
|
||||||
@@ -488,7 +515,7 @@ if (NOT CROSSTOOLS)
|
|||||||
#target_link_libraries(pip_plugin pip)
|
#target_link_libraries(pip_plugin pip)
|
||||||
|
|
||||||
add_executable(pip_test "main.cpp")
|
add_executable(pip_test "main.cpp")
|
||||||
target_link_libraries(pip_test pip pip_io_utils pip_client_server)
|
target_link_libraries(pip_test pip pip_io_utils pip_client_server pip_http_server)
|
||||||
if(sodium_FOUND)
|
if(sodium_FOUND)
|
||||||
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
add_executable(pip_cloud_test "main_picloud_test.cpp")
|
||||||
target_link_libraries(pip_cloud_test pip_cloud)
|
target_link_libraries(pip_cloud_test pip_cloud)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ Create imported targets:
|
|||||||
* PIP::ClientServer
|
* PIP::ClientServer
|
||||||
* PIP::Cloud
|
* PIP::Cloud
|
||||||
* PIP::Lua
|
* PIP::Lua
|
||||||
|
* PIP::HTTPServer
|
||||||
|
|
||||||
These targets include directories and depends on
|
These targets include directories and depends on
|
||||||
main library
|
main library
|
||||||
@@ -23,10 +24,10 @@ include(SHSTKMacros)
|
|||||||
|
|
||||||
shstk_set_find_dirs(PIP)
|
shstk_set_find_dirs(PIP)
|
||||||
|
|
||||||
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua")
|
set(__libs "usb;crypt;console;fftw;compress;opencl;io_utils;client_server;cloud;lua;http_server")
|
||||||
|
|
||||||
if (BUILDING_PIP)
|
if (BUILDING_PIP)
|
||||||
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua")
|
#set(_libs "pip;pip_usb;pip_console;pip_crypt;pip_fftw;pip_compress;pip_opencl;pip_io_utils;pip_cloud;pip_lua;pip_http_server")
|
||||||
#set(_bins "pip_cmg;pip_rc;deploy_tool")
|
#set(_bins "pip_cmg;pip_rc;deploy_tool")
|
||||||
#get_target_property(_path pip BINARY_DIR)
|
#get_target_property(_path pip BINARY_DIR)
|
||||||
#get_target_property(_path pip LIBRARY_OUTPUT_NAME)
|
#get_target_property(_path pip LIBRARY_OUTPUT_NAME)
|
||||||
@@ -96,6 +97,7 @@ set(__module_io_utils IOUtils )
|
|||||||
set(__module_client_server ClientServer)
|
set(__module_client_server ClientServer)
|
||||||
set(__module_cloud Cloud )
|
set(__module_cloud Cloud )
|
||||||
set(__module_lua Lua )
|
set(__module_lua Lua )
|
||||||
|
set(__module_http_server HTTPServer )
|
||||||
|
|
||||||
foreach (_l ${__libs})
|
foreach (_l ${__libs})
|
||||||
set( __inc_${_l} "")
|
set( __inc_${_l} "")
|
||||||
|
|||||||
308
libs/http_server/microhttpd_server_p.cpp
Normal file
308
libs/http_server/microhttpd_server_p.cpp
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
#include "microhttpd_server_p.h"
|
||||||
|
|
||||||
|
#include "pidir.h"
|
||||||
|
#include "pifile.h"
|
||||||
|
#include "piliterals_string.h"
|
||||||
|
|
||||||
|
#include <microhttpd.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct MicrohttpdServerConnection {
|
||||||
|
bool ready();
|
||||||
|
int send_reply(const MicrohttpdServer::Reply & r);
|
||||||
|
int send_error();
|
||||||
|
|
||||||
|
bool done = false;
|
||||||
|
MicrohttpdServer::Method method = MicrohttpdServer::Method::Unknown;
|
||||||
|
PIString path;
|
||||||
|
PIByteArray body;
|
||||||
|
PIMap<PIString, PIString> headers, args, post;
|
||||||
|
MHD_Connection * connection = nullptr;
|
||||||
|
MicrohttpdServer * server = nullptr;
|
||||||
|
MHD_PostProcessor * postprocessor = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool MicrohttpdServerConnection::ready() {
|
||||||
|
if (!server) return false;
|
||||||
|
if (done) return true;
|
||||||
|
done = true;
|
||||||
|
MicrohttpdServer::Reply rep;
|
||||||
|
if (method == MicrohttpdServer::Method::Get) {
|
||||||
|
PIByteArray file = server->getFile(path);
|
||||||
|
if (!file.isEmpty()) {
|
||||||
|
rep.addHeader(MHD_HTTP_HEADER_CACHE_CONTROL, "public");
|
||||||
|
rep.addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/octet-stream");
|
||||||
|
rep.setBody(file);
|
||||||
|
send_reply(rep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (path == "/favicon.ico"_a) {
|
||||||
|
piCout << "send favicon" << server->favicon.size() << "bytes";
|
||||||
|
rep.setBody(server->favicon);
|
||||||
|
send_reply(rep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
piCout << "ready" << (int)method << path;
|
||||||
|
MicrohttpdServer::Request req;
|
||||||
|
req.method = method;
|
||||||
|
req.path = path;
|
||||||
|
req.body = body;
|
||||||
|
req.headers = headers;
|
||||||
|
req.args = args;
|
||||||
|
// rep.headers = headers;
|
||||||
|
if (server->callback) rep = server->callback(req);
|
||||||
|
rep.addFixedHeaders();
|
||||||
|
send_reply(rep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MicrohttpdServerConnection::send_reply(const MicrohttpdServer::Reply & r) {
|
||||||
|
MHD_Response * response = MHD_create_response_from_buffer(r.body.size(), (void *)r.body.data(), MHD_RESPMEM_MUST_COPY);
|
||||||
|
if (!response) {
|
||||||
|
piCout << "null response" << r.body.size() << (void *)r.body.data();
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
auto it = r.headers.makeIterator();
|
||||||
|
while (it.next())
|
||||||
|
MHD_add_response_header(response, it.key().dataAscii(), it.value().dataUTF8());
|
||||||
|
piCout << "status" << r.code;
|
||||||
|
int ret = MHD_queue_response(connection, r.code, response);
|
||||||
|
MHD_destroy_response(response);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int MicrohttpdServerConnection::send_error() {
|
||||||
|
return MHD_queue_response(connection, MHD_HTTP_BAD_REQUEST, MHD_create_response_from_buffer(0, nullptr, MHD_RESPMEM_MUST_COPY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int iterate_post(void * conn_cls,
|
||||||
|
MHD_ValueKind kind,
|
||||||
|
const char * key,
|
||||||
|
const char * filename,
|
||||||
|
const char * content_type,
|
||||||
|
const char * transfer_encoding,
|
||||||
|
const char * data,
|
||||||
|
uint64_t off,
|
||||||
|
size_t size) {
|
||||||
|
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)conn_cls;
|
||||||
|
if (!conn) return MHD_NO;
|
||||||
|
conn->post[PIString::fromUTF8(key)] = PIString::fromUTF8(data);
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void request_completed(void * cls, MHD_Connection * connection, void ** con_cls, MHD_RequestTerminationCode toe) {
|
||||||
|
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||||
|
// qDebug() << "request_completed" << conn << conn->headers << conn->post << '"' << conn->body << '"';
|
||||||
|
if (!conn) return;
|
||||||
|
if (conn->method == MicrohttpdServer::Method::Post && conn->postprocessor) MHD_destroy_post_processor(conn->postprocessor);
|
||||||
|
conn->ready();
|
||||||
|
piDeleteSafety(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
int header_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||||
|
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||||
|
if (!conn) return MHD_NO;
|
||||||
|
conn->headers[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
int args_iterate(void * cls, MHD_ValueKind kind, const char * key, const char * value) {
|
||||||
|
MicrohttpdServerConnection * conn = (MicrohttpdServerConnection *)cls;
|
||||||
|
if (!conn) return MHD_NO;
|
||||||
|
conn->args[PIString::fromUTF8(key)] = PIString::fromUTF8(value);
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int answer_to_connection(void * cls,
|
||||||
|
MHD_Connection * connection,
|
||||||
|
const char * url,
|
||||||
|
const char * method,
|
||||||
|
const char * version,
|
||||||
|
const char * upload_data,
|
||||||
|
size_t * upload_data_size,
|
||||||
|
void ** con_cls) {
|
||||||
|
MicrohttpdServer * server = (MicrohttpdServer *)cls;
|
||||||
|
|
||||||
|
MicrohttpdServer::Method m = MicrohttpdServer::Method::Unknown;
|
||||||
|
|
||||||
|
if (0 == strcmp(method, "GET"))
|
||||||
|
m = MicrohttpdServer::Method::Get;
|
||||||
|
else if (0 == strcmp(method, "POST"))
|
||||||
|
m = MicrohttpdServer::Method::Post;
|
||||||
|
else if (0 == strcmp(method, "HEAD"))
|
||||||
|
m = MicrohttpdServer::Method::Head;
|
||||||
|
else if (0 == strcmp(method, "PUT"))
|
||||||
|
m = MicrohttpdServer::Method::Put;
|
||||||
|
else if (0 == strcmp(method, "DELETE"))
|
||||||
|
m = MicrohttpdServer::Method::Delete;
|
||||||
|
else if (0 == strcmp(method, "CONNECT"))
|
||||||
|
m = MicrohttpdServer::Method::Connect;
|
||||||
|
else if (0 == strcmp(method, "OPTIONS"))
|
||||||
|
m = MicrohttpdServer::Method::Options;
|
||||||
|
else if (0 == strcmp(method, "TRACE"))
|
||||||
|
m = MicrohttpdServer::Method::Trace;
|
||||||
|
else if (0 == strcmp(method, "PATCH"))
|
||||||
|
m = MicrohttpdServer::Method::Patch;
|
||||||
|
|
||||||
|
if (m == MicrohttpdServer::Method::Unknown) {
|
||||||
|
piCout << "[MicrohttpdServer] Unknown method!";
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// piCout << "answer" << url << method << server;
|
||||||
|
MicrohttpdServerConnection *& conn((MicrohttpdServerConnection *&)(*con_cls));
|
||||||
|
if (!conn) {
|
||||||
|
conn = new MicrohttpdServerConnection();
|
||||||
|
conn->connection = connection;
|
||||||
|
conn->server = server;
|
||||||
|
conn->path = PIString::fromUTF8(url);
|
||||||
|
conn->method = m;
|
||||||
|
MHD_get_connection_values(connection, MHD_HEADER_KIND, (MHD_KeyValueIterator)header_iterate, *con_cls);
|
||||||
|
MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, (MHD_KeyValueIterator)args_iterate, *con_cls);
|
||||||
|
|
||||||
|
if (m == MicrohttpdServer::Method::Post) {
|
||||||
|
// qDebug() << "new POST" << *upload_data_size;
|
||||||
|
conn->postprocessor = MHD_create_post_processor(connection, 65536, (MHD_PostDataIterator)iterate_post, (void *)conn);
|
||||||
|
}
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m) {
|
||||||
|
case MicrohttpdServer::Method::Get:
|
||||||
|
if (!conn->ready()) return conn->send_error();
|
||||||
|
return MHD_YES;
|
||||||
|
case MicrohttpdServer::Method::Post:
|
||||||
|
// qDebug() << "add POST" << *upload_data_size << PIString::fromUtf8(upload_data, *upload_data_size);
|
||||||
|
if (*upload_data_size) {
|
||||||
|
conn->body.append(upload_data, *upload_data_size);
|
||||||
|
if (conn->postprocessor) MHD_post_process(conn->postprocessor, upload_data, *upload_data_size);
|
||||||
|
*upload_data_size = 0;
|
||||||
|
return MHD_YES;
|
||||||
|
} else {
|
||||||
|
// qDebug() << "answer ok";
|
||||||
|
if (!conn->ready()) return conn->send_error();
|
||||||
|
return MHD_YES;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn->send_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRIVATE_DEFINITION_START(MicrohttpdServer)
|
||||||
|
MHD_Daemon * daemon;
|
||||||
|
PRIVATE_DEFINITION_END(MicrohttpdServer)
|
||||||
|
|
||||||
|
|
||||||
|
MicrohttpdServer::MicrohttpdServer() {
|
||||||
|
PRIVATE->daemon = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MicrohttpdServer::~MicrohttpdServer() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::setWWWRoot(const PIString & path) {
|
||||||
|
www_root = path;
|
||||||
|
if (www_root.isEmpty()) return;
|
||||||
|
www_root = PIDir(www_root).absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::setFavicon(const PIByteArray & im) {
|
||||||
|
favicon = im;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MicrohttpdServer::listen(PINetworkAddress addr) {
|
||||||
|
stop();
|
||||||
|
uint flags = 0;
|
||||||
|
#if MHD_VERSION <= 0x00095100
|
||||||
|
flags = MHD_USE_POLL_INTERNALLY;
|
||||||
|
#else
|
||||||
|
flags = MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD;
|
||||||
|
#endif
|
||||||
|
sockaddr_in sa_addr;
|
||||||
|
memset(&sa_addr, 0, sizeof(sa_addr));
|
||||||
|
sa_addr.sin_port = htons(addr.port());
|
||||||
|
sa_addr.sin_addr.s_addr = addr.ip();
|
||||||
|
sa_addr.sin_family = AF_INET;
|
||||||
|
PRIVATE->daemon = MHD_start_daemon(flags,
|
||||||
|
addr.port(),
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
(MHD_AccessHandlerCallback)answer_to_connection,
|
||||||
|
this,
|
||||||
|
MHD_OPTION_NOTIFY_COMPLETED,
|
||||||
|
request_completed,
|
||||||
|
nullptr,
|
||||||
|
MHD_OPTION_SOCK_ADDR,
|
||||||
|
&sa_addr,
|
||||||
|
MHD_OPTION_END);
|
||||||
|
return isListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MicrohttpdServer::isListen() const {
|
||||||
|
return PRIVATE->daemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIByteArray MicrohttpdServer::getFile(PIString name) {
|
||||||
|
if (www_root.isEmpty()) return PIByteArray();
|
||||||
|
if (name == "/") name += "index.html";
|
||||||
|
PIString path = PIDir(www_root).relative(name);
|
||||||
|
// qDebug() << "getFile" << path;
|
||||||
|
if (path.isEmpty() || !path.startsWith(www_root)) return PIByteArray();
|
||||||
|
return PIFile::readAll(PIDir(www_root).absolute(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::stop() {
|
||||||
|
if (PRIVATE->daemon) {
|
||||||
|
MHD_stop_daemon(PRIVATE->daemon);
|
||||||
|
PRIVATE->daemon = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::Reply::addHeader(const PIString & header, const PIString & value) {
|
||||||
|
headers[header] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::Reply::removeHeader(const PIString & header) {
|
||||||
|
headers.remove(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::Reply::setBody(const PIByteArray & b) {
|
||||||
|
body = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::Reply::setCode(int c) {
|
||||||
|
code = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MicrohttpdServer::Reply::addFixedHeaders() {
|
||||||
|
if (!headers.contains(MHD_HTTP_HEADER_CONTENT_TYPE)) {
|
||||||
|
if (body.startsWith(PIByteArray::fromAscii("<!DOCTYPE html>")))
|
||||||
|
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html; charset=utf-8");
|
||||||
|
else
|
||||||
|
addHeader(MHD_HTTP_HEADER_CONTENT_TYPE, "application/json; charset=utf-8");
|
||||||
|
}
|
||||||
|
addHeader(MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||||
|
}
|
||||||
50
libs/http_server/pihttpserver.cpp
Normal file
50
libs/http_server/pihttpserver.cpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#include "pihttpserver.h"
|
||||||
|
|
||||||
|
#include "piliterals_string.h"
|
||||||
|
|
||||||
|
|
||||||
|
PIHTTPServer::PIHTTPServer() {
|
||||||
|
setRequestCallback([this](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
|
MicrohttpdServer::Reply rep;
|
||||||
|
rep.setCode(404);
|
||||||
|
auto in_path = r.path.split("/");
|
||||||
|
in_path.removeAll("");
|
||||||
|
auto it = functions.makeReverseIterator();
|
||||||
|
while (it.next()) {
|
||||||
|
if (it.value().function) {
|
||||||
|
if (it.value().match(in_path)) {
|
||||||
|
rep.setCode(200);
|
||||||
|
rep = it.value().function(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto hit = reply_headers.makeIterator();
|
||||||
|
while (hit.next())
|
||||||
|
rep.addHeader(hit.key(), hit.value());
|
||||||
|
return rep;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIHTTPServer::~PIHTTPServer() {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PIHTTPServer::registerPath(const PIString & path, RequestFunction functor) {
|
||||||
|
auto & ep(functions[path]);
|
||||||
|
ep.path = path.split("/");
|
||||||
|
ep.function = functor;
|
||||||
|
ep.path.removeAll("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIHTTPServer::Endpoint::match(const PIStringList & in_path) const {
|
||||||
|
if (in_path.size() != path.size()) return false;
|
||||||
|
for (int i = 0; i < path.size_s(); ++i) {
|
||||||
|
if (path[i] == "*"_a) continue;
|
||||||
|
if (path[i] != in_path[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
75
libs/main/http_server/microhttpd_server_p.h
Normal file
75
libs/main/http_server/microhttpd_server_p.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#ifndef MICROHTTPD_SERVER_P_H
|
||||||
|
#define MICROHTTPD_SERVER_P_H
|
||||||
|
|
||||||
|
#include "pibase.h"
|
||||||
|
#include "piobject.h"
|
||||||
|
#include "pip_http_server_export.h"
|
||||||
|
|
||||||
|
struct MicrohttpdServerConnection;
|
||||||
|
|
||||||
|
class PIP_HTTP_SERVER_EXPORT MicrohttpdServer: public PIObject {
|
||||||
|
PIOBJECT(MicrohttpdServer)
|
||||||
|
friend struct MicrohttpdServerConnection;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MicrohttpdServer();
|
||||||
|
virtual ~MicrohttpdServer();
|
||||||
|
|
||||||
|
enum class Method {
|
||||||
|
Unknown,
|
||||||
|
Get,
|
||||||
|
Head,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Delete,
|
||||||
|
Connect,
|
||||||
|
Options,
|
||||||
|
Trace,
|
||||||
|
Patch
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PIP_HTTP_SERVER_EXPORT Request {
|
||||||
|
MicrohttpdServer::Method method;
|
||||||
|
PIString path;
|
||||||
|
PIByteArray body;
|
||||||
|
PIMap<PIString, PIString> headers;
|
||||||
|
PIMap<PIString, PIString> args;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PIP_HTTP_SERVER_EXPORT Reply {
|
||||||
|
friend struct MicrohttpdServerConnection;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addHeader(const PIString & header, const PIString & value);
|
||||||
|
void removeHeader(const PIString & header);
|
||||||
|
void setBody(const PIByteArray & b);
|
||||||
|
void setCode(int c);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addFixedHeaders();
|
||||||
|
int code = 200;
|
||||||
|
PIByteArray body;
|
||||||
|
PIMap<PIString, PIString> headers;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setWWWRoot(const PIString & path);
|
||||||
|
void setFavicon(const PIByteArray & im);
|
||||||
|
|
||||||
|
bool listen(PINetworkAddress addr);
|
||||||
|
bool listenAll(ushort port) { return listen({0, port}); }
|
||||||
|
bool isListen() const;
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void setRequestCallback(std::function<Reply(Request)> c) { callback = c; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
PIByteArray getFile(PIString name);
|
||||||
|
|
||||||
|
PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT)
|
||||||
|
PIString www_root;
|
||||||
|
PIByteArray favicon;
|
||||||
|
std::function<Reply(Request)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
33
libs/main/http_server/pihttpserver.h
Normal file
33
libs/main/http_server/pihttpserver.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef PIHTTPSERVER_H
|
||||||
|
#define PIHTTPSERVER_H
|
||||||
|
|
||||||
|
#include "microhttpd_server_p.h"
|
||||||
|
#include "pip_http_server_export.h"
|
||||||
|
|
||||||
|
class PIP_HTTP_SERVER_EXPORT PIHTTPServer: public MicrohttpdServer {
|
||||||
|
PIOBJECT_SUBCLASS(PIHTTPServer, MicrohttpdServer)
|
||||||
|
|
||||||
|
public:
|
||||||
|
PIHTTPServer();
|
||||||
|
virtual ~PIHTTPServer();
|
||||||
|
|
||||||
|
using RequestFunction = std::function<MicrohttpdServer::Reply(const MicrohttpdServer::Request &)>;
|
||||||
|
|
||||||
|
void registerPath(const PIString & path, RequestFunction functor);
|
||||||
|
|
||||||
|
void addReplyHeader(const PIString & name, const PIString & value) { reply_headers[name] = value; }
|
||||||
|
void removeReplyHeader(const PIString & name) { reply_headers.remove(name); }
|
||||||
|
void clearReplyHeaders() { reply_headers.clear(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Endpoint {
|
||||||
|
bool match(const PIStringList & in_path) const;
|
||||||
|
PIStringList path;
|
||||||
|
RequestFunction function;
|
||||||
|
};
|
||||||
|
PIMap<PIString, PIString> reply_headers;
|
||||||
|
PIMap<PIString, Endpoint> functions;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -553,6 +553,17 @@ uint PIString::hash() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIByteArray PIString::toAscii() const {
|
||||||
|
if (isEmpty()) return PIByteArray();
|
||||||
|
PIByteArray ret;
|
||||||
|
ret.resize(size());
|
||||||
|
for (int i = 0; i < size_s(); ++i) {
|
||||||
|
ret[i] = uchar(at(i).ch);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PIByteArray PIString::toSystem() const {
|
PIByteArray PIString::toSystem() const {
|
||||||
if (isEmpty()) return PIByteArray();
|
if (isEmpty()) return PIByteArray();
|
||||||
buildData(__syslocname__);
|
buildData(__syslocname__);
|
||||||
|
|||||||
@@ -1107,6 +1107,10 @@ public:
|
|||||||
//! \~russian Тоже самое, что \a toUTF8().
|
//! \~russian Тоже самое, что \a toUTF8().
|
||||||
PIByteArray toByteArray() const { return toUTF8(); }
|
PIByteArray toByteArray() const { return toUTF8(); }
|
||||||
|
|
||||||
|
//! \~english Returns \a PIByteArray contains \a dataAscii() of this string without terminating null-char.
|
||||||
|
//! \~russian Возвращает \a PIByteArray содержащий \a dataAscii() строки без завершающего нулевого байта.
|
||||||
|
PIByteArray toAscii() const;
|
||||||
|
|
||||||
//! \~english Returns \a PIByteArray contains \a data() of this string without terminating null-char.
|
//! \~english Returns \a PIByteArray contains \a data() of this string without terminating null-char.
|
||||||
//! \~russian Возвращает \a PIByteArray содержащий \a data() строки без завершающего нулевого байта.
|
//! \~russian Возвращает \a PIByteArray содержащий \a data() строки без завершающего нулевого байта.
|
||||||
PIByteArray toSystem() const;
|
PIByteArray toSystem() const;
|
||||||
|
|||||||
@@ -32,16 +32,9 @@
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class PIP_EXPORT PIProtectedVariable {
|
class PIP_EXPORT PIProtectedVariable {
|
||||||
public:
|
public:
|
||||||
//! \~english Sets value to copy of \"v\"
|
//! \~english Sets value to \"v\"
|
||||||
//! \~russian Устанавливает значение как копию \"v\"
|
//! \~russian Устанавливает значение как \"v\"
|
||||||
void set(const T & v) {
|
void set(T v) {
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
var = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \~english Sets value by moving \"v\"
|
|
||||||
//! \~russian Устанавливает значение перемещением \"v\"
|
|
||||||
void set(T && v) {
|
|
||||||
PIMutexLocker _ml(mutex);
|
PIMutexLocker _ml(mutex);
|
||||||
var = std::move(v);
|
var = std::move(v);
|
||||||
}
|
}
|
||||||
@@ -64,10 +57,10 @@ public:
|
|||||||
//! \~russian Разблокирует мьютекс
|
//! \~russian Разблокирует мьютекс
|
||||||
void unlock() { mutex.unlock(); }
|
void unlock() { mutex.unlock(); }
|
||||||
|
|
||||||
//! \~english Sets value to copy of \"v\"
|
//! \~english Sets value to \"v\"
|
||||||
//! \~russian Устанавливает значение как копию \"v\"
|
//! \~russian Устанавливает значение как \"v\"
|
||||||
PIProtectedVariable<T> & operator=(const T & v) {
|
PIProtectedVariable<T> & operator=(T v) {
|
||||||
set(v);
|
set(std::move(v));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,20 @@ struct base64HelpStruct {
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
bool PIByteArray::startsWith(const PIByteArray & o) const {
|
||||||
|
if (o.isEmpty()) return false;
|
||||||
|
if (size() < o.size()) return false;
|
||||||
|
return piCompareBinary(data(), o.data(), o.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PIByteArray::endsWith(const PIByteArray & o) const {
|
||||||
|
if (o.isEmpty()) return false;
|
||||||
|
if (size() < o.size()) return false;
|
||||||
|
return piCompareBinary(data(size() - o.size()), o.data(), o.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PIByteArray & PIByteArray::convertToBase64() {
|
PIByteArray & PIByteArray::convertToBase64() {
|
||||||
return *this = toBase64();
|
return *this = toBase64();
|
||||||
}
|
}
|
||||||
@@ -396,6 +410,17 @@ PIByteArray PIByteArray::fromHex(PIString str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIByteArray PIByteArray::fromAscii(const char * str) {
|
||||||
|
PIByteArray ret;
|
||||||
|
int ind = 0;
|
||||||
|
while (str[ind] != 0) {
|
||||||
|
ret.append(str[ind]);
|
||||||
|
++ind;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PICout operator<<(PICout s, const PIByteArray & ba) {
|
PICout operator<<(PICout s, const PIByteArray & ba) {
|
||||||
s.space();
|
s.space();
|
||||||
s.saveAndSetControls(0);
|
s.saveAndSetControls(0);
|
||||||
|
|||||||
@@ -340,6 +340,10 @@ public:
|
|||||||
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
|
//! \~\sa \a every(), \a any(), \a contains(), \a indexWhere()
|
||||||
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const { return d.entries(test, start); }
|
inline int entries(std::function<bool(uchar e)> test, ssize_t start = 0) const { return d.entries(test, start); }
|
||||||
|
|
||||||
|
bool startsWith(const PIByteArray & o) const;
|
||||||
|
|
||||||
|
bool endsWith(const PIByteArray & o) const;
|
||||||
|
|
||||||
//! \~english Returns the first index at which a given element `e`
|
//! \~english Returns the first index at which a given element `e`
|
||||||
//! can be found in the array, or `-1` if it is not present.
|
//! can be found in the array, or `-1` if it is not present.
|
||||||
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
//! \~russian Возвращает первый индекс, по которому данный элемент `e`
|
||||||
@@ -1165,6 +1169,8 @@ public:
|
|||||||
|
|
||||||
static PIByteArray fromHex(PIString str);
|
static PIByteArray fromHex(PIString str);
|
||||||
|
|
||||||
|
static PIByteArray fromAscii(const char * str);
|
||||||
|
|
||||||
//! \~english Return converted from Base 64 data
|
//! \~english Return converted from Base 64 data
|
||||||
//! \~russian Возвращает массив из Base 64 представления
|
//! \~russian Возвращает массив из Base 64 представления
|
||||||
static PIByteArray fromBase64(const PIByteArray & base64);
|
static PIByteArray fromBase64(const PIByteArray & base64);
|
||||||
|
|||||||
250
main.cpp
250
main.cpp
@@ -1,220 +1,64 @@
|
|||||||
#include "pibytearray.h"
|
#include "pihttpserver.h"
|
||||||
#include "piclientserver_client.h"
|
|
||||||
#include "piclientserver_server.h"
|
|
||||||
#include "picodeparser.h"
|
|
||||||
#include "piintrospection_server.h"
|
|
||||||
#include "piiostream.h"
|
|
||||||
#include "pijson.h"
|
|
||||||
#include "pilog.h"
|
|
||||||
#include "pimathbase.h"
|
|
||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
#include "piprotectedvariable.h"
|
|
||||||
#include "pitranslator_p.h"
|
|
||||||
#include "pivaluetree_conversions.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
using namespace PICoutManipulators;
|
using namespace PICoutManipulators;
|
||||||
/*
|
|
||||||
class MyStr: public PIString {
|
|
||||||
public:
|
|
||||||
MyStr(): PIString() {}
|
|
||||||
MyStr(const char * o): PIString(o) { piCout << "MyStr *"; }
|
|
||||||
MyStr(const MyStr & o): PIString(o) { piCout << "MyStr &"; }
|
|
||||||
// MyStr(const MyStr & o): PIString(o) { piCout << "MyStr &"; }
|
|
||||||
MyStr(MyStr && o): PIString(o) { piCout << "MyStr &&"; }
|
|
||||||
MyStr & operator=(const MyStr & o) {
|
|
||||||
*this += o;
|
|
||||||
piCout << "MyStr =&";
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
MyStr & operator=(MyStr && o) {
|
|
||||||
*this += o;
|
|
||||||
piCout << "MyStr =&&";
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
PIKbdListener kbd;
|
||||||
|
const char * pageTitle = "<!DOCTYPE html>"
|
||||||
|
"<html>"
|
||||||
|
"<body>"
|
||||||
|
"<h1>Title</h1>"
|
||||||
|
"</body>"
|
||||||
|
"</html>";
|
||||||
|
|
||||||
class RWL {
|
|
||||||
public:
|
|
||||||
void lockWrite() {
|
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
while (reading > 0 || writing) {
|
|
||||||
var.wait(mutex);
|
|
||||||
}
|
|
||||||
writing = true;
|
|
||||||
}
|
|
||||||
void unlockWrite() {
|
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
writing = false;
|
|
||||||
var.notifyAll();
|
|
||||||
}
|
|
||||||
void lockRead() {
|
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
while (writing) {
|
|
||||||
var.wait(mutex);
|
|
||||||
}
|
|
||||||
++reading;
|
|
||||||
}
|
|
||||||
void unlockRead() {
|
|
||||||
PIMutexLocker _ml(mutex);
|
|
||||||
--reading;
|
|
||||||
var.notifyAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PIConditionVariable var;
|
|
||||||
int reading = 0;
|
|
||||||
bool writing = false;
|
|
||||||
PIMutex mutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
PIMutex mutex;
|
|
||||||
PISemaphore sem(10);
|
|
||||||
PIReadWriteLock rwl;
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
/*sem.acquire(2);
|
kbd.enableExitCapture();
|
||||||
piCout << sem.tryAcquire(2);
|
|
||||||
piCout << sem.available();
|
|
||||||
return 0;*/
|
|
||||||
PIThread t_w0(
|
|
||||||
[] {
|
|
||||||
// PIMutexLocker _ml(mutex);
|
|
||||||
PIWriteLocker rl(rwl);
|
|
||||||
piCout << "write0 start ...";
|
|
||||||
piMSleep(500);
|
|
||||||
piCout << "write0 end"
|
|
||||||
<< "\n";
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
1_Hz);
|
|
||||||
PIThread t_w1(
|
|
||||||
[] {
|
|
||||||
// PIMutexLocker _ml(mutex);
|
|
||||||
PIWriteLocker rl(rwl);
|
|
||||||
piCout << "write1 start ...";
|
|
||||||
piMSleep(500);
|
|
||||||
piCout << "write1 end"
|
|
||||||
<< "\n";
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
1_Hz);
|
|
||||||
|
|
||||||
int cnt0 = 0, cnt1 = 0;
|
PIHTTPServer server;
|
||||||
PIThread t_r0(
|
|
||||||
[&cnt0] {
|
|
||||||
// PIMutexLocker _ml(mutex);
|
|
||||||
PIReadLocker rl(rwl);
|
|
||||||
piCout << "read0 start ...";
|
|
||||||
piMSleep(50);
|
|
||||||
// bool ok = rwl.tryLockRead(100_ms);
|
|
||||||
// if (ok) ++cnt0;
|
|
||||||
piCout << "read0 end";
|
|
||||||
// if (ok) rwl.unlockRead();
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
10_Hz);
|
|
||||||
PIThread t_r1(
|
|
||||||
[&cnt1] {
|
|
||||||
// PIMutexLocker _ml(mutex);
|
|
||||||
// PIReadLocker rl(rwl);
|
|
||||||
piCout << "read1 start ...";
|
|
||||||
piMSleep(50);
|
|
||||||
bool ok = rwl.tryLockRead(100_ms);
|
|
||||||
if (ok) ++cnt1;
|
|
||||||
piCout << "read1 end" << ok;
|
|
||||||
if (ok) rwl.unlockRead();
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
11_Hz);
|
|
||||||
|
|
||||||
piSleep(8.);
|
server.setFavicon(PIFile::readAll("logo.png", false));
|
||||||
|
server.listen({"127.0.0.1", 7777});
|
||||||
|
|
||||||
t_r0.stopAndWait();
|
server.registerPath("/", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
t_r1.stopAndWait();
|
MicrohttpdServer::Reply ret;
|
||||||
t_w0.stopAndWait();
|
ret.setBody(PIByteArray::fromAscii(pageTitle));
|
||||||
t_w1.stopAndWait();
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
piCout << cnt0 << cnt1;
|
server.registerPath("/html", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
|
MicrohttpdServer::Reply ret;
|
||||||
|
ret.setBody("<!DOCTYPE html><html><body><p>arg=%1</p></body></html>"_a.arg(r.args.value("a0")).toUTF8());
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
/*PICodeParser parser;
|
server.registerPath("/api", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
parser.parseFile("client_server.h");
|
MicrohttpdServer::Reply ret;
|
||||||
for (auto m: parser.enums) {
|
ret.setBody(PIByteArray::fromAscii("<!DOCTYPE html><html><body>API</body></html>"));
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
server.registerPath("/api/*", [](const MicrohttpdServer::Request & r) -> MicrohttpdServer::Reply {
|
||||||
|
MicrohttpdServer::Reply ret;
|
||||||
|
ret.setBody("<!DOCTYPE html><html><body>API etry %1</body></html>"_a.arg(r.path).toUTF8());
|
||||||
|
ret.setCode(405);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
/*server.setRequestCallback([](MicrohttpdServer::Request r) -> MicrohttpdServer::Reply {
|
||||||
|
MicrohttpdServer::Reply rep;
|
||||||
|
piCout << "request" << r.path;
|
||||||
|
piCout << " header" << r.headers;
|
||||||
|
piCout << " args" << r.args;
|
||||||
|
piCout << " body" << r.body;
|
||||||
piCout << "";
|
piCout << "";
|
||||||
piCout << m.name; // << m.args << m.value;
|
rep.setBody(PIByteArray::fromAscii("[{\"value1\": true, \"value2\": \"ыекштп\"}]"));
|
||||||
// piCout << m.expand({"hello"});
|
return rep;
|
||||||
}*/
|
});*/
|
||||||
|
piCout << "start" << server.isListen();
|
||||||
|
|
||||||
return 0;
|
WAIT_FOR_EXIT
|
||||||
PITranslator::loadLang("ru");
|
|
||||||
PISerial f("COM123");
|
|
||||||
f.open();
|
|
||||||
|
|
||||||
/*auto test = [](PIString s, PIString v) {
|
|
||||||
piCout << " in:" << s;
|
|
||||||
piCout << "arg:" << minArgPlaceholder(s);
|
|
||||||
piCout << "out:" << arg(s, v);
|
|
||||||
piCout << "";
|
|
||||||
};
|
|
||||||
|
|
||||||
test(" %", "asd");
|
|
||||||
test("%", "asd");
|
|
||||||
test("1", "asd");
|
|
||||||
test(" %11", "asd");
|
|
||||||
test("%1%2 %0f%0g", "asd");
|
|
||||||
test("%01 ", "asd");*/
|
|
||||||
|
|
||||||
/*piCout << PIString::readableSize(50_KiB);
|
|
||||||
piCout << PIString::readableSize(1_GB);
|
|
||||||
PITranslator::loadLang("ru");
|
|
||||||
piCout << PIString::readableSize(50_KiB);
|
|
||||||
piCout << PIString::readableSize(1_GB);
|
|
||||||
piCout << "test\nstring"_tr;
|
|
||||||
PITranslator::clear();
|
|
||||||
piCout << PIString::readableSize(50_KiB);
|
|
||||||
piCout << PIString::readableSize(1_GB);
|
|
||||||
piCout << "test\nstring"_tr;
|
|
||||||
piCout << "hello!"_tr;
|
|
||||||
PITranslator::loadConfig("[]\nhello!=привет!\n[Co]\nhello!=привет CO!\n"_u8);
|
|
||||||
piCout << "hello!"_tr("Co") << "hello!"_tr;*/
|
|
||||||
// piCout << "hello!"_trNoOp;
|
|
||||||
|
|
||||||
|
|
||||||
/*PISet<int> set;
|
|
||||||
piCout << set << piSerialize(set) << piDeserialize<PISet<int>>(piSerialize(set));
|
|
||||||
set << 1 << 2 << 3;
|
|
||||||
piCout << set << piSerialize(set) << piDeserialize<PISet<int>>(piSerialize(set));
|
|
||||||
set << 1 << -2 << 50 << -100;
|
|
||||||
piCout << set << piSerialize(set) << piDeserialize<PISet<int>>(piSerialize(set));*/
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
std::numeric_limits<complexf>::epsilon();
|
|
||||||
using cmlp = complexf;
|
|
||||||
PIMathMatrixT<3, 3, double> v0;
|
|
||||||
PIMathMatrixT<3, 3, cmlp> v1;
|
|
||||||
v0[0][1] = 1;
|
|
||||||
v0[1][1] = 2;
|
|
||||||
v0[2][1] = 3;
|
|
||||||
v1[0][1] = cmlp(1., 0);
|
|
||||||
v1[1][1] = cmlp(2., -1);
|
|
||||||
v1[2][1] = cmlp(3., 2);
|
|
||||||
piCout << v0 << v1;
|
|
||||||
piCout << (v0 * 2.) << (v1 * cmlp(2., 2.));
|
|
||||||
piCout << (v0 + 2.) << (v1 + cmlp(2.));
|
|
||||||
piCout << (v0 - 2.) << (v1 - cmlp(2.));
|
|
||||||
piCout << (v0 / 2.) << (v1 / cmlp(2., 1.));
|
|
||||||
// piCout << (v0.length()) << (v1.length());
|
|
||||||
// piCout << (v0.lengthSqr()) << (v1.lengthSqr());
|
|
||||||
// piCout << (v0.manhattanLength()) << (v1.manhattanLength());
|
|
||||||
|
|
||||||
/*foo<int>();
|
|
||||||
foo<double>();
|
|
||||||
foo<complexf>();
|
|
||||||
foo<complexd>();
|
|
||||||
return 0;*/
|
|
||||||
|
|
||||||
|
server.stop();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user