1 /*
2 * Copyright (C) 2020 Luciano Iam <oss@lucianoiam.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the/GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <iostream>
20 #include <sstream>
21
22 #include <glibmm/fileutils.h>
23 #include <glibmm/miscutils.h>
24
25 #include "ardour/filesystem_paths.h"
26 #include "pbd/file_utils.h"
27
28 #include "resources.h"
29 #include "json.h"
30
31 using namespace ArdourSurface;
32
33 static const char* const data_dir_env_var = "ARDOUR_WEBSURFACES_PATH";
34 static const char* const data_dir_name = "web_surfaces";
35 static const char* const builtin_dir_name = "builtin";
36 static const char* const user_dir_name = "user";
37
38 static bool
dir_filter(const std::string & str,void *)39 dir_filter (const std::string &str, void* /*arg*/)
40 {
41 return Glib::file_test (str, Glib::FILE_TEST_IS_DIR);
42 }
43
ServerResources()44 ServerResources::ServerResources ()
45 : _index_dir ("")
46 , _builtin_dir ("")
47 , _user_dir ("")
48 {
49 }
50
51 const std::string&
index_dir()52 ServerResources::index_dir ()
53 {
54 if (_index_dir.empty ()) {
55 _index_dir = server_data_dir ();
56 }
57
58 return _index_dir;
59 }
60
61 const std::string&
builtin_dir()62 ServerResources::builtin_dir ()
63 {
64 if (_builtin_dir.empty ()) {
65 _builtin_dir = Glib::build_filename (server_data_dir (), builtin_dir_name);
66 }
67
68 return _builtin_dir;
69 }
70
71 const std::string&
user_dir()72 ServerResources::user_dir ()
73 {
74 if (_user_dir.empty ()) {
75 _user_dir = Glib::build_filename (ARDOUR::user_config_directory (), data_dir_name);
76 }
77
78 return _user_dir;
79 }
80
81 std::string
scan()82 ServerResources::scan ()
83 {
84 std::stringstream ss;
85
86 std::string builtin_dir_str = PBD::canonical_path (builtin_dir ());
87 SurfaceManifestVector builtin = read_manifests (builtin_dir_str);
88
89 ss << "[{"
90 << "\"filesystemPath\":\"" << WebSocketsJSON::escape (builtin_dir_str) << "\""
91 << ",\"path\":\"" << WebSocketsJSON::escape (builtin_dir_name) << "\""
92 << ",\"surfaces\":"
93 << "[";
94
95 for (SurfaceManifestVector::iterator it = builtin.begin (); it != builtin.end (); ) {
96 ss << it->to_json ();
97 if (++it != builtin.end()) {
98 ss << ",";
99 }
100 }
101
102 std::string user_dir_str = PBD::canonical_path (user_dir ());
103 SurfaceManifestVector user = read_manifests (user_dir_str);
104
105 ss << "]},{"
106 << "\"filesystemPath\":\"" << WebSocketsJSON::escape (user_dir_str) << "\""
107 << ",\"path\":\"" << WebSocketsJSON::escape (user_dir_name) << "\""
108 << ",\"surfaces\":"
109 << "[";
110
111 for (SurfaceManifestVector::iterator it = user.begin (); it != user.end (); ) {
112 ss << it->to_json ();
113 if (++it != user.end()) {
114 ss << ",";
115 }
116 }
117
118 ss << "]}]";
119
120 return ss.str ();
121 }
122
123 std::string
server_data_dir()124 ServerResources::server_data_dir ()
125 {
126 std::string data_dir;
127
128 bool defined = false;
129 std::string env_dir (Glib::getenv (data_dir_env_var, defined));
130
131 if (defined && !env_dir.empty ()) {
132 /* useful for development */
133 data_dir = env_dir;
134 } else {
135 /* use reverse iterator, since ardour_data_search_path() prefixes the user-data dir */
136 PBD::Searchpath s (ARDOUR::ardour_data_search_path ());
137 for (PBD::Searchpath::reverse_iterator i = s.rbegin (); i != s.rend(); ++i) {
138 data_dir = Glib::build_filename (*i, data_dir_name);
139 if (Glib::file_test(data_dir, Glib::FILE_TEST_EXISTS | Glib::FILE_TEST_IS_DIR)) {
140 break;
141 }
142 }
143 }
144
145 return data_dir;
146 }
147
148 SurfaceManifestVector
read_manifests(std::string dir)149 ServerResources::read_manifests (std::string dir)
150 {
151 SurfaceManifestVector result;
152 std::vector<std::string> subdirs;
153 PBD::Searchpath spath (dir);
154
155 find_paths_matching_filter (subdirs, spath, dir_filter,
156 0 /*arg*/, true /*pass_fullpath*/, true /*return_fullpath*/, false /*recurse*/);
157
158 for (std::vector<std::string>::const_iterator it = subdirs.begin (); it != subdirs.end (); ++it) {
159 if (!SurfaceManifest::exists_at_path (*it)) {
160 continue;
161 }
162
163 SurfaceManifest manifest (*it);
164
165 if (manifest.valid ()) {
166 result.push_back (manifest);
167 }
168 }
169
170 return result;
171 }
172