Skip to content

Commit 94f47b1

Browse files
committed
added desktop runtime
1 parent 91592b0 commit 94f47b1

File tree

8 files changed

+331
-11
lines changed

8 files changed

+331
-11
lines changed

example/CMakeLists.txt

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,16 @@ configure_file(
2222
${CMAKE_CURRENT_BINARY_DIR}/archive.hpp
2323
@ONLY
2424
)
25-
26-
webframe_add_application(NAME example
27-
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
28-
INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}
29-
LINK_LIBRARIES yyjson::yyjson hyperpage::hyperpage
30-
RUNTIME server)
25+
if(WIN32)
26+
webframe_add_application(NAME example
27+
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
28+
INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}
29+
LINK_LIBRARIES yyjson::yyjson hyperpage::hyperpage
30+
RUNTIME desktop server)
31+
else()
32+
webframe_add_application(NAME example
33+
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
34+
INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}
35+
LINK_LIBRARIES yyjson::yyjson hyperpage::hyperpage
36+
RUNTIME server)
37+
endif()

include/webframe.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,17 @@
3232
#include <webframe/handler.hpp>
3333
#include <webframe/router.hpp>
3434

35-
#if defined(_WIN32) && defined(WEBFRAME_DESKTOP)
35+
#if defined(_WIN32) && defined(WEBFRAME_DESKTOP_RUNTIME)
3636
#define WEBFRAME_WIN32_APP 1
3737
#endif
3838

39+
#if defined(WEBFRAME_WIN32_APP)
40+
#ifndef WIN32_LEAN_AND_MEAN
41+
#define WIN32_LEAN_AND_MEAN
42+
#endif
43+
#include <windows.h>
44+
#endif
45+
3946
namespace webframe
4047
{
4148
enum class method
@@ -71,7 +78,7 @@ namespace webframe
7178
{
7279
public:
7380
#ifdef WEBFRAME_WIN32_APP
74-
virtual int dispatch(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow, application *a, router *r) = 0;
81+
virtual int dispatch(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, application *a, router *r) = 0;
7582
#else
7683
virtual int dispatch(int argc, const char **argv, application *a, router *r) = 0;
7784
#endif
@@ -82,12 +89,12 @@ namespace webframe
8289

8390
#if defined(WEBFRAME_WIN32_APP)
8491
#define WEBFRAME_MAIN(AppType) \
85-
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) \
92+
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \
8693
{ \
8794
std::unique_ptr<webframe::runtime> runtime(webframe::webframe_init()); \
8895
AppType app; \
8996
webframe::router router; \
90-
return runtime->dispatch(hInstance, hPrevInstance, pCmdLine, nCmdShow, &app, &router); \
97+
return runtime->dispatch(hInstance, hPrevInstance, lpCmdLine, nCmdShow, &app, &router); \
9198
}
9299
#else
93100
#define WEBFRAME_MAIN(AppType) \

src/CMakeLists.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ file(GLOB WEBFRAME_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
22
set(WEBFRAME_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include)
33

44
if(BUILD_RUNTIME)
5-
message(STATUS "Building desktop runtime")
5+
if(WIN32)
6+
file(GLOB WEBFRAME_DESKTOP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtimes/desktop/*.cpp)
7+
webframe_add_runtime(NAME desktop
8+
SOURCES ${WEBFRAME_SOURCES} ${WEBFRAME_DESKTOP_SOURCES}
9+
PUBLIC_INCLUDE_DIRS ${WEBFRAME_INCLUDE_DIR}
10+
PRIVATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/runtimes/desktop
11+
PUBLIC_LINK_LIBRARIES wx::core wx::webview)
12+
target_compile_definitions(webframe_desktop PUBLIC WEBFRAME_DESKTOP_RUNTIME=1)
13+
endif()
614
file(GLOB WEBFRAME_SERVER_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtimes/server/*.cpp)
715
webframe_add_runtime(NAME server
816
SOURCES ${WEBFRAME_SOURCES} ${WEBFRAME_SERVER_SOURCES}

src/runtimes/desktop/desktop.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef WEBFRAME_DESKTOP_HPP
2+
#define WEBFRAME_DESKTOP_HPP
3+
4+
#include <webframe.hpp>
5+
6+
#include <wx/wx.h>
7+
#include <wx/webview.h>
8+
#include <wx/uri.h>
9+
10+
class wfApp;
11+
12+
namespace webframe::desktop
13+
{
14+
class request : public webframe::request
15+
{
16+
public:
17+
request(const wxWebViewHandlerRequest *request);
18+
~request() = default;
19+
webframe::method get_method() const override;
20+
std::string get_path() const override;
21+
bool get_header(const std::string &key, std::string &value) const override;
22+
std::pair<const uint8_t *, size_t> get_body() const override;
23+
void read_body(const std::function<void(const uint8_t *, size_t)> &callback) const override;
24+
private:
25+
const wxWebViewHandlerRequest *_request;
26+
wxString _body;
27+
};
28+
29+
class response : public webframe::response
30+
{
31+
public:
32+
response(wxWebViewHandlerResponse *response, bool &sent);
33+
~response() = default;
34+
void set_status(int status) override;
35+
void set_header(const std::string &key, const std::string &value) override;
36+
void set_body(const uint8_t *data, size_t size) override;
37+
void write_body(const std::function<bool(std::pair<const uint8_t *, size_t> &)> &callback) override;
38+
private:
39+
wxWebViewHandlerResponse *_response;
40+
bool &_sent;
41+
};
42+
43+
class webview_handler : public wxWebViewHandler
44+
{
45+
public:
46+
webview_handler(webframe::router *router);
47+
~webview_handler() = default;
48+
void StartRequest(const wxWebViewHandlerRequest& request, wxSharedPtr<wxWebViewHandlerResponse> response) override;
49+
private:
50+
webframe::router *_router;
51+
};
52+
53+
class runtime : public webframe::runtime
54+
{
55+
public:
56+
#ifdef WEBFRAME_WIN32_APP
57+
int dispatch(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, webframe::application *a, webframe::router *r) override;
58+
#else
59+
int dispatch(int argc, const char **argv, webframe::application *a, webframe::router *r) override;
60+
#endif
61+
private:
62+
int launch_wx_app(wfApp *app, webframe::application *a, webframe::router *r);
63+
};
64+
}
65+
66+
#endif

src/runtimes/desktop/request.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include <desktop.hpp>
2+
3+
namespace webframe
4+
{
5+
namespace desktop
6+
{
7+
request::request(const wxWebViewHandlerRequest *request) : _request(request)
8+
{
9+
_body = _request->GetDataString();
10+
}
11+
12+
webframe::method request::get_method() const
13+
{
14+
const wxString method = _request->GetMethod();
15+
webframe::method result;
16+
if (method == "GET")
17+
{
18+
result = webframe::method::http_get;
19+
}
20+
else if (method == "POST")
21+
{
22+
result = webframe::method::http_post;
23+
}
24+
else if (method == "PUT")
25+
{
26+
result = webframe::method::http_put;
27+
}
28+
else if (method == "DELETE")
29+
{
30+
result = webframe::method::http_delete;
31+
}
32+
else
33+
{
34+
result = static_cast<webframe::method>(-1);
35+
}
36+
return result;
37+
}
38+
39+
std::string request::get_path() const
40+
{
41+
wxURI uri = _request->GetURI();
42+
wxString uri_path = uri.GetPath();
43+
if (!uri_path.StartsWith("/"))
44+
{
45+
uri_path.Prepend("/");
46+
}
47+
return std::string(uri_path.ToStdString());
48+
}
49+
50+
bool request::get_header(const std::string &key, std::string &value) const
51+
{
52+
wxString header_value = _request->GetHeader(key);
53+
bool result(false);
54+
if (!header_value.empty())
55+
{
56+
value = std::string(header_value.ToStdString());
57+
result = true;
58+
}
59+
return result;
60+
}
61+
62+
std::pair<const uint8_t *, size_t> request::get_body() const
63+
{
64+
const uint8_t *data = reinterpret_cast<const uint8_t *>(_body.GetData().AsCharBuf().data());
65+
size_t size = _body.size();
66+
return { data, size };
67+
}
68+
69+
void request::read_body(const std::function<void(const uint8_t *, size_t)> &callback) const
70+
{
71+
const auto& [data, size] = get_body();
72+
callback(data, size);
73+
}
74+
}
75+
}

src/runtimes/desktop/response.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include <desktop.hpp>
2+
3+
namespace webframe
4+
{
5+
namespace desktop
6+
{
7+
response::response(wxWebViewHandlerResponse *response, bool &sent) : _response(response), _sent(sent)
8+
{
9+
}
10+
11+
void response::set_status(int status)
12+
{
13+
_response->SetStatus(status);
14+
}
15+
16+
void response::set_header(const std::string &key, const std::string &value)
17+
{
18+
_response->SetHeader(key, value);
19+
}
20+
21+
void response::set_body(const uint8_t *data, size_t size)
22+
{
23+
_response->Finish(std::string(reinterpret_cast<const char *>(data), size));
24+
_sent = true;
25+
}
26+
27+
void response::write_body(const std::function<bool(std::pair<const uint8_t *, size_t> &)> &callback)
28+
{
29+
std::vector<uint8_t> buffer;
30+
bool has_more_data = true;
31+
while (has_more_data)
32+
{
33+
std::pair<const uint8_t *, size_t> data;
34+
if (callback(data))
35+
{
36+
buffer.insert(buffer.end(), data.first, data.first + data.second);
37+
}
38+
else
39+
{
40+
has_more_data = false;
41+
}
42+
}
43+
set_body(buffer.data(), buffer.size());
44+
}
45+
}
46+
}

src/runtimes/desktop/runtime.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <desktop.hpp>
2+
3+
class wfApp : public wxApp
4+
{
5+
public:
6+
void Init(webframe::application *application, webframe::router *router)
7+
{
8+
_application = application;
9+
_router = router;
10+
}
11+
bool OnInit() override
12+
{
13+
_application->configure_desktop();
14+
_application->configure_router(_router);
15+
_frame = std::make_unique<wxFrame>(nullptr, wxID_ANY, "WebFrame");
16+
_webview = wxWebView::New(_frame.get(), wxID_ANY, "about:blank", wxDefaultPosition, wxDefaultSize, wxWebViewBackendEdge);
17+
#ifdef __WXMSW__
18+
_webview->Bind(wxEVT_WEBVIEW_NAVIGATING, [](wxWebViewEvent &event)
19+
{
20+
const wxString url = event.GetURL();
21+
if (!url.StartsWith("https://webframe.ipc"))
22+
{
23+
event.Skip();
24+
} });
25+
#endif
26+
_webview->Bind(wxEVT_WEBVIEW_CREATED, [this](wxWebViewEvent &event)
27+
{
28+
wxWebView *webview = reinterpret_cast<wxWebView *>(event.GetEventObject());
29+
webview->RegisterHandler(wxSharedPtr<wxWebViewHandler>(new webframe::desktop::webview_handler(_router)));
30+
webview->LoadURL("https://webframe.ipc/index.html");
31+
});
32+
_frame->Show();
33+
return true;
34+
}
35+
36+
private:
37+
std::unique_ptr<wxFrame> _frame;
38+
wxWebView *_webview;
39+
webframe::application *_application;
40+
webframe::router *_router;
41+
};
42+
43+
namespace webframe
44+
{
45+
namespace desktop
46+
{
47+
int runtime::launch_wx_app(wfApp *app, webframe::application *a, webframe::router *r)
48+
{
49+
int result(0);
50+
app->Init(a, r);
51+
if (app->CallOnInit())
52+
{
53+
a->on_dispatch();
54+
result = app->OnRun();
55+
}
56+
else
57+
{
58+
result = 1;
59+
}
60+
wxEntryCleanup();
61+
return result;
62+
}
63+
}
64+
65+
runtime *webframe_init()
66+
{
67+
return new desktop::runtime();
68+
}
69+
}
70+
71+
// keep platform specific garbage down here
72+
wxIMPLEMENT_APP_NO_MAIN(wfApp);
73+
#ifdef WEBFRAME_WIN32_APP
74+
#include <wx/msw/init.h>
75+
int webframe::desktop::runtime::dispatch(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, webframe::application *a, webframe::router *r)
76+
{
77+
wxEntryStart(hInstance);
78+
return launch_wx_app(reinterpret_cast<wfApp *>(wxTheApp), a, r);
79+
}
80+
#else
81+
int webframe::desktop::runtime::dispatch(int argc, const char **argv, webframe::application *a, webframe::router *r)
82+
{
83+
wxEntryStart(argc, const_cast<char **>(argv));
84+
return launch_wx_app(reinterpret_cast<wfApp *>(wxTheApp), a, r);
85+
}
86+
#endif
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <desktop.hpp>
2+
3+
namespace webframe
4+
{
5+
namespace desktop
6+
{
7+
webview_handler::webview_handler(webframe::router *router) : wxWebViewHandler("https"), _router(router)
8+
{
9+
SetVirtualHost("webframe.ipc");
10+
}
11+
12+
void webview_handler::StartRequest(const wxWebViewHandlerRequest& request, wxSharedPtr<wxWebViewHandlerResponse> response)
13+
{
14+
bool sent(false);
15+
webframe::desktop::request req(&request);
16+
webframe::desktop::response res(response.get(), sent);
17+
webframe::handler *handler = _router->find_route(req.get_path());
18+
handler->handle_request(&req, &res);
19+
if (!sent)
20+
{
21+
response->Finish("");
22+
}
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)