Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 207 lines (186 sloc) 7.773 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
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
37 int StatusServer::HandleHttp(void* user_argument,
38 struct MHD_Connection *connection,
39 const char *url, const char *method,
40 const char *version,
41 const char *upload_data, size_t *upload_size,
42 void**) {
43 StatusServer* server = (StatusServer*) user_argument;
44 struct MHD_Response *response;
45 int ret;
46 const char *buffer;
47 size_t size;
48 server->CreatePage(&buffer, &size);
49 response = MHD_create_response_from_data(size, (void*) buffer,
50 MHD_NO, MHD_NO);
b5c1e96 @hzeller o more useful output on status server.
authored
51 MHD_add_response_header(response, "Content-Type", "text/html");
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
52 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
53 MHD_destroy_response(response);
54 return ret;
55 }
56
b5c1e96 @hzeller o more useful output on status server.
authored
57 StatusServer::StatusServer(ConvolverFilesystem *fs)
58 : filesystem_(fs), daemon_(NULL) {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
59 fs->handler_cache()->SetObserver(this);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
60 }
61
62 bool StatusServer::Start(int port) {
63 daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, NULL,
64 &HandleHttp, this,
65 MHD_OPTION_END);
66 return daemon_ != NULL;
67 }
68
69 StatusServer::~StatusServer() {
70 if (daemon_)
71 MHD_stop_daemon(daemon_);
72 }
73
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
74 // FileHandlerCache::Observer interface.
75 void StatusServer::RetireHandlerEvent(FileHandler *handler) {
76 HandlerStats stats;
77 handler->GetHandlerStatus(&stats); // Get last available stats.
78 if (stats.progress >= 0) {
79 total_seconds_music_seen_ += stats.total_duration_seconds;
80 total_seconds_filtered_ += stats.total_duration_seconds * stats.progress;
81 }
82 stats.last_access = fuse_convolve::CurrentTime();
83 stats.status = HandlerStats::RETIRED;
84 retired_.push_front(stats);
85 while (retired_.size() > kMaxRetired)
86 retired_.pop_back();
87 }
88
89 static const char sMessageRowHtml[] = "<td>%s</td><td>%s</td>"
b5c1e96 @hzeller o more useful output on status server.
authored
90 "<td colspan='3'>-</td>";
91
92 static const char sProgressRowHtml[] =
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
93 "<td>%s</td><td>"
b5c1e96 @hzeller o more useful output on status server.
authored
94 "<div style='width:%dpx; border:1px solid black;'>\n"
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
95 " <div style='width:%d%%;background:%s;'>&nbsp;</div>\n</div></td>"
b5c1e96 @hzeller o more useful output on status server.
authored
96 "<td align='right'>%2d:%02d</td><td>/</td><td align='right'>%2d:%02d</td>";
97
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
98 static void AppendFileInfo(std::string *result, const char *progress_style,
99 const HandlerStats &stats) {
b5c1e96 @hzeller o more useful output on status server.
authored
100 result->append("<tr>");
101 char row[1024];
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
102 const char *status = "";
103 switch (stats.status) {
104 case HandlerStats::OPEN: status = "open"; break;
105 case HandlerStats::IDLE: status = "idle"; break;
106 case HandlerStats::RETIRED: status = "----"; break;
107 // no default to let the compiler detect new values.
108 }
109 if (stats.progress <= 0) {
110 snprintf(row, sizeof(row), sMessageRowHtml, status,
111 (stats.progress < 0)
a2aa9a4 @hzeller o let error messages make it to the console.
authored
112 ? "Not a sound file or no filter found. Pass through."
113 : "Only Header accessed.");
b5c1e96 @hzeller o more useful output on status server.
authored
114 } else {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
115 const int secs = stats.total_duration_seconds;
116 const int fract_sec = stats.progress * secs;
117 snprintf(row, sizeof(row), sProgressRowHtml, status,
118 kProgressWidth, (int) (100 * stats.progress), progress_style,
b5c1e96 @hzeller o more useful output on status server.
authored
119 fract_sec / 60, fract_sec % 60, secs / 60, secs % 60);
120 }
121 result->append(row);
122 result->append("<td bgcolor='#c0c0c0'>&nbsp;")
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
123 .append(stats.format).append("&nbsp;</td>")
124 .append("<td style='font-size:small;'>").append(stats.filename)
125 .append("</td>");
b5c1e96 @hzeller o more useful output on status server.
authored
126 result->append("</tr>\n");
127 }
128
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
129 struct CompareStats {
130 bool operator() (const HandlerStats &a, const HandlerStats &b) {
131 if (a.status < b.status) return true; // open before idle.
132 else if (a.status > b.status) return false;
133 return b.last_access < a.last_access; // reverse time.
134 }
135 };
136
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
137 void StatusServer::CreatePage(const char **buffer, size_t *size) {
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
138 const double start = fuse_convolve::CurrentTime();
b5c1e96 @hzeller o more useful output on status server.
authored
139 current_page_.clear();
4c1a006 @hzeller o no -g
authored
140 current_page_.append("<body style='font-family:Helvetica;'>");
b5c1e96 @hzeller o more useful output on status server.
authored
141 current_page_.append("<center>Welcome to fuse convolve ")
142 .append(filesystem_->version()).append("</center>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
143
144 std::vector<HandlerStats> stat_list;
145 filesystem_->handler_cache()->GetStats(&stat_list);
146
147 // Get statistics of active files.
148 double active_music_seen = 0.0;
149 double active_filtered = 0.0;
150 for (size_t i = 0; i < stat_list.size(); ++i) {
151 const HandlerStats &stats = stat_list[i];
152 if (stats.progress >= 0) {
153 active_music_seen += stats.total_duration_seconds;
154 active_filtered += stats.total_duration_seconds * stats.progress;
155 }
156 }
157 const int t_seen = total_seconds_music_seen_ + active_music_seen;
158 const int t_filtered = total_seconds_filtered_ + active_filtered;
159 char total_stats[1024];
160 snprintf(total_stats, sizeof(total_stats),
161 "Total opening files <b>%d</b> | "
162 ".. and re-opened from recency cache <b>%d</b><br/>"
163 "Total music seen <b>%d:%02d:%02d</b> | "
164 ".. and convolved <b>%d:%02d:%02d</b><br/>",
165 filesystem_->total_file_openings(),
166 filesystem_->total_file_reopen(),
167 t_seen / 3600, (t_seen % 3600) / 60, t_seen % 60,
168 t_filtered / 3600, (t_filtered % 3600) / 60, t_filtered % 60);
169 current_page_.append(total_stats);
170
b5c1e96 @hzeller o more useful output on status server.
authored
171 current_page_.append("<h3>Recent Files</h3>\n");
a2aa9a4 @hzeller o let error messages make it to the console.
authored
172 char current_open[128];
173 snprintf(current_open, sizeof(current_open), "%ld in recency cache.\n",
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
174 stat_list.size());
175
a2aa9a4 @hzeller o let error messages make it to the console.
authored
176 current_page_.append(current_open);
b5c1e96 @hzeller o more useful output on status server.
authored
177 current_page_.append("<table>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
178 current_page_.append("<tr><th>Stat</th>"
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
179 "<th width='400px'>Progress</th>"
180 "<th>Pos</th><td></td><th>Tot</th><th>Format</th>"
181 "<th>File</th></tr>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
182 CompareStats comparator;
183 std::sort(stat_list.begin(), stat_list.end(), comparator);
184 for (size_t i = 0; i < stat_list.size(); ++i) {
185 AppendFileInfo(&current_page_, kActiveProgress, stat_list[i]);
b5c1e96 @hzeller o more useful output on status server.
authored
186 }
187 current_page_.append("</table><hr/>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
188
189 if (retired_.size() > 0) {
190 current_page_.append("<table>\n");
191 current_page_.append("<h3>Retired</h3>\n");
192 for (RetiredList::const_iterator it = retired_.begin();
193 it != retired_.end(); ++it) {
194 AppendFileInfo(&current_page_, kRetiredProgress, *it);
195 }
196 current_page_.append("</table><hr/>\n");
197 }
198
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
199 const double duration = fuse_convolve::CurrentTime() - start;
200 char time_buffer[128];
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
201 snprintf(time_buffer, sizeof(time_buffer), "page-gen %.2fms",
c1a03f2 @hzeller o Needed convenient sub-second resolution time. Added CurrentTime()
authored
202 duration * 1000.0);
203 current_page_.append(time_buffer).append("<div align='right'>HZ</div></body>");
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
204 *buffer = current_page_.data();
205 *size = current_page_.size();
206 }
Something went wrong with that request. Please try again.