winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

VersionEntity.cpp (6362B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 
      4 #include "VersionEntity.h"
      5 
      6 #include "../ErrorHandling.h"
      7 #include "../ReportingHandler.h"
      8 #include "ContentId.h"
      9 
     10 #include <nlohmann/json.hpp>
     11 
     12 #define THROW_INVALID_RESPONSE_IF_NOT(condition, message, handler)                                                     \
     13     THROW_CODE_IF_NOT_LOG(ServiceInvalidResponse, condition, handler, message)
     14 
     15 using namespace SFS;
     16 using namespace SFS::details;
     17 using json = nlohmann::json;
     18 
     19 namespace
     20 {
     21 void ValidateContentType(const VersionEntity& entity, ContentType expectedType, const ReportingHandler& handler)
     22 {
     23     THROW_CODE_IF_LOG(Result::ServiceUnexpectedContentType,
     24                       entity.GetContentType() != expectedType,
     25                       handler,
     26                       "The service returned entity \"" + entity.contentId.name + "\" with content type [" +
     27                           ToString(entity.GetContentType()) + "] while the expected type was [" +
     28                           ToString(expectedType) + "]");
     29 }
     30 } // namespace
     31 
     32 std::unique_ptr<VersionEntity> VersionEntity::FromJson(const nlohmann::json& data, const ReportingHandler& handler)
     33 {
     34     // Expected format for a generic version entity:
     35     // {
     36     //   "ContentId": {
     37     //     "Namespace": <ns>,
     38     //     "Name": <name>,
     39     //     "Version": <version>
     40     //   }
     41     // }
     42     //
     43     // Expected extra elements for an app version entity:
     44     // {
     45     //   ...
     46     //   "UpdateId": "<id>",
     47     //   "Prerequisites": [
     48     //     {
     49     //       "Namespace": "<ns>",
     50     //       "Name": "<name>",
     51     //       "Version": "<version>"
     52     //     }
     53     //   ]
     54     // }
     55 
     56     THROW_INVALID_RESPONSE_IF_NOT(data.is_object(), "Response is not a JSON object", handler);
     57 
     58     std::unique_ptr<VersionEntity> tmp;
     59     const bool isAppEntity = data.contains("UpdateId");
     60     if (isAppEntity)
     61     {
     62         tmp = std::make_unique<AppVersionEntity>();
     63     }
     64     else
     65     {
     66         tmp = std::make_unique<GenericVersionEntity>();
     67     }
     68 
     69     THROW_INVALID_RESPONSE_IF_NOT(data.contains("ContentId"), "Missing ContentId in response", handler);
     70 
     71     const auto& contentId = data["ContentId"];
     72     THROW_INVALID_RESPONSE_IF_NOT(contentId.is_object(), "ContentId is not a JSON object", handler);
     73 
     74     THROW_INVALID_RESPONSE_IF_NOT(contentId.contains("Namespace"), "Missing ContentId.Namespace in response", handler);
     75     THROW_INVALID_RESPONSE_IF_NOT(contentId["Namespace"].is_string(), "ContentId.Namespace is not a string", handler);
     76     tmp->contentId.nameSpace = contentId["Namespace"];
     77 
     78     THROW_INVALID_RESPONSE_IF_NOT(contentId.contains("Name"), "Missing ContentId.Name in response", handler);
     79     THROW_INVALID_RESPONSE_IF_NOT(contentId["Name"].is_string(), "ContentId.Name is not a string", handler);
     80     tmp->contentId.name = contentId["Name"];
     81 
     82     THROW_INVALID_RESPONSE_IF_NOT(contentId.contains("Version"), "Missing ContentId.Version in response", handler);
     83     THROW_INVALID_RESPONSE_IF_NOT(contentId["Version"].is_string(), "ContentId.Version is not a string", handler);
     84     tmp->contentId.version = contentId["Version"];
     85 
     86     if (isAppEntity)
     87     {
     88         auto appEntity = dynamic_cast<AppVersionEntity*>(tmp.get());
     89 
     90         THROW_INVALID_RESPONSE_IF_NOT(data["UpdateId"].is_string(), "UpdateId is not a string", handler);
     91         appEntity->updateId = data["UpdateId"];
     92 
     93         THROW_INVALID_RESPONSE_IF_NOT(data.contains("Prerequisites"), "Missing Prerequisites in response", handler);
     94         THROW_INVALID_RESPONSE_IF_NOT(data["Prerequisites"].is_array(), "Prerequisites is not an array", handler);
     95 
     96         for (const auto& prereq : data["Prerequisites"])
     97         {
     98             THROW_INVALID_RESPONSE_IF_NOT(prereq.is_object(), "Prerequisite element is not a JSON object", handler);
     99 
    100             GenericVersionEntity prereqEntity;
    101             THROW_INVALID_RESPONSE_IF_NOT(prereq.contains("Namespace"),
    102                                           "Missing Prerequisite.Namespace in response",
    103                                           handler);
    104             THROW_INVALID_RESPONSE_IF_NOT(prereq["Namespace"].is_string(),
    105                                           "Prerequisite.Namespace is not a string",
    106                                           handler);
    107             prereqEntity.contentId.nameSpace = prereq["Namespace"];
    108 
    109             THROW_INVALID_RESPONSE_IF_NOT(prereq.contains("Name"), "Missing Prerequisite.Name in response", handler);
    110             THROW_INVALID_RESPONSE_IF_NOT(prereq["Name"].is_string(), "Prerequisite.Name is not a string", handler);
    111             prereqEntity.contentId.name = prereq["Name"];
    112 
    113             THROW_INVALID_RESPONSE_IF_NOT(prereq.contains("Version"),
    114                                           "Missing Prerequisite.Version in response",
    115                                           handler);
    116             THROW_INVALID_RESPONSE_IF_NOT(prereq["Version"].is_string(),
    117                                           "Prerequisite.Version is not a string",
    118                                           handler);
    119             prereqEntity.contentId.version = prereq["Version"];
    120 
    121             appEntity->prerequisites.push_back(std::move(prereqEntity));
    122         }
    123     }
    124     return tmp;
    125 }
    126 
    127 std::unique_ptr<ContentId> VersionEntity::ToContentId(VersionEntity&& entity, const ReportingHandler& handler)
    128 {
    129     std::unique_ptr<ContentId> tmp;
    130     THROW_IF_FAILED_LOG(ContentId::Make(std::move(entity.contentId.nameSpace),
    131                                         std::move(entity.contentId.name),
    132                                         std::move(entity.contentId.version),
    133                                         tmp),
    134                         handler);
    135     return tmp;
    136 }
    137 
    138 ContentType GenericVersionEntity::GetContentType() const
    139 {
    140     return ContentType::Generic;
    141 }
    142 
    143 ContentType AppVersionEntity::GetContentType() const
    144 {
    145     return ContentType::App;
    146 }
    147 
    148 AppVersionEntity* AppVersionEntity::GetAppVersionEntityPtr(std::unique_ptr<VersionEntity>& versionEntity,
    149                                                            const ReportingHandler& handler)
    150 {
    151     ValidateContentType(*versionEntity, ContentType::App, handler);
    152     return dynamic_cast<AppVersionEntity*>(versionEntity.get());
    153 }