summaryrefslogtreecommitdiffstats
path: root/api/logic/modplatform/flame/FileResolvingTask.cpp
blob: 24cafcddbecb4cc00d33cc69ea95b158b225cdb5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "FileResolvingTask.h"
#include "Json.h"

const char * metabase = "https://cursemeta.dries007.net";

Flame::FileResolvingTask::FileResolvingTask(Flame::Manifest& toProcess)
    : m_toProcess(toProcess)
{
}

void Flame::FileResolvingTask::executeTask()
{
    setStatus(tr("Resolving mod IDs..."));
    setProgress(0, m_toProcess.files.size());
    m_dljob.reset(new NetJob("Mod id resolver"));
    results.resize(m_toProcess.files.size());
    int index = 0;
    for(auto & file: m_toProcess.files)
    {
        auto projectIdStr = QString::number(file.projectId);
        auto fileIdStr = QString::number(file.fileId);
        QString metaurl = QString("%1/%2/%3.json").arg(metabase, projectIdStr, fileIdStr);
        auto dl = Net::Download::makeByteArray(QUrl(metaurl), &results[index]);
        m_dljob->addNetAction(dl);
        index ++;
    }
    connect(m_dljob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::netJobFinished);
    m_dljob->start();
}

void Flame::FileResolvingTask::netJobFinished()
{
    bool failed = false;
    int index = 0;
    for(auto & bytes: results)
    {
        try
        {
            auto doc = Json::requireDocument(bytes);
            auto obj = Json::requireObject(doc);
            auto & out = m_toProcess.files[index];
            // result code signifies true failure.
            if(obj.contains("code"))
            {
                qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a negative result:";
                qCritical() << bytes;
                failed = true;
                continue;
            }
            out.fileName = Json::requireString(obj, "FileNameOnDisk");
            QString rawUrl = Json::requireString(obj, "DownloadURL");
            out.url = QUrl(rawUrl, QUrl::TolerantMode);
            if(!out.url.isValid())
            {
                throw JSONValidationError(QString("Invalid URL: %1").arg(rawUrl));
            }
            // This is a piece of a Flame project JSON pulled out into the file metadata (here) for convenience
            // It is also optional
            QJsonObject projObj = Json::ensureObject(obj, "_Project", {});
            if(!projObj.isEmpty())
            {
                QString strType = Json::ensureString(projObj, "PackageType", "mod").toLower();
                if(strType == "singlefile")
                {
                    out.type = File::Type::SingleFile;
                }
                else if(strType == "ctoc")
                {
                    out.type = File::Type::Ctoc;
                }
                else if(strType == "cmod2")
                {
                    out.type = File::Type::Cmod2;
                }
                else if(strType == "mod")
                {
                    out.type = File::Type::Mod;
                }
                else if(strType == "folder")
                {
                    out.type = File::Type::Folder;
                }
                else if(strType == "modpack")
                {
                    out.type = File::Type::Modpack;
                }
                else
                {
                    qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of unknown file type:" << strType;
                    out.type = File::Type::Unknown;
                    failed = true;
                    continue;
                }
                out.targetFolder = Json::ensureString(projObj, "Path", "mods");
            }
            out.resolved = true;
        }
        catch (const JSONValidationError &e)
        {
            auto & out = m_toProcess.files[index];
            qCritical() << "Resolving of" << out.projectId << out.fileId << "failed because of a parsing error:";
            qCritical() << e.cause();
            qCritical() << "JSON:";
            qCritical() << bytes;
            failed = true;
        }
        index++;
    }
    if(!failed)
    {
        emitSucceeded();
    }
    else
    {
        emitFailed(tr("Some mod ID resolving tasks failed."));
    }
}