1 #include "singletons/Paths.hpp" 2 3 #include "singletons/Settings.hpp" 4 5 #include <QCoreApplication> 6 #include <QCryptographicHash> 7 #include <QDir> 8 #include <QStandardPaths> 9 #include <cassert> 10 11 #include "common/Modes.hpp" 12 #include "util/CombinePath.hpp" 13 14 using namespace std::literals; 15 16 namespace chatterino { 17 18 Paths *Paths::instance = nullptr; 19 Paths()20Paths::Paths() 21 { 22 this->instance = this; 23 24 this->initAppFilePathHash(); 25 26 this->initCheckPortable(); 27 this->initRootDirectory(); 28 this->initSubDirectories(); 29 } 30 createFolder(const QString & folderPath)31bool Paths::createFolder(const QString &folderPath) 32 { 33 return QDir().mkpath(folderPath); 34 } 35 isPortable()36bool Paths::isPortable() 37 { 38 return Modes::instance().isPortable; 39 } 40 cacheDirectory()41QString Paths::cacheDirectory() 42 { 43 static const auto pathSetting = [] { 44 QStringSetting cachePathSetting("/cache/path"); 45 46 cachePathSetting.connect([](const auto &newPath, auto) { 47 if (!newPath.isEmpty()) 48 { 49 QDir().mkpath(newPath); 50 } 51 }); 52 53 return cachePathSetting; 54 }(); 55 56 auto path = pathSetting.getValue(); 57 58 if (path.isEmpty()) 59 { 60 return this->cacheDirectory_; 61 } 62 63 return path; 64 } 65 initAppFilePathHash()66void Paths::initAppFilePathHash() 67 { 68 this->applicationFilePathHash = 69 QCryptographicHash::hash( 70 QCoreApplication::applicationFilePath().toUtf8(), 71 QCryptographicHash::Sha224) 72 .toBase64() 73 .mid(0, 32) 74 .replace("+", "-") 75 .replace("/", "x"); 76 } 77 initCheckPortable()78void Paths::initCheckPortable() 79 { 80 this->portable_ = QFileInfo::exists( 81 combinePath(QCoreApplication::applicationDirPath(), "portable")); 82 } 83 initRootDirectory()84void Paths::initRootDirectory() 85 { 86 assert(this->portable_.is_initialized()); 87 88 // Root path = %APPDATA%/Chatterino or the folder that the executable 89 // resides in 90 91 this->rootAppDataDirectory = [&]() -> QString { 92 // portable 93 if (this->isPortable()) 94 { 95 return QCoreApplication::applicationDirPath(); 96 } 97 98 // permanent installation 99 QString path = 100 QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); 101 if (path.isEmpty()) 102 { 103 throw std::runtime_error("Could not create directory \""s + 104 path.toStdString() + "\""); 105 } 106 107 // create directory Chatterino2 instead of chatterino on windows because the 108 // ladder one is takes by chatterino 1 already 109 #ifdef Q_OS_WIN 110 path.replace("chatterino", "Chatterino"); 111 112 path += "2"; 113 #endif 114 return path; 115 }(); 116 } 117 initSubDirectories()118void Paths::initSubDirectories() 119 { 120 // required the app data directory to be set first 121 assert(!this->rootAppDataDirectory.isEmpty()); 122 123 // create settings subdirectories and validate that they are created 124 // properly 125 auto makePath = [&](const std::string &name) -> QString { 126 auto path = combinePath(this->rootAppDataDirectory, 127 QString::fromStdString(name)); 128 129 if (!QDir().mkpath(path)) 130 { 131 throw std::runtime_error("Could not create directory \""s + 132 path.toStdString() + "\""); 133 } 134 135 return path; 136 }; 137 138 makePath(""); 139 this->settingsDirectory = makePath("Settings"); 140 this->cacheDirectory_ = makePath("Cache"); 141 this->messageLogDirectory = makePath("Logs"); 142 this->miscDirectory = makePath("Misc"); 143 this->twitchProfileAvatars = makePath("ProfileAvatars"); 144 //QDir().mkdir(this->twitchProfileAvatars + "/twitch"); 145 } 146 getPaths()147Paths *getPaths() 148 { 149 return Paths::instance; 150 } 151 152 } // namespace chatterino 153