Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 238 lines (213 sloc) 9.461 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
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
38 static const size_t kMaxRetired = 200;
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";
42
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
43 // Aaah, I need to find the right Browser-Tab :)
44 // Sneak in a favicon without another resource access.
45 // TODO: make a nice icon, recognizable as something that has to do with "
46 // files and music ...
b15aaf9 @hzeller o add title.
authored
47 static const char kHtmlHeader[] = "<header>"
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
48 "<title>Folve</title>\n"
b15aaf9 @hzeller o add title.
authored
49 "<link rel='icon' type='image/png'"
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
50 "href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2"
51 "AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9wJDwUlEA/UBrsA"
52 "AABSSURBVCjPrZIxDgAgDAKh8f9froOTirU1ssKFYqS7Q4mktAxFRQDJcsPORMDYsDCXhn331"
b15aaf9 @hzeller o add title.
authored
53 "9GPwHJVuaFl3l4D1+h0UjIdbTh9SpP2KQ2AgSfVAdEQGx23tOopAAAAAElFTkSuQmCC'/>\n"
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
54 "</header>";
55
b698853 @hzeller o README updates.
authored
56 // Callback function called by micro http daemon. Gets the StatusServer pointer
57 // in the user_argument.
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
58 int StatusServer::HandleHttp(void* user_argument,
59 struct MHD_Connection *connection,
60 const char *url, const char *method,
61 const char *version,
62 const char *upload_data, size_t *upload_size,
63 void**) {
64 StatusServer* server = (StatusServer*) user_argument;
65 struct MHD_Response *response;
66 int ret;
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
67 const std::string &page = server->CreatePage();
68 response = MHD_create_response_from_data(page.length(), (void*) page.data(),
69 MHD_NO, MHD_NO);
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
70 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
71 ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
72 MHD_destroy_response(response);
73 return ret;
74 }
75
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
76 StatusServer::StatusServer(FolveFilesystem *fs)
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
77 : expunged_retired_(0), total_seconds_filtered_(0),
78 total_seconds_music_seen_(0),
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
79 filesystem_(fs), daemon_(NULL) {
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
80 fs->handler_cache()->SetObserver(this);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
81 }
82
83 bool StatusServer::Start(int port) {
84 daemon_ = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, NULL,
85 &HandleHttp, this,
86 MHD_OPTION_END);
87 return daemon_ != NULL;
88 }
89
90 StatusServer::~StatusServer() {
b698853 @hzeller o README updates.
authored
91 if (daemon_) MHD_stop_daemon(daemon_);
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
92 }
93
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
94 // FileHandlerCache::Observer interface.
95 void StatusServer::RetireHandlerEvent(FileHandler *handler) {
96 HandlerStats stats;
97 handler->GetHandlerStatus(&stats); // Get last available stats.
98 if (stats.progress >= 0) {
8268c37 @hzeller o Bubble up error messages in status server.
authored
99 total_seconds_music_seen_ += stats.duration_seconds;
100 total_seconds_filtered_ += stats.duration_seconds * stats.progress;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
101 }
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
102 stats.last_access = folve::CurrentTime();
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
103 stats.status = HandlerStats::RETIRED;
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
104 boost::lock_guard<boost::mutex> l(retired_mutex_);
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
105 retired_.push_front(stats);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
106 while (retired_.size() > kMaxRetired) {
107 ++expunged_retired_;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
108 retired_.pop_back();
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
109 }
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
110 }
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
111
e70e18f @hzeller o Make sure we don't mess up our buffers when multiple threads
authored
112 static const char sMessageRowHtml[] =
113 "<td>%s</td><td style='font-size:small;'>%s</td>"
9ca938d @hzeller o comment tweaking.
authored
114 "<td colspan='3' align='center'>-</td>";
b5c1e96 @hzeller o more useful output on status server.
authored
115
116 static const char sProgressRowHtml[] =
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
117 "<td>%s</td><td>"
b5c1e96 @hzeller o more useful output on status server.
authored
118 "<div style='width:%dpx; border:1px solid black;'>\n"
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
119 " <div style='width:%d%%;background:%s;'>&nbsp;</div>\n</div></td>"
b5c1e96 @hzeller o more useful output on status server.
authored
120 "<td align='right'>%2d:%02d</td><td>/</td><td align='right'>%2d:%02d</td>";
121
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
122 static void AppendFileInfo(std::string *result, const char *progress_style,
123 const HandlerStats &stats) {
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
124 result->append("<tr style='text-wrap:none;white-space:nowrap;'>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
125 const char *status = "";
126 switch (stats.status) {
127 case HandlerStats::OPEN: status = "open"; break;
128 case HandlerStats::IDLE: status = "idle"; break;
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
129 case HandlerStats::RETIRED: status = "&nbsp;----&nbsp;"; break;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
130 // no default to let the compiler detect new values.
131 }
8268c37 @hzeller o Bubble up error messages in status server.
authored
132 if (!stats.message.empty()) {
133 Appendf(result, sMessageRowHtml, status, stats.message.c_str());
134 } else if (stats.progress == 0) {
135 Appendf(result, sMessageRowHtml, status, "Only header accessed");
b5c1e96 @hzeller o more useful output on status server.
authored
136 } else {
8268c37 @hzeller o Bubble up error messages in status server.
authored
137 const int secs = stats.duration_seconds;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
138 const int fract_sec = stats.progress * secs;
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
139 Appendf(result, sProgressRowHtml, status,
140 kProgressWidth, (int) (100 * stats.progress), progress_style,
141 fract_sec / 60, fract_sec % 60, secs / 60, secs % 60);
b5c1e96 @hzeller o more useful output on status server.
authored
142 }
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
143 Appendf(result, "<td bgcolor='#c0c0c0'>&nbsp;%s&nbsp;</td>",
144 stats.format.c_str());
145 Appendf(result,"<td "
146 "style='font-size:small;text-wrap:none;white-space:nowrap'>%s</td>",
147 stats.filename.c_str());
b5c1e96 @hzeller o more useful output on status server.
authored
148 result->append("</tr>\n");
149 }
150
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
151 struct CompareStats {
152 bool operator() (const HandlerStats &a, const HandlerStats &b) {
153 if (a.status < b.status) return true; // open before idle.
154 else if (a.status > b.status) return false;
155 return b.last_access < a.last_access; // reverse time.
156 }
157 };
158
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
159 const std::string &StatusServer::CreatePage() {
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
160 const double start = folve::CurrentTime();
b698853 @hzeller o README updates.
authored
161 // We re-use a string to avoid re-allocing memory every time we generate
162 // a page. Since we run with MHD_USE_SELECT_INTERNALLY, this is only accessed
163 // by one thread.
b5c1e96 @hzeller o more useful output on status server.
authored
164 current_page_.clear();
78e66dd @hzeller o I need to find my browser-tab :) Add favicon.
authored
165 current_page_.append(kHtmlHeader);
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
166 current_page_.append("<body style='font-family:Sans-Serif;'>\n");
b698853 @hzeller o README updates.
authored
167 Appendf(&current_page_, "<center style='background-color:#A0FFA0;'>"
53130a3 @hzeller o link to github page
authored
168 "Welcome to "
169 "<a href='https://github.com/hzeller/folve#readme'>Folve</a>"
170 "%s</center>\n"
b698853 @hzeller o README updates.
authored
171 "Convolving audio files from <code>%s</code><br/>\n",
0aee3bb @hzeller o Show base dir that is mounted.
authored
172 filesystem_->version().c_str(), filesystem_->underlying_dir().c_str());
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
173
174 std::vector<HandlerStats> stat_list;
175 filesystem_->handler_cache()->GetStats(&stat_list);
176
562b493 @hzeller o Print out config file name while spotting a problem
authored
177 // Get statistics of active files to add to the existing ones.
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
178 double active_music_seen = 0.0;
179 double active_filtered = 0.0;
180 for (size_t i = 0; i < stat_list.size(); ++i) {
181 const HandlerStats &stats = stat_list[i];
182 if (stats.progress >= 0) {
8268c37 @hzeller o Bubble up error messages in status server.
authored
183 active_music_seen += stats.duration_seconds;
184 active_filtered += stats.duration_seconds * stats.progress;
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
185 }
186 }
187 const int t_seen = total_seconds_music_seen_ + active_music_seen;
188 const int t_filtered = total_seconds_filtered_ + active_filtered;
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
189 Appendf(&current_page_, "Total opening files <b>%d</b> "
190 ".. and re-opened from recency cache <b>%d</b><br/>",
191 filesystem_->total_file_openings(),
192 filesystem_->total_file_reopen());
193 Appendf(&current_page_, "Total music seen <b>%dd %d:%02d:%02d</b> ",
194 t_seen / 86400, (t_seen % 86400) / 3600,
195 (t_seen % 3600) / 60, t_seen % 60);
196 Appendf(&current_page_, ".. and convolved <b>%dd %d:%02d:%02d</b> ",
197 t_filtered / 86400, (t_filtered % 86400) / 3600,
198 (t_filtered % 3600) / 60, t_filtered % 60);
199 Appendf(&current_page_, "(%.1f%%)<br/>",
200 (t_seen == 0) ? 0.0 : (100.0 * t_filtered / t_seen));
201
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
202 Appendf(&current_page_, "<h3>Accessed Recently</h3>\n%ld in recency cache\n",
bea11d6 @hzeller o Don't use snprintf, but use a new function Appendf() to assemble
authored
203 stat_list.size());
204
b5c1e96 @hzeller o more useful output on status server.
authored
205 current_page_.append("<table>\n");
b698853 @hzeller o README updates.
authored
206 Appendf(&current_page_, "<tr><th>Stat</th><th width='%dpx'>Progress</th>"
207 "<th>Pos</th><td></td><th>Len</th><th>Format</th>"
208 "<th align='left'>File</th></tr>\n", kProgressWidth);
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
209 CompareStats comparator;
210 std::sort(stat_list.begin(), stat_list.end(), comparator);
211 for (size_t i = 0; i < stat_list.size(); ++i) {
212 AppendFileInfo(&current_page_, kActiveProgress, stat_list[i]);
b5c1e96 @hzeller o more useful output on status server.
authored
213 }
214 current_page_.append("</table><hr/>\n");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
215
216 if (retired_.size() > 0) {
217 current_page_.append("<h3>Retired</h3>\n");
bcb77e7 @hzeller o Ran with Amarok over my files. Looks like it sometimes only 'almost'
authored
218 current_page_.append("<table>\n");
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
219 boost::lock_guard<boost::mutex> l(retired_mutex_);
b698853 @hzeller o README updates.
authored
220 for (RetiredList::const_iterator it = retired_.begin();
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
221 it != retired_.end(); ++it) {
222 AppendFileInfo(&current_page_, kRetiredProgress, *it);
223 }
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
224 current_page_.append("</table>\n");
225 if (expunged_retired_ > 0) {
226 Appendf(&current_page_, "... (%d more)<p></p>", expunged_retired_);
227 }
228 current_page_.append("<hr/>");
223f392 @hzeller o Have a separate HandlerStats object that contains relevant
authored
229 }
230
a9d3e53 @hzeller o Found a project name: "Folve". Some renamings because of that.
authored
231 const double duration = folve::CurrentTime() - start;
232 Appendf(&current_page_,
233 "<span style='float:left;font-size:small;'>page-gen %.2fms</span>"
234 "<span style='float:right;font-size:small;'>HZ</span>"
235 "</body>", duration * 1000.0);
1e9ff21 @hzeller o main: report if parameters are not directories.
authored
236 return current_page_;
8d1fbe7 @hzeller o Move fuse-convolve.c to fuse-convolve.cc. Make filter-interface
authored
237 }
Something went wrong with that request. Please try again.