Skip to content
Newer
Older
100644 226 lines (204 sloc) 8.6 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 <stdarg.h>
19 #include <stdio.h>
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
20 #include <stdlib.h>
21 #include <sys/select.h>
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25
26 #include <microhttpd.h>
27
b5c1e96 @hzeller o more useful output on status server.
authored
28 #include "convolver-filesystem.h"
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
29 #include "status-server.h"
30 #include "util.h"
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
31
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
32 static const size_t kMaxRetired = 200;
33 static const int kProgressWidth = 400;
34 static const char kActiveProgress[] = "#7070ff";
35 static const char kRetiredProgress[] = "#d0d0d0";
36
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
37 // Aaah, I need to find the right Browser-Tab :)
38 // Sneak in a favicon without another resource access.
39 // TODO: make a nice icon, recognizable as something that has to do with "
40 // files and music ...
41 static const char kHtmlHeader[] = "<header><link rel='icon' type='image/png'"
42 "href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2"
43 "AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wJDwUlEA/UBrsA"
44 "AABSSURBVCjPrZIxDgAgDAKh8f9froOTirU1ssKFYqS7Q4mktAxFRQDJcsPORMDYsDCXhn331"
45 "9GPwHJVuaFl3l4D1+h0UjIdbTh9SpP2KQ2AgSfVAdEQGx23tOopAAAAAElFTkSuQmCC'/>"
46 "</header>";
47
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
48 int StatusServer::HandleHttp(void* user_argument,
49 struct MHD_Connection *connection,
50 const char *url, const char *method,
51 const char *version,
52 const char *upload_data, size_t *upload_size,
53 void**) {
54 StatusServer* server = (StatusServer*) user_argument;
55 struct MHD_Response *response;
56 int ret;
57 const char *buffer;
58 size_t size;
59 server->CreatePage(&buffer, &size);
60 response = MHD_create_response_from_data(size, (void*) buffer,
61 MHD_NO, MHD_NO);
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
62 MHD_add_response_header(response, "Content-Type", "text/html; charset=utf-8");
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
63 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
64 MHD_destroy_response(response);
65 return ret;
66 }
67
b5c1e96 @hzeller o more useful output on status server.
authored
68 StatusServer::StatusServer(ConvolverFilesystem *fs)
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
69 : total_seconds_filtered_(0), total_seconds_music_seen_(0),
70 filesystem_(fs), daemon_(NULL) {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
71 fs->handler_cache()->SetObserver(this);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
72 }
73
74 bool StatusServer::Start(int port) {
75 daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, NULL,
76 &HandleHttp, this,
77 MHD_OPTION_END);
78 return daemon_ != NULL;
79 }
80
81 StatusServer::~StatusServer() {
82 if (daemon_)
83 MHD_stop_daemon(daemon_);
84 }
85
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
86 // FileHandlerCache::Observer interface.
87 void StatusServer::RetireHandlerEvent(FileHandler *handler) {
88 HandlerStats stats;
89 handler->GetHandlerStatus(&stats); // Get last available stats.
90 if (stats.progress >= 0) {
91 total_seconds_music_seen_ += stats.total_duration_seconds;
92 total_seconds_filtered_ += stats.total_duration_seconds * stats.progress;
93 }
94 stats.last_access = fuse_convolve::CurrentTime();
95 stats.status = HandlerStats::RETIRED;
96 retired_.push_front(stats);
97 while (retired_.size() > kMaxRetired)
98 retired_.pop_back();
99 }
100
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
101 static const char sMessageRowHtml[] =
102 "<td>%s</td><td>%s</td>"
b5c1e96 @hzeller o more useful output on status server.
authored
103 "<td colspan='3'>-</td>";
104
105 static const char sProgressRowHtml[] =
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
106 "<td>%s</td><td>"
b5c1e96 @hzeller o more useful output on status server.
authored
107 "<div style='width:%dpx; border:1px solid black;'>\n"
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
108 " <div style='width:%d%%;background:%s;'>&nbsp;</div>\n</div></td>"
b5c1e96 @hzeller o more useful output on status server.
authored
109 "<td align='right'>%2d:%02d</td><td>/</td><td align='right'>%2d:%02d</td>";
110
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
111 static void AppendFileInfo(std::string *result, const char *progress_style,
112 const HandlerStats &stats) {
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
113 result->append("<tr style='text-wrap:none;white-space:nowrap;'>");
b5c1e96 @hzeller o more useful output on status server.
authored
114 char row[1024];
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
115 const char *status = "";
116 switch (stats.status) {
117 case HandlerStats::OPEN: status = "open"; break;
118 case HandlerStats::IDLE: status = "idle"; break;
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
119 case HandlerStats::RETIRED: status = "&nbsp;----&nbsp;"; break;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
120 // no default to let the compiler detect new values.
121 }
122 if (stats.progress <= 0) {
123 snprintf(row, sizeof(row), sMessageRowHtml, status,
124 (stats.progress < 0)
a2aa9a4 @hzeller o let error messages make it to the console.
authored
125 ? "Not a sound file or no filter found. Pass through."
126 : "Only Header accessed.");
b5c1e96 @hzeller o more useful output on status server.
authored
127 } else {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
128 const int secs = stats.total_duration_seconds;
129 const int fract_sec = stats.progress * secs;
130 snprintf(row, sizeof(row), sProgressRowHtml, status,
131 kProgressWidth, (int) (100 * stats.progress), progress_style,
b5c1e96 @hzeller o more useful output on status server.
authored
132 fract_sec / 60, fract_sec % 60, secs / 60, secs % 60);
133 }
134 result->append(row);
135 result->append("<td bgcolor='#c0c0c0'>&nbsp;")
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
136 .append(stats.format).append("&nbsp;</td>")
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
137 .append("<td style='font-size:small;text-wrap:none;white-space:nowrap'>")
138 .append(stats.filename)
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
139 .append("</td>");
b5c1e96 @hzeller o more useful output on status server.
authored
140 result->append("</tr>\n");
141 }
142
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
143 struct CompareStats {
144 bool operator() (const HandlerStats &a, const HandlerStats &b) {
145 if (a.status < b.status) return true; // open before idle.
146 else if (a.status > b.status) return false;
147 return b.last_access < a.last_access; // reverse time.
148 }
149 };
150
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
151 void StatusServer::CreatePage(const char **buffer, size_t *size) {
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
152 const double start = fuse_convolve::CurrentTime();
b5c1e96 @hzeller o more useful output on status server.
authored
153 current_page_.clear();
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
154 current_page_.append(kHtmlHeader);
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
155 current_page_.append("<body style='font-family:Helvetica;'>\n");
b5c1e96 @hzeller o more useful output on status server.
authored
156 current_page_.append("<center>Welcome to fuse convolve ")
157 .append(filesystem_->version()).append("</center>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
158
159 std::vector<HandlerStats> stat_list;
160 filesystem_->handler_cache()->GetStats(&stat_list);
161
162 // Get statistics of active files.
163 double active_music_seen = 0.0;
164 double active_filtered = 0.0;
165 for (size_t i = 0; i < stat_list.size(); ++i) {
166 const HandlerStats &stats = stat_list[i];
167 if (stats.progress >= 0) {
168 active_music_seen += stats.total_duration_seconds;
169 active_filtered += stats.total_duration_seconds * stats.progress;
170 }
171 }
172 const int t_seen = total_seconds_music_seen_ + active_music_seen;
173 const int t_filtered = total_seconds_filtered_ + active_filtered;
174 char total_stats[1024];
175 snprintf(total_stats, sizeof(total_stats),
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
176 "Total opening files <b>%d</b> "
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
177 ".. and re-opened from recency cache <b>%d</b><br/>"
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
178 "Total music seen <b>%dd %d:%02d:%02d</b> "
179 ".. and convolved <b>%dd %d:%02d:%02d</b> (%.1f%%)<br/>",
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
180 filesystem_->total_file_openings(),
181 filesystem_->total_file_reopen(),
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
182 t_seen / 86400, (t_seen % 86400) / 3600,
183 (t_seen % 3600) / 60, t_seen % 60,
184 t_filtered / 86400, (t_filtered % 86400) / 3600,
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
185 (t_filtered % 3600) / 60, t_filtered % 60,
186 (t_seen == 0) ? 0.0 : (100.0 * t_filtered / t_seen));
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
187 current_page_.append(total_stats);
188
b5c1e96 @hzeller o more useful output on status server.
authored
189 current_page_.append("<h3>Recent Files</h3>\n");
a2aa9a4 @hzeller o let error messages make it to the console.
authored
190 char current_open[128];
191 snprintf(current_open, sizeof(current_open), "%ld in recency cache.\n",
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
192 stat_list.size());
193
a2aa9a4 @hzeller o let error messages make it to the console.
authored
194 current_page_.append(current_open);
b5c1e96 @hzeller o more useful output on status server.
authored
195 current_page_.append("<table>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
196 current_page_.append("<tr><th>Stat</th>"
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
197 "<th width='400px'>Progress</th>"
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
198 "<th>Pos</th><td></td><th>Len</th><th>Format</th>"
199 "<th align='left'>File</th></tr>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
200 CompareStats comparator;
201 std::sort(stat_list.begin(), stat_list.end(), comparator);
202 for (size_t i = 0; i < stat_list.size(); ++i) {
203 AppendFileInfo(&current_page_, kActiveProgress, stat_list[i]);
b5c1e96 @hzeller o more useful output on status server.
authored
204 }
205 current_page_.append("</table><hr/>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
206
207 if (retired_.size() > 0) {
208 current_page_.append("<h3>Retired</h3>\n");
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
209 current_page_.append("<table>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
210 for (RetiredList::const_iterator it = retired_.begin();
211 it != retired_.end(); ++it) {
212 AppendFileInfo(&current_page_, kRetiredProgress, *it);
213 }
214 current_page_.append("</table><hr/>\n");
215 }
216
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
217 const double duration = fuse_convolve::CurrentTime() - start;
218 char time_buffer[128];
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
219 snprintf(time_buffer, sizeof(time_buffer), "page-gen %.2fms",
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
220 duration * 1000.0);
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
221 current_page_.append(time_buffer).append("<div align='right'>HZ</div>\n"
222 "</body>");
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
223 *buffer = current_page_.data();
224 *size = current_page_.size();
225 }
Something went wrong with that request. Please try again.