ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/DecentralizedMedia/DecentralizedMedia.cpp
Revision: 517
Committed: 2005-06-20T21:43:06-07:00 (20 years ago) by douglas
File size: 5949 byte(s)
Log Message:
This is probably a better way of doing the precompiled header thing, it doesn't cause menes to be almost completely rebuilt every time something changes.

File Contents

# Content
1 // Decentralized Media
2 //
3 // Douglas Thrift
4 //
5 // $Id$
6
7 #include <menes/standard.hh>
8
9 #include <menes-api/pcre/regex.hpp>
10 #include <menes-api/realpath.hpp>
11 #include <menes-app/simple.hpp>
12 #include <menes-dbi/driver.hpp>
13 #include <menes-dbi/resultset.hpp>
14 #include <menes-etl/fnbind.hpp>
15 #include <menes-ios/helpers.hpp>
16 #include <menes-net/http/request.hpp>
17 #include <menes-net/http/response.hpp>
18 #include <menes-xml/document.hpp>
19 #include <menes-xml/parse.hpp>
20
21 #include "DecentralizedMedia.hpp"
22
23 int Main(const app::Options& options)
24 {
25 ext::RedBlackSet<ext::String> extensions, locals;
26 api::Pcre::RegEx extension(_B("^-extension=(.+)$")), local(_B("^-local=(.+)$"));
27
28 _foreach (const app::ArgumentList, arg, app::GetArguments())
29 {
30 api::Pcre::RegEx::Match match;
31
32 if (match = extension(*arg))
33 extensions.Insert(match[1]);
34 else if (match = local(*arg))
35 locals.Insert(api::RealPath(match[1]));
36 }
37
38 if (extensions.IsEmpty())
39 extensions.Insert(_B("mp3"));
40
41 if (!api::Path(_B("Media")).Exists())
42 api::Posix::CheckError(::mkdir("Media", 0755));
43
44 locals.Insert(api::RealPath(_B("Media")));
45
46 _S<DecentralizedMedia> media(extensions, locals);
47
48 media.Block();
49
50 return 0;
51 }
52
53 DecentralizedMedia::DecentralizedMedia(const ext::RedBlackSet<ext::String>& extensions, const ext::RedBlackSet<ext::String>& locals) : waf::Server(_B("Web")), process(bmp.IsRunning() ? NULL : new api::Process(_B("/usr/X11R6/bin/beep-media-player"))), connection(dbi::GetDriver("dbi::PgSql::Driver")->Connect("", "douglas", "", "media")), extensions(extensions)
54 {
55 if (!process.IsEmpty())
56 {
57 process->ClearReader();
58 process->ClearWriter();
59 }
60
61 connection->Execute(_B("UPDATE files SET live = FALSE"));
62
63 {
64 _L<ext::String> args;
65
66 _foreach (const ext::RedBlackSet<ext::String>, extension, extensions)
67 args.InsertLast(_S<ios::String>() << "-extension=" << *extension);
68
69 _foreach (const ext::RedBlackSet<ext::String>, local, locals)
70 args.InsertLast(_S<ios::String>() << "-local=" << *local);
71
72 _S<api::Process> media(_B("Util/media"), args);
73
74 Media(*media.GetReader());
75
76 media.Join();
77 }
78
79 {
80 _L<ext::String> args;
81
82 args.InsertLast(_B("-s"));
83 args.InsertLast(_B("object/DecentralizedMedia.hh.gch"));
84
85 _S<api::Process> make(CFG_GNU_MAKE, args);
86
87 make.ClearWriter();
88
89 _S<ios::String> error;
90
91 ios::ReadToWrite(*make.GetReader(), error);
92
93 if (make.Join() != 0)
94 throw ext::StringException(error);
95 }
96
97 AddPort(6996);
98 }
99
100 DecentralizedMedia::~DecentralizedMedia()
101 {
102 if (!process.IsEmpty())
103 {
104 _H<api::Thread> thread(new api::Thread(etl::BindAll(&DecentralizedMedia::Destroy, this)));
105
106 bmp.Quit();
107
108 thread->Join();
109 }
110 }
111
112 _L<ext::String> DecentralizedMedia::GetArtists() const
113 {
114 _H<dbi::ResultSet> artists_(connection->Execute(_B("SELECT DISTINCT artist FROM files WHERE live = TRUE")));
115 _L<ext::String> artists;
116
117 while (artists_->MoveNext())
118 artists.InsertLast(artists_->GetString(_B("artist")));
119
120 return artists;
121 }
122
123 _L<ext::String> DecentralizedMedia::GetTitles() const
124 {
125 _H<dbi::ResultSet> titles_(connection->Execute(_B("SELECT DISTINCT title FROM files WHERE live = TRUE")));
126 _L<ext::String> titles;
127
128 while (titles_->MoveNext())
129 titles.InsertLast(titles_->GetString(_B("title")));
130
131 return titles;
132 }
133
134 _L<ext::String> DecentralizedMedia::GetAlbums() const
135 {
136 _H<dbi::ResultSet> albums_(connection->Execute(_B("SELECT DISTINCT album FROM files WHERE live = TRUE")));
137 _L<ext::String> albums;
138
139 while (albums_->MoveNext())
140 albums.InsertLast(albums_->GetString(_B("album")));
141
142 return albums;
143 }
144
145 _L<ext::String> DecentralizedMedia::GetGenres() const
146 {
147 _H<dbi::ResultSet> genres_(connection->Execute(_B("SELECT DISTINCT album FROM files WHERE live = TRUE")));
148 _L<ext::String> genres;
149
150 while (genres_->MoveNext())
151 genres.InsertLast(genres_->GetString(_B("genre")));
152
153 return genres;
154 }
155
156 _L<MediaFolder> DecentralizedMedia::GetFolders() const
157 {
158 _H<dbi::ResultSet> paths(connection->Execute(_B("SELECT DISTINCT root FROM files WHERE live = TRUE")));
159 _L<MediaFolder> folders;
160
161 while (paths->MoveNext())
162 folders.InsertLast(MediaFolder(connection, paths->GetString(_B("path"))));
163
164 return folders;
165 }
166
167 void DecentralizedMedia::Process(const net::Http::Request& request, net::Http::Response& response)
168 {
169 if (request.method_ == _B("EXTENSIONS") || request.method_ == _B("GET") && request.uri_.GetUri().IsEmpty())
170 {
171 api::Cout << "EXTENSIONS" << ios::NewLine;
172
173 response.SetStatus(200);
174
175 _foreach (const ext::RedBlackSet<ext::String>, extension, extensions)
176 response << *extension << ios::NewLineNoFlush;
177 }
178 else if (request.method_ == _B("MEDIA") || request.method_ == _B("POST") && request.uri_.GetUri().IsEmpty())
179 {
180 api::Cout << "MEDIA" << ios::NewLine;
181
182 if (!request.content_.IsEmpty())
183 {
184 Media(*request.content_);
185
186 response.SetStatus(204);
187 }
188 else
189 response.SetStatus(402);
190 }
191 else
192 waf::Server::Process(request, response);
193 }
194
195 void DecentralizedMedia::Media(ios::Reader& media)
196 {
197 _H<xml::Document> document(xml::Parse(media));
198 api::Pcre::RegEx share("^//(.+)/(.+)$");
199
200 _foreach (const xml::NodeSet, folder, *document/"media"/"folder")
201 {
202 ext::String path(**folder/"path");
203
204 if (api::Pcre::RegEx::Match match = share(path))
205 {
206 _H<Share> share(new Share(connection, match[1], match[2]));
207
208 path = share->path.GetPath();
209
210 // XXX: these are probably going to need read/write locking
211 sharesByPath[path] = share;
212 sharesByHost[match[1]][match[2]] = share;
213
214 share->Mount();
215 }
216
217 Media(*folder, path, path);
218 }
219 }
220
221 void DecentralizedMedia::Media(const _H<xml::Node>& folder, const api::Path& path, const api::Path& root)
222 {
223 MediaFolder(connection, path, root);
224
225 _foreach (const xml::NodeSet, file, *folder/"file")
226 MediaFile(connection, path.GetChild(**file/"path"), **file/"artist", **file/"title", **file/"album", **file/"genre", root);
227
228 _foreach (const xml::NodeSet, folder_, *folder/"folder")
229 Media(*folder_, path.GetChild(**folder_/"path"), root);
230 }

Properties

Name Value
svn:eol-style native
svn:keywords Id