-
Notifications
You must be signed in to change notification settings - Fork 3
/
weblegends.h
187 lines (155 loc) · 5.65 KB
/
weblegends.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#pragma once
#include <queue>
#include <typeinfo>
#include "Core.h"
#include <Console.h>
#include <Export.h>
#include <PluginManager.h>
#include "DataDefs.h"
#define NOMINMAX
#include "PassiveSocket.h"
#include "ActiveSocket.h"
#include "tinythread.h"
#ifndef HAVE_NULLPTR
#define nullptr 0L
#endif
using namespace DFHack;
using namespace df::enums;
#include "weblegends-plugin.h"
#include "debug.h"
DFhackDataExport extern std::vector<std::string> *plugin_globals;
class Client;
class Layout;
class WebLegends
{
CPassiveSocket sock;
tthread::thread *thread;
bool do_shutdown;
std::vector<Client *> to_delete;
std::vector<Client *> clients;
protected:
tthread::mutex to_delete_lock;
public:
WebLegends() : sock(), thread(nullptr), do_shutdown(false) {}
~WebLegends() {}
command_result init(color_ostream & out);
command_result shutdown(color_ostream & out);
command_result export_all(color_ostream & out, const std::string & folder);
command_result export_recursive(color_ostream & out, std::set<std::string> & exported, std::queue<std::string> & queue, const std::string & folder);
void queue_linked_pages(std::queue<std::string> & queue, const std::string & url, std::string & body);
protected:
void mark(Client *c);
bool http(CActiveSocket *sock, std::string & request);
friend class Client;
private:
static void run(void *wl);
void run();
bool cleanup();
inline static weblegends_handlers_v0_t *get_handlers_v0()
{
return static_cast<weblegends_handlers_v0_t *>(Core::getInstance().GetData(WEBLEGENDS_PLUGIN_HANDLERS_V0));
}
inline static weblegends_handlers_v1_t *get_handlers_v1()
{
return static_cast<weblegends_handlers_v1_t *>(Core::getInstance().GetData(WEBLEGENDS_PLUGIN_HANDLERS_V1));
}
void handle(CActiveSocket *sock, const std::string & method, const std::string & url, char http1Point, bool keepAlive);
bool request(weblegends_handler_v1 & response, const std::string & url);
static bool is_world_loaded();
static void render_home(Layout & l);
static void render_sidebar(Layout & l);
static bool render_entity(Layout & l, int32_t id, int32_t page);
static bool render_era(Layout & l, int32_t id, int32_t page);
static bool render_eventcol(Layout & l, int32_t id, int32_t page);
static bool render_figure(Layout & l, int32_t id, int32_t page);
static bool render_item(Layout & l, int32_t id, int32_t page);
static bool render_region(Layout & l, int32_t id, int32_t page);
static bool render_site(Layout & l, int32_t id, int32_t page);
static bool render_structure(Layout & l, int32_t site_id, int32_t id, int32_t page);
static bool render_layer(Layout & l, int32_t id, int32_t page);
static bool render_entity_list(Layout & l, int32_t page);
static bool render_era_list(Layout & l, int32_t page);
static bool render_eventcol_list(Layout & l, int32_t page);
static bool render_figure_list(Layout & l, int32_t page);
static bool render_item_list(Layout & l, int32_t page);
static bool render_region_list(Layout & l, int32_t page);
static bool render_site_list(Layout & l, int32_t page);
static bool render_layer_list(Layout & l, int32_t page);
};
class weblegends_handler_v1_impl : public weblegends_handler_v1
{
class cp437_streambuf : public std::streambuf
{
public:
cp437_streambuf(std::streambuf *raw) : raw(raw) {}
std::streambuf *raw;
protected:
virtual int_type overflow(int_type c)
{
if (c != EOF)
{
auto utf8 = DF2UTF(std::string(1, char(c)));
if (raw->sputn(utf8.c_str(), std::streamsize(utf8.size())) != std::streamsize(utf8.size()))
{
c = EOF;
}
}
return c;
}
};
weblegends_handler_v1_impl() :
current_status_code(200),
current_status_description("OK"),
current_headers(),
body_raw(),
cp437_buf(body_raw.rdbuf()),
body_cp437(&cp437_buf)
{
current_headers["Content-Type"] = "text/html; charset=utf-8";
}
friend class WebLegends;
int32_t current_status_code;
std::string current_status_description;
std::map<std::string, std::string> current_headers;
std::ostringstream body_raw;
cp437_streambuf cp437_buf;
std::ostream body_cp437;
public:
virtual int32_t & status_code() { return current_status_code; }
virtual std::string & status_description() { return current_status_description; }
virtual std::map<std::string, std::string> & headers() { return current_headers; }
virtual std::ostream & cp437_out() { return body_cp437; }
virtual std::ostream & raw_out() { return body_raw; }
};
class Client
{
WebLegends *weblegends;
CActiveSocket *sock;
tthread::thread *thread;
public:
Client(WebLegends *weblegends, CActiveSocket *sock);
~Client();
private:
static void run(void *c);
void run();
protected:
bool start();
void kill();
void join();
friend class WebLegends;
};
class Layout : public weblegends_layout_v1
{
public:
std::ostringstream header_nav;
std::ostringstream sidebar_nav;
std::string title_html;
std::string base_html;
bool in_sidebar_section{};
void set_title(const std::string & title);
void set_base_path(const std::string & url);
void add_header_link(const std::string & url, const std::string & label, bool current = false);
void add_sidebar_section(const std::string & title);
void add_sidebar_link(const std::string & url, const std::string & label);
void write_to(weblegends_handler_v1 & handler) const;
};