| 197 | } |
| 198 | |
| 199 | Task::Ptr ResourceAPI::getDependencyVersion(DependencySearchArgs&& args, Callback<ModPlatform::IndexedVersion>&& callbacks) const |
| 200 | { |
| 201 | auto versions_url_optional = getDependencyURL(args); |
| 202 | if (!versions_url_optional.has_value()) |
| 203 | return nullptr; |
| 204 | |
| 205 | auto versions_url = versions_url_optional.value(); |
| 206 | |
| 207 | auto netJob = makeShared<NetJob>(QString("%1::Dependency").arg(args.dependency.addonId.toString()), APPLICATION->network()); |
| 208 | auto [action, response] = Net::ApiDownload::makeByteArray(versions_url); |
| 209 | netJob->addNetAction(action); |
| 210 | |
| 211 | QObject::connect(netJob.get(), &NetJob::succeeded, [this, response, callbacks, args] { |
| 212 | QJsonParseError parse_error{}; |
| 213 | QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); |
| 214 | if (parse_error.error != QJsonParseError::NoError) { |
| 215 | qWarning() << "Error while parsing JSON response for getting dependency version at" << parse_error.offset |
| 216 | << "reason:" << parse_error.errorString(); |
| 217 | qWarning() << *response; |
| 218 | return; |
| 219 | } |
| 220 | |
| 221 | QJsonArray arr; |
| 222 | if (args.dependency.version.length() != 0 && doc.isObject()) { |
| 223 | arr.append(doc.object()); |
| 224 | } else { |
| 225 | arr = doc.isObject() ? doc.object()["data"].toArray() : doc.array(); |
| 226 | } |
| 227 | |
| 228 | QVector<ModPlatform::IndexedVersion> versions; |
| 229 | for (auto versionIter : arr) { |
| 230 | auto obj = versionIter.toObject(); |
| 231 | |
| 232 | auto file = loadIndexedPackVersion(obj, ModPlatform::ResourceType::Mod); |
| 233 | if (!file.addonId.isValid()) |
| 234 | file.addonId = args.dependency.addonId; |
| 235 | |
| 236 | if (file.fileId.isValid() && |
| 237 | (!file.loaders || args.loader & file.loaders)) // Heuristic to check if the returned value is valid |
| 238 | versions.append(file); |
| 239 | } |
| 240 | |
| 241 | auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool { |
| 242 | // dates are in RFC 3339 format |
| 243 | return a.date > b.date; |
| 244 | }; |
| 245 | std::sort(versions.begin(), versions.end(), orderSortPredicate); |
| 246 | auto bestMatch = versions.size() != 0 ? versions.front() : ModPlatform::IndexedVersion(); |
| 247 | callbacks.on_succeed(bestMatch); |
| 248 | }); |
| 249 | |
| 250 | // Capture a weak_ptr instead of a shared_ptr to avoid circular dependency issues. |
| 251 | // This prevents the lambda from extending the lifetime of the shared resource, |
| 252 | // as it only temporarily locks the resource when needed. |
| 253 | auto weak = netJob.toWeakRef(); |
| 254 | QObject::connect(netJob.get(), &NetJob::failed, [weak, callbacks](const QString& reason) { |
| 255 | int network_error_code = -1; |
| 256 | if (auto netJob = weak.lock()) { |
no test coverage detected