Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 330 lines (297 sloc) 13.139 kb
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
1 // Copyright (C) 2012 Henner Zeller <h.zeller@acm.org>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 #include <arpa/inet.h>
17 #include <fcntl.h>
b5c1e96 @hzeller o more useful output on status server.
authored
18 #include <stdio.h>
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
19 #include <stdlib.h>
20 #include <sys/select.h>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24
25 #include <microhttpd.h>
26
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
27 #include <boost/thread/locks.hpp>
28
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
29 #include "folve-filesystem.h"
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
30 #include "status-server.h"
31 #include "util.h"
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
32
8268c37 @hzeller o Bubble up error messages in status server.
authored
33 using folve::Appendf;
34
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
35 // TODO: someone with a bit more stylesheet-fu can attempt to make this
36 // more pretty and the HTML more compact.
37
f1ef960 @hzeller o a bit HTML polishing.
authored
38 static const size_t kMaxRetired = 20;
b698853 @hzeller o README updates.
authored
39 static const int kProgressWidth = 300;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
40 static const char kActiveProgress[] = "#7070ff";
41 static const char kRetiredProgress[] = "#d0d0d0";
249865a @hzeller o Make debug mode switchable in UI.
authored
42 static const char kSettingsUrl[] = "/settings";
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
43
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
44 // Aaah, I need to find the right Browser-Tab :)
45 // Sneak in a favicon without another resource access.
46 // TODO: make a nice icon, recognizable as something that has to do with "
47 // files and music ...
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
48 static const char kHtmlHeader[] = "<html><head>"
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
49 "<title>Folve</title>\n"
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
50 "<link rel='icon' type='image/png' "
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
51 "href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2"
52 "AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wJDwUlEA/UBrsA"
53 "AABSSURBVCjPrZIxDgAgDAKh8f9froOTirU1ssKFYqS7Q4mktAxFRQDJcsPORMDYsDCXhn331"
b15aaf9 @hzeller o add title.
authored
54 "9GPwHJVuaFl3l4D1+h0UjIdbTh9SpP2KQ2AgSfVAdEQGx23tOopAAAAAElFTkSuQmCC'/>\n"
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
55 "</head>\n";
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
56
b698853 @hzeller o README updates.
authored
57 // Callback function called by micro http daemon. Gets the StatusServer pointer
58 // in the user_argument.
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
59 int StatusServer::HandleHttp(void* user_argument,
60 struct MHD_Connection *connection,
61 const char *url, const char *method,
62 const char *version,
63 const char *upload_data, size_t *upload_size,
64 void**) {
65 StatusServer* server = (StatusServer*) user_argument;
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
66 struct MHD_Response *response;
67 int ret;
68
249865a @hzeller o Make debug mode switchable in UI.
authored
69 if (strcmp(url, kSettingsUrl) == 0) {
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
70 server->SetFilter(MHD_lookup_connection_value(connection,
71 MHD_GET_ARGUMENT_KIND, "f"));
249865a @hzeller o Make debug mode switchable in UI.
authored
72 server->SetDebug(MHD_lookup_connection_value(connection,
73 MHD_GET_ARGUMENT_KIND, "d"));
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
74 // We redirect to slash after this, to remove parameters from the GET-URL
75 response = MHD_create_response_from_data(0, (void*)"", MHD_NO, MHD_NO);
76 MHD_add_response_header(response, "Location", "/");
77 ret = MHD_queue_response(connection, 302, response);
78 } else {
79 const std::string &page = server->CreatePage();
80 response = MHD_create_response_from_data(page.length(), (void*) page.data(),
81 MHD_NO, MHD_NO);
82 MHD_add_response_header(response, "Content-Type",
83 "text/html; charset=utf-8");
84 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
85 }
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
86 // Tell aggressive cachers not to do so.
87 MHD_add_response_header(response, "Cache-Control", "no-cache");
88 MHD_add_response_header(response, "Expires", "24 Nov 1972 23:42:42 GMT");
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
89 MHD_destroy_response(response);
90 return ret;
91 }
92
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
93 StatusServer::StatusServer(FolveFilesystem *fs)
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
94 : expunged_retired_(0), total_seconds_filtered_(0),
95 total_seconds_music_seen_(0),
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
96 filesystem_(fs), daemon_(NULL), filter_switched_(false) {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
97 fs->handler_cache()->SetObserver(this);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
98 }
99
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
100 void StatusServer::SetFilter(const char *filter) {
101 if (filter == NULL || *filter == '\0') return;
102 char *end;
103 int index = strtol(filter, &end, 10);
104 if (end == NULL || *end != '\0') return;
105 filter_switched_ = (index != filesystem_->current_cfg_index());
106 filesystem_->SwitchCurrentConfigIndex(index);
107 }
108
249865a @hzeller o Make debug mode switchable in UI.
authored
109 void StatusServer::SetDebug(const char *dbg) {
8c7e5c1 @hzeller o Only if -D is given, the debug toggle is active in the UI.
authored
110 if (!filesystem_->is_debug_ui_enabled()) return;
249865a @hzeller o Make debug mode switchable in UI.
authored
111 filesystem_->SetDebugMode(dbg != NULL && *dbg == '1');
112 }
113
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
114 bool StatusServer::Start(int port) {
115 daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, NULL,
116 &HandleHttp, this,
117 MHD_OPTION_END);
118 return daemon_ != NULL;
119 }
120
121 StatusServer::~StatusServer() {
b698853 @hzeller o README updates.
authored
122 if (daemon_) MHD_stop_daemon(daemon_);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
123 }
124
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
125 // FileHandlerCache::Observer interface.
126 void StatusServer::RetireHandlerEvent(FileHandler *handler) {
127 HandlerStats stats;
128 handler->GetHandlerStatus(&stats); // Get last available stats.
129 if (stats.progress >= 0) {
8268c37 @hzeller o Bubble up error messages in status server.
authored
130 total_seconds_music_seen_ += stats.duration_seconds;
131 total_seconds_filtered_ += stats.duration_seconds * stats.progress;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
132 }
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
133 stats.last_access = folve::CurrentTime();
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
134 stats.status = HandlerStats::RETIRED;
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
135 boost::lock_guard<boost::mutex> l(retired_mutex_);
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
136 retired_.push_front(stats);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
137 while (retired_.size() > kMaxRetired) {
138 ++expunged_retired_;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
139 retired_.pop_back();
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
140 }
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
141 }
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
142
f1ef960 @hzeller o a bit HTML polishing.
authored
143 // As ugly #defines, so that gcc can warn about printf() format problems.
144 #define sMessageRowHtml \
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
145 "<td>%s</td><td colspan='3' style='font-size:small;'>%s</td>"
b5c1e96 @hzeller o more useful output on status server.
authored
146
f1ef960 @hzeller o a bit HTML polishing.
authored
147 #define sProgressRowHtml \
148 "<td>%s</td>" \
149 "<td>%s</td>" \
150 "<td><div style='background:white;width:%dpx;border:1px solid black;'>\n" \
151 " <div style='width:%d%%;background:%s;'>&nbsp;</div>\n</div></td>" \
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
152 "<td>%s</td>"
f1ef960 @hzeller o a bit HTML polishing.
authored
153
154 #define sTimeColumns \
155 "<td align='right'>%2d:%02d</td><td>/</td><td align='right'>%2d:%02d</td>"
156 #define sDecibelColumn \
157 "<td align='right' style='background:%s;'>%.1f dB</td>"
b5c1e96 @hzeller o more useful output on status server.
authored
158
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
159 static void AppendFileInfo(std::string *result, const char *progress_style,
160 const HandlerStats &stats) {
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
161 result->append("<tr style='text-wrap:none;white-space:nowrap;'>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
162 const char *status = "";
163 switch (stats.status) {
164 case HandlerStats::OPEN: status = "open"; break;
165 case HandlerStats::IDLE: status = "idle"; break;
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
166 case HandlerStats::RETIRED: status = "&nbsp;----&nbsp;"; break;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
167 // no default to let the compiler detect new values.
168 }
f1ef960 @hzeller o a bit HTML polishing.
authored
169
8268c37 @hzeller o Bubble up error messages in status server.
authored
170 if (!stats.message.empty()) {
171 Appendf(result, sMessageRowHtml, status, stats.message.c_str());
172 } else if (stats.progress == 0) {
173 Appendf(result, sMessageRowHtml, status, "Only header accessed");
b5c1e96 @hzeller o more useful output on status server.
authored
174 } else {
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
175 Appendf(result, sProgressRowHtml, status,
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
176 stats.in_gapless ? "&rarr;" : "",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
177 kProgressWidth, (int) (100 * stats.progress), progress_style,
f1ef960 @hzeller o a bit HTML polishing.
authored
178 stats.out_gapless ? "&rarr;" : "");
179 }
180 const int secs = stats.duration_seconds;
181 const int fract_sec = stats.progress * secs;
6d4f28b @hzeller o if there is a time, show it.
authored
182 if (secs >= 0 && fract_sec >= 0) {
f1ef960 @hzeller o a bit HTML polishing.
authored
183 Appendf(result, sTimeColumns,
184 fract_sec / 60, fract_sec % 60,
185 secs / 60, secs % 60);
186 } else {
187 result->append("<td colspan='3'>-</td>");
b5c1e96 @hzeller o more useful output on status server.
authored
188 }
f1ef960 @hzeller o a bit HTML polishing.
authored
189 if (stats.max_output_value > 0.0) {
190 Appendf(result, sDecibelColumn,
191 stats.max_output_value > 1.0 ? "#FF0505" : "white",
192 20 * log(stats.max_output_value));
193 } else {
194 result->append("<td>-</td>");
195 }
196
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
197 Appendf(result, "<td bgcolor='#c0c0c0'>&nbsp;%s&nbsp;</td>",
198 stats.format.c_str());
199 Appendf(result,"<td "
200 "style='font-size:small;text-wrap:none;white-space:nowrap'>%s</td>",
201 stats.filename.c_str());
b5c1e96 @hzeller o more useful output on status server.
authored
202 result->append("</tr>\n");
203 }
204
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
205 void StatusServer::AppendFilterOptions(std::string *result) {
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
206 Appendf(result, "<form action='%s'>\n"
207 "<label for='cfg_sel'>Config directory </label>", kSettingsUrl);
208 Appendf(result, "<select id='cfg_sel' name='f' "
209 "onchange='this.form.submit();'>\n");
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
210 for (size_t i = 0; i < filesystem_->config_dirs().size(); ++i) {
211 const std::string &c = filesystem_->config_dirs()[i];
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
212 Appendf(result, " <option value='%zd'%s>%s</option>\n", i,
213 ((int) i == filesystem_->current_cfg_index())
214 ? " selected='selected'" : "",
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
215 (i == 0) ? "[No convolver - just pass through]" : c.c_str());
216 }
217 result->append("</select>");
218 if (filesystem_->config_dirs().size() == 1) {
219 result->append(" (This is a boring configuration, add filter directories "
220 "with -c &lt;dir&gt; [-c &lt;another-dir&gt; ...] :-) )");
221 } else if (filter_switched_) {
222 result->append(" <span style='font-size:small;'>Affects re- or newly opened "
223 "files.</span>");
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
224 filter_switched_ = false; // only show once.
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
225 }
8c7e5c1 @hzeller o Only if -D is given, the debug toggle is active in the UI.
authored
226 if (filesystem_->is_debug_ui_enabled()) {
227 Appendf(result, "<span style='float:right;font-size:small;'>"
228 "<label for='dbg_sel'>Folve debug to syslog</label>"
229 "<input id='dbg_sel' onchange='this.form.submit();' "
230 "type='checkbox' name='d' value='1'%s/></span>",
231 filesystem_->IsDebugMode() ? " checked" : "");
232 }
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
233 result->append("</form>");
234 }
235
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
236 struct CompareStats {
237 bool operator() (const HandlerStats &a, const HandlerStats &b) {
238 if (a.status < b.status) return true; // open before idle.
239 else if (a.status > b.status) return false;
240 return b.last_access < a.last_access; // reverse time.
241 }
242 };
243
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
244 const std::string &StatusServer::CreatePage() {
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
245 const double start = folve::CurrentTime();
b698853 @hzeller o README updates.
authored
246 // We re-use a string to avoid re-allocing memory every time we generate
247 // a page. Since we run with MHD_USE_SELECT_INTERNALLY, this is only accessed
248 // by one thread.
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
249 content_.clear();
250 content_.append(kHtmlHeader);
251 content_.append("<body style='font-family:Sans-Serif;'>\n");
252 Appendf(&content_, "<center style='background-color:#A0FFA0;'>"
53130a3 @hzeller o link to github page
authored
253 "Welcome to "
ee675fe @hzeller o Provide a way to select between different filter diretories.
authored
254 "<a href='https://github.com/hzeller/folve#readme'>Folve</a> "
255 FOLVE_VERSION "</center>\n"
256 "Convolving audio files from <code>%s</code>\n",
257 filesystem_->underlying_dir().c_str());
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
258
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
259 AppendFilterOptions(&content_);
27c44cd @hzeller o Use fuse option handling to extract our flags and options.
authored
260
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
261 std::vector<HandlerStats> stat_list;
262 filesystem_->handler_cache()->GetStats(&stat_list);
263
562b493 @hzeller o Print out config file name while spotting a problem
authored
264 // Get statistics of active files to add to the existing ones.
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
265 double active_music_seen = 0.0;
266 double active_filtered = 0.0;
267 for (size_t i = 0; i < stat_list.size(); ++i) {
268 const HandlerStats &stats = stat_list[i];
269 if (stats.progress >= 0) {
8268c37 @hzeller o Bubble up error messages in status server.
authored
270 active_music_seen += stats.duration_seconds;
271 active_filtered += stats.duration_seconds * stats.progress;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
272 }
273 }
274 const int t_seen = total_seconds_music_seen_ + active_music_seen;
275 const int t_filtered = total_seconds_filtered_ + active_filtered;
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
276 Appendf(&content_, "Total opening files <b>%d</b> "
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
277 ".. and re-opened from recency cache <b>%d</b><br/>",
278 filesystem_->total_file_openings(),
279 filesystem_->total_file_reopen());
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
280 Appendf(&content_, "Total music seen <b>%dd %d:%02d:%02d</b> ",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
281 t_seen / 86400, (t_seen % 86400) / 3600,
282 (t_seen % 3600) / 60, t_seen % 60);
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
283 Appendf(&content_, ".. and convolved <b>%dd %d:%02d:%02d</b> ",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
284 t_filtered / 86400, (t_filtered % 86400) / 3600,
285 (t_filtered % 3600) / 60, t_filtered % 60);
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
286 Appendf(&content_, "(%.1f%%)<br/>",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
287 (t_seen == 0) ? 0.0 : (100.0 * t_filtered / t_seen));
288
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
289 Appendf(&content_, "<h3>Accessed Recently</h3>\n%zd in recency cache\n",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
290 stat_list.size());
291
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
292 if (filesystem_->gapless_processing()) {
d93a35b @hzeller o Uh, typo in gapless message.
authored
293 content_.append("<br/>&rarr; : denotes gapless transfers\n");
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
294 }
f1ef960 @hzeller o a bit HTML polishing.
authored
295 content_.append("<table cellspacing='10'>\n");
08bbf28 @hzeller o First shot at gapless. Works pretty well for my test-case.
authored
296 Appendf(&content_, "<tr><th>Stat</th><td><!--gapless in--></td>"
297 "<th width='%dpx'>Progress</th>" // progress bar.
298 "<td><!-- gapless out --></td>"
f1ef960 @hzeller o a bit HTML polishing.
authored
299 "<th>Pos</th><td></td><th>Len</th><th>Max out</th><th>Format</th>"
b698853 @hzeller o README updates.
authored
300 "<th align='left'>File</th></tr>\n", kProgressWidth);
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
301 CompareStats comparator;
302 std::sort(stat_list.begin(), stat_list.end(), comparator);
303 for (size_t i = 0; i < stat_list.size(); ++i) {
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
304 AppendFileInfo(&content_, kActiveProgress, stat_list[i]);
b5c1e96 @hzeller o more useful output on status server.
authored
305 }
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
306 content_.append("</table><hr/>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
307
308 if (retired_.size() > 0) {
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
309 content_.append("<h3>Retired</h3>\n");
310 content_.append("<table>\n");
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
311 boost::lock_guard<boost::mutex> l(retired_mutex_);
b698853 @hzeller o README updates.
authored
312 for (RetiredList::const_iterator it = retired_.begin();
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
313 it != retired_.end(); ++it) {
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
314 AppendFileInfo(&content_, kRetiredProgress, *it);
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
315 }
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
316 content_.append("</table>\n");
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
317 if (expunged_retired_ > 0) {
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
318 Appendf(&content_, "... (%d more)<p></p>", expunged_retired_);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
319 }
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
320 content_.append("<hr/>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
321 }
322
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
323 const double duration = folve::CurrentTime() - start;
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
324 Appendf(&content_,
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
325 "<span style='float:left;font-size:small;'>page-gen %.2fms</span>"
326 "<span style='float:right;font-size:small;'>HZ</span>"
e619ff2 @hzeller o Redirect to / after settings. That way, a reload won't change any
authored
327 "</body></html>\n", duration * 1000.0);
7d695c6 @hzeller o Rename current_page_ to content_ to be more generic.
authored
328 return content_;
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
329 }
Something went wrong with that request. Please try again.