Compare commits
2 Commits
ec3f7b4847
...
c5b4c1ace4
Author | SHA1 | Date | |
---|---|---|---|
c5b4c1ace4 | |||
e27c278b13 |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -5,6 +5,9 @@
|
|||||||
"vector": "cpp",
|
"vector": "cpp",
|
||||||
"string": "cpp",
|
"string": "cpp",
|
||||||
"format": "cpp",
|
"format": "cpp",
|
||||||
"string.h": "c"
|
"string.h": "c",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"text_encoding": "cpp",
|
||||||
|
"typeinfo": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -337,6 +337,20 @@ json DistroqueryAPI::getProvidersForRequirement(string repository, string requir
|
|||||||
}
|
}
|
||||||
|
|
||||||
j = getProvidersForRequirementFromDb(db, ct, requirement, flags, version, onlyarch);
|
j = getProvidersForRequirementFromDb(db, ct, requirement, flags, version, onlyarch);
|
||||||
|
|
||||||
|
// Add resolved file requirements
|
||||||
|
if (requirement[0] == '/') {
|
||||||
|
json fileProviders = getFileProviders(repository, requirement, onlyarch);
|
||||||
|
if (fileProviders.contains("providers")) {
|
||||||
|
if (!j.contains("providers")) {
|
||||||
|
j["providers"] = json::array();
|
||||||
|
}
|
||||||
|
for (auto provider:fileProviders["providers"]) {
|
||||||
|
j["providers"].push_back(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
@ -416,13 +430,166 @@ json DistroqueryAPI::getPackageSourceDetails(string repository, string package)
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
j["error"] = "error preparing query '" + sql + "'";
|
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
sqlite3_close(db);
|
sqlite3_close(db);
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json DistroqueryAPI::getFileProviders(string repository, string path, string arch) {
|
||||||
|
json j;
|
||||||
|
string sql;
|
||||||
|
sqlite3_stmt *stmt, *stmt2;
|
||||||
|
|
||||||
|
struct configTag* ct = findRepositoryByTag(repository.c_str());
|
||||||
|
if (ct == NULL) {
|
||||||
|
j["error"] = "repository with tag '" + repository + "' does not exist";
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ct->repodata_url == NULL) {
|
||||||
|
j["error"] = "repository with tag '" + repository + "' is not supported by this API";
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
string dbname;
|
||||||
|
json providers = json::array();
|
||||||
|
while (ct->repository[i]) {
|
||||||
|
dbname = string(ct->repository[i]->repository_dir) + ct->repository[i]->tag + "-" + arch + "-files.db";
|
||||||
|
auto db = openRepositoryDatabase(ct->repository[i], arch, "-files");
|
||||||
|
if (!db) {
|
||||||
|
j["error"] = "error opening database for repository " + string(ct->repository[i]->tag) + " and arch " + arch;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pos = 0;
|
||||||
|
string s = path + "/";
|
||||||
|
long parent = -1;
|
||||||
|
while ((pos = s.find("/")) != std::string::npos) {
|
||||||
|
string name;
|
||||||
|
string token = s.substr(0, pos);
|
||||||
|
if (token != "") {
|
||||||
|
sql = "SELECT id,parent FROM files WHERE name='" + token + "' AND parent=" + to_string(parent);
|
||||||
|
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) {
|
||||||
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
long id = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, NULL, "id"));
|
||||||
|
parent = id;
|
||||||
|
} else {
|
||||||
|
// not found
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.erase(0, pos + 1);
|
||||||
|
if (s.length() == 0) {
|
||||||
|
// found
|
||||||
|
sql = "SELECT name FROM packages_files_rel WHERE id_file=" + to_string(parent);
|
||||||
|
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt2, NULL) == SQLITE_OK) {
|
||||||
|
if (sqlite3_step(stmt2) == SQLITE_ROW) {
|
||||||
|
json provider;
|
||||||
|
provider["repository"] = string(ct->repository[i]->tag);
|
||||||
|
provider["name"] = reinterpret_cast<const char*>(sqlite3_column_text(stmt2,sqlite3_find_column_id(stmt2, NULL, "name")));
|
||||||
|
provider["flags"] = "";
|
||||||
|
provider["version"] = "";
|
||||||
|
providers.push_back(provider);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_close(db);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
j["providers"] = providers;
|
||||||
|
return j;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
string DistroqueryAPI::resolvePackageFilePathById(sqlite3 *db, long id) {
|
||||||
|
string sql;
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
string outpath="";
|
||||||
|
static long cachedid = -1;
|
||||||
|
static string cachedpath = "";
|
||||||
|
|
||||||
|
if (id == cachedid)
|
||||||
|
return cachedpath;
|
||||||
|
|
||||||
|
cachedid = id;
|
||||||
|
|
||||||
|
while (id >= 0) {
|
||||||
|
sql = "SELECT parent,name FROM files WHERE id=" + to_string(id);
|
||||||
|
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) {
|
||||||
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
id = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, NULL, "parent"));
|
||||||
|
string name = reinterpret_cast<const char*>(sqlite3_column_text(stmt,sqlite3_find_column_id(stmt, NULL, "name")));
|
||||||
|
outpath = "/" + name + outpath;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedpath = outpath;
|
||||||
|
return outpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
json DistroqueryAPI::getPackageFiles(string repository, string package, string arch) {
|
||||||
|
json j;
|
||||||
|
string sql;
|
||||||
|
sqlite3_stmt *stmt;
|
||||||
|
|
||||||
|
struct configTag* ct = findRepositoryByTag(repository.c_str());
|
||||||
|
if (ct == NULL) {
|
||||||
|
j["error"] = "repository with tag '" + repository + "' does not exist";
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ct->repodata_url == NULL) {
|
||||||
|
j["error"] = "repository with tag '" + repository + "' is not supported by this API";
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto db = openRepositoryDatabase(ct, arch, "-files");
|
||||||
|
if (!db) {
|
||||||
|
j["error"] = "error opening database for repository " + repository + " and arch " + arch;
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
sql = "SELECT files.id,files.parent,files.name FROM files,packages_files_rel WHERE packages_files_rel.name = '" + package + "' " +
|
||||||
|
"AND files.id=packages_files_rel.id_file";
|
||||||
|
if (sqlite3_prepare_v2(db, sql.c_str(), sql.length(), &stmt, NULL) == SQLITE_OK) {
|
||||||
|
json files = json::array();
|
||||||
|
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
json file;
|
||||||
|
long parent = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, NULL, "parent"));
|
||||||
|
file["path"] = resolvePackageFilePathById(db, parent) + "/" +
|
||||||
|
reinterpret_cast<const char*>(sqlite3_column_text(stmt,sqlite3_find_column_id(stmt, NULL, "name")));
|
||||||
|
// TODO: unusable/missing values
|
||||||
|
/*file["flags"] = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, "packages_files_rel", "flags"));
|
||||||
|
file["user"] = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, "packages_files_rel", "user"));
|
||||||
|
file["group"] = sqlite3_column_int(stmt,sqlite3_find_column_id(stmt, "packages_files_rel", "group"));*/
|
||||||
|
files.push_back(file);
|
||||||
|
}
|
||||||
|
j["files"] = files;
|
||||||
|
} else {
|
||||||
|
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_close(db);
|
||||||
|
return j;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
json DistroqueryAPI::getPackageDetails(string repository, string package, string arch) {
|
json DistroqueryAPI::getPackageDetails(string repository, string package, string arch) {
|
||||||
json j;
|
json j;
|
||||||
string sql;
|
string sql;
|
||||||
@ -534,8 +701,15 @@ json DistroqueryAPI::getPackageDetails(string repository, string package, string
|
|||||||
sqlite3_finalize(stmt2);
|
sqlite3_finalize(stmt2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Package files
|
||||||
|
json files = getPackageFiles(repository, package, arch);
|
||||||
|
if (files.contains("files"))
|
||||||
|
j["files"] = files["files"];
|
||||||
|
else
|
||||||
|
j["files"] = files;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
j["error"] = "error preparing query '" + sql + "'";
|
j["error"] = "error preparing query '" + sql + "': " + sqlite3_errmsg(db);
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,6 +808,12 @@ void DistroqueryAPI::getApiResponse(string path_info) {
|
|||||||
|
|
||||||
if (v.size() > 0) {
|
if (v.size() > 0) {
|
||||||
path = v[0];
|
path = v[0];
|
||||||
|
// Fix URL decoding due to '%' returned encoded as '%25'
|
||||||
|
size_t pos = path.find("%25");
|
||||||
|
while (pos != string::npos) {
|
||||||
|
path.replace(pos, 3, "%");
|
||||||
|
pos = path.find("%25", pos + 1);
|
||||||
|
}
|
||||||
path_split = split(path, "/");
|
path_split = split(path, "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,14 +870,30 @@ void DistroqueryAPI::getApiResponse(string path_info) {
|
|||||||
// API service: package
|
// API service: package
|
||||||
if (path_split.size() < 3 || path_split.size() > 4)
|
if (path_split.size() < 3 || path_split.size() > 4)
|
||||||
sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]);
|
sendErrorResponse("expected 3 or 4 arguments for " + path_split[0]);
|
||||||
json details;
|
json response;
|
||||||
string package = urlDecode(path_split[2]);
|
string package = urlDecode(path_split[2]);
|
||||||
if (path_split.size() == 3) {
|
if (path_split.size() == 3) {
|
||||||
details = getPackageSourceDetails(path_split[1], package);
|
response = getPackageSourceDetails(path_split[1], package);
|
||||||
} else {
|
} else {
|
||||||
details = getPackageDetails(path_split[1], package, path_split[3]);
|
response = getPackageDetails(path_split[1], package, path_split[3]);
|
||||||
}
|
}
|
||||||
cout << details.dump();
|
cout << response.dump();
|
||||||
|
} else if (path_split[0] == "package_files") {
|
||||||
|
// API service: package_files
|
||||||
|
if (path_split.size() != 4)
|
||||||
|
sendErrorResponse("expected 4 arguments for " + path_split[0]);
|
||||||
|
json response;
|
||||||
|
string package = urlDecode(path_split[2]);
|
||||||
|
response = getPackageFiles(path_split[1], package, path_split[3]);
|
||||||
|
cout << response.dump();
|
||||||
|
} else if (path_split[0] == "file_providers") {
|
||||||
|
// API service: package_files
|
||||||
|
if (path_split.size() != 4)
|
||||||
|
sendErrorResponse("expected 4 arguments for " + path_split[0]);
|
||||||
|
json response;
|
||||||
|
string filepath = urlDecode(path_split[2]);
|
||||||
|
response = getFileProviders(path_split[1], filepath, path_split[3]);
|
||||||
|
cout << response.dump();
|
||||||
} else if (path_split[0] == "providers") {
|
} else if (path_split[0] == "providers") {
|
||||||
// API service: providers
|
// API service: providers
|
||||||
if (path_split.size() != 3 && path_split.size() != 5)
|
if (path_split.size() != 3 && path_split.size() != 5)
|
||||||
@ -717,7 +913,7 @@ void DistroqueryAPI::getApiResponse(string path_info) {
|
|||||||
json problems = getRepositoryProblems(path_split[1]);
|
json problems = getRepositoryProblems(path_split[1]);
|
||||||
cout << problems.dump();
|
cout << problems.dump();
|
||||||
} else {
|
} else {
|
||||||
sendErrorResponse("invalid request for service '" + path_split[0]);
|
sendErrorResponse("unknown service: '" + path_split[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendErrorResponse("empty request");
|
sendErrorResponse("empty request");
|
||||||
|
@ -48,7 +48,10 @@ class DistroqueryAPI {
|
|||||||
json getProvidersForRequirement(string repository, string requirement, string flags,
|
json getProvidersForRequirement(string repository, string requirement, string flags,
|
||||||
string version, string onlyarch="");
|
string version, string onlyarch="");
|
||||||
json getPackageSourceDetails(string repository, string package);
|
json getPackageSourceDetails(string repository, string package);
|
||||||
|
string resolvePackageFilePathById(sqlite3 *db, long id);
|
||||||
json getBuiltPackagesFromSourceID(configTag* ct, long id);
|
json getBuiltPackagesFromSourceID(configTag* ct, long id);
|
||||||
|
json getFileProviders(string repository, string path, string arch);
|
||||||
|
json getPackageFiles(string repository, string package, string arch);
|
||||||
json getPackageDetails(string repository, string package, string arch);
|
json getPackageDetails(string repository, string package, string arch);
|
||||||
json getRepositoryProblems(string repository);
|
json getRepositoryProblems(string repository);
|
||||||
};
|
};
|
||||||
|
@ -146,10 +146,9 @@ int sqlite3_find_column_id(sqlite3_stmt *stmt, const char* table, const char* na
|
|||||||
string urlDecode(string str) {
|
string urlDecode(string str) {
|
||||||
string ret;
|
string ret;
|
||||||
char ch;
|
char ch;
|
||||||
int i, len = str.length();
|
|
||||||
unsigned int ii;
|
unsigned int ii;
|
||||||
|
|
||||||
for (i=0; i < len; i++){
|
for (int i=0; i < str.length(); i++){
|
||||||
if (str[i] != '%') {
|
if (str[i] != '%') {
|
||||||
if (str[i] == '+')
|
if (str[i] == '+')
|
||||||
ret += ' ';
|
ret += ' ';
|
||||||
|
Loading…
Reference in New Issue
Block a user