2018-09-22 redis desktop windows 相關

1.為什么

  • redis相關學習
  • 了解redisdesktop代碼架構
  • 學習c++下面如何優(yōu)雅地與redis進行數(shù)據(jù)通信

2.是什么

Open source cross-platform Redis Desktop Manager based on Qt 5
跨平臺的基于qt5的redis桌面控制端

3.編譯安裝【參考官網

3.1、環(huán)境相關

windows 10
visual studio 2015[自行安裝即可]
qt5.9.2【qt官網舊版本地址
git
cmake【用于編譯libssh2

3.2、下載源碼

git clone --recursive https://github.com/uglide/RedisDesktopManager.git -b 0.9 rdm

3.3、官網步驟

Build on Windows

  1. Install Visual Studio 2015 Community with Updates
  2. Install Qt 5.9
  3. Install Win32 Openssl 1.0.X

第一個坑,需要安裝1.0.x版本,安裝1.1.X之后報缺少相應的動態(tài)庫。

第二個坑,安裝的路徑不要出現(xiàn)空格等異常字符,會導致找不到相關的動態(tài)庫,默認安裝C:\OpenSSL-Win32即可,如果安裝在其他目錄,編譯文件rds\RedisDesktopManager\3rdparty\qredisclient\3rdparty\qsshclient\3rdparty\3rdparty.pri修改相應的路徑即可


  1. Install CMake
  2. Build libssh2 library in folder 3rdparty/qredisclient/3rdparty/qsshclient/3rdparty/libssh2 using CMake

編譯步驟:
1、進入libssh2目錄
2、mkdir bin
3、cd bin
4、cmake .. 【等待完成】
5、cmake --build . 【等待完成】

第一個坑, 由于git下來之后目錄太長,導致文件文全路徑超過了256,將libssh2移到較短的路徑下面即可,如果移動了,記得編譯完成之后拷回原先的文件夾中

第二個坑,編譯生產的libssh2實際在目錄libssh2\bin\src\Debug下面,需要手動修改
rds\RedisDesktopManager\3rdparty\qredisclient\3rdparty\qsshclient\3rdparty\3rdparty.pri編譯路徑


  1. Open ./src/rdm.pro in Qt Creator
    阿彌陀佛,終于編譯完成


  2. Run build

4.源碼研究

4.1異常處理

main函數(shù)中有下面的一段代碼

    QFileInfo appPath(QString::fromLocal8Bit(argv[0]));
    QString appDir(appPath.absoluteDir().path());
    QString crashReporterPath = QString("%1/crashreporter").arg(appDir.isEmpty() ? "." : appDir);
    CrashHandler::instance()->Init(QDir::homePath(), appPath.absoluteFilePath(), crashReporterPath);

字面意思理解應該是異常崩潰處理,剛好是之前工作中遇到的,之前在公司中使用的是處理

windows下面異常奔潰處理,印象中是使用的minidump相關的東西
linux下面是core dump相關的東西,印象中是可以使用命令ulimit開啟,也可以在程序中通過setrlimit系統(tǒng)調用開啟,然后使用gdb進行數(shù)據(jù)查看

且看這邊是如何使用的。
單例模式的CrashHandler,具體的實現(xiàn)在CrashHandlerPrivate中,qt中典型的代碼模式。

class CrashHandlerPrivate;
class CrashHandler
{
public:
    static CrashHandler* instance();
    //初始化函數(shù)
    void Init(const QString&  reportPath, const QString &appPath, const QString &crashReporterFullPath);

    void setReportCrashesToSystem(bool report);
    bool writeMinidump();

private:
    CrashHandler();
    ~CrashHandler();
    Q_DISABLE_COPY(CrashHandler)
        CrashHandlerPrivate* d;
};

init函數(shù)調用直接調用CrashHandlerPrivate::InitCrashHandler函數(shù),且仔細看來

void CrashHandlerPrivate::InitCrashHandler(const QString& dumpPath, const QString& appPath, const QString& crashReporterFullPath)
{
    if ( pHandler != NULL )
        return;

    wcscpy(applicationPath, appPath.toStdWString().c_str());
    wcscpy(crashReporterPath, crashReporterFullPath.toStdWString().c_str());
 
#if defined(Q_OS_WIN32)
    std::wstring pathAsStr = (const wchar_t*)dumpPath.utf16();
    pHandler = new google_breakpad::ExceptionHandler(
        pathAsStr,
        /*FilterCallback*/ 0,
        DumpCallback,
        /*context*/
        0,
        true
        );
#elif defined(Q_OS_LINUX)
    std::string pathAsStr = dumpPath.toStdString();
    google_breakpad::MinidumpDescriptor md(pathAsStr);
    pHandler = new google_breakpad::ExceptionHandler(
        md,
        /*FilterCallback*/ 0,
        DumpCallback,
        /*context*/ 0,
        true,
        -1
        );
#elif defined(Q_OS_MAC)
    std::string pathAsStr = dumpPath.toStdString();
    pHandler = new google_breakpad::ExceptionHandler(
        pathAsStr,
        /*FilterCallback*/ 0,
        DumpCallback,
        /*context*/
        0,
        true,
        NULL
        );
#endif
}

使用的是google breakpad相關異常處理,貌似之前在哪邊看到過,搜索一下詳細介紹google breakpad, 以后項目中可以考慮。

4.2main函數(shù)繼續(xù)

主程序這種Application

    Application a(argc, argv);
    a.initModels();
    a.initQml();

Application繼承于QApplication,
構造函數(shù)

Application::Application(int &argc, char **argv)
    : QApplication(argc, argv),
      m_engine(this),
      m_qmlUtils(QSharedPointer<QmlUtils>(new QmlUtils())),      
      m_logger(nullptr)
{
    // Init components required for models and qml
    initLog();
    initAppInfo();
    processCmdArgs();
    initAppFonts();    
    initRedisClient();
    initUpdater();    
    installTranslator();
}

4.2.1幾個成員變量

  • QQmlApplicationEngine m_engine; qt中定義QQmlApplicationEngine
  • QSharedPointer<QmlUtils> m_qmlUtils; 工具類
  • QSharedPointer<ConnectionsManager> m_connections; 用于與redis進行通信使用
  • QSharedPointer<Updater> m_updater;查詢新版本
  • QSharedPointer<ValueEditor::TabsModel> m_keyValues;
  • QSharedPointer<ValueEditor::FormattersManager> m_formattersManager;
  • QSharedPointer<BulkOperations::Manager> m_bulkOperations;
  • QSharedPointer<TabViewModel> m_consoleModel;
  • QSharedPointer<TabViewModel> m_serverStatsModel;
  • QSharedPointer<Console::AutocompleteModel> m_consoleAutocompleteModel;
  • LogHandler* m_logger;

使用的第三方的庫 easylogging++

class LogHandler : public QObject, public el::LogDispatchCallback

參見easylogging++詳細講解

void Application::initLog()
{
    el::Configurations defaultConf;
    defaultConf.setToDefault();
    defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
    defaultConf.setGlobally(el::ConfigurationType::ToFile, "false");
    el::Loggers::reconfigureLogger("default", defaultConf);

    el::Loggers::removeFlag(el::LoggingFlag::NewLineForContainer);
    el::Helpers::installLogDispatchCallback<LogHandler>("LogHandler");
    m_logger = el::Helpers::logDispatchCallback<LogHandler>("LogHandler");

    if (!m_logger) {
        LOG(ERROR) << "App log: ERROR";
    } else {
        LOG(INFO) << "App log init: OK";
    }
}

上述是日志初始化。

  • QString m_settingsDir; 保存連接redis的參數(shù)

  • QString m_renderingBackend;是否renderingBackend

4.2.2構造函數(shù)

4.2.2.1 initLog();日志初始化,見上

4.2.2.2 initAppInfo() 設置一些application的信息

4.2.2.3 processCmdArgs(); 處理命令行的參數(shù)

void Application::processCmdArgs()
{
    QCommandLineParser parser;    
    QCommandLineOption settingsDir(
            "settings-dir",
             "(Optional) Directory where RDM looks/saves .rdm directory with connections.json file",
             "settingsDir",
             QDir::homePath()
    );
    QCommandLineOption renderingBackend(
            "rendering-backend",
             "(Optional) QML rendering backend [software|opengl|d3d12|'']",
             "renderingBackend",
             "auto"
    );
    parser.addHelpOption();
    parser.addVersionOption();
    parser.addOption(settingsDir);
    parser.addOption(renderingBackend);
    parser.process(*this);

    m_settingsDir = parser.value(settingsDir);
    m_renderingBackend = parser.value(renderingBackend);
}

QCommandLineOption 之前未曾使用過,用于解析命令行參數(shù)的內容,gei it

4.2.2.4 initAppFonts() 設置字體參數(shù)

4.2.2.5 initRedisClient()初始化redisclient

inline void initRedisClient()
{
    qRegisterMetaType<RedisClient::Command>("Command");
    qRegisterMetaType<RedisClient::Command>("RedisClient::Command");
    qRegisterMetaType<RedisClient::Response>("Response");
    qRegisterMetaType<RedisClient::Response>("RedisClient::Response");
    qRegisterMetaType<QVector<QVariant*>>("QVector<QVariant*>");
    qRegisterMetaType<QVariant*>("QVariant*");    
}

只是注冊了一些redisclient的一些數(shù)據(jù)結構,連接redis,使用了qredisclient

4.2.2.6 initUpdater()初始化查詢是否有新版本,有新版本告警。

4.2.2.7installTranslator()用于國際化。

4.2.3 initModels()初始化數(shù)據(jù)項

void Application::initModels()
{
    //1、設置連接redis參數(shù),管理鏈接,初始化m_keyValues,記錄redis的一些關鍵參數(shù)信息TabsModel;初始化m_connections;初始化m_bulkOperations
    initConnectionsManager();
    //2、初始化m_consoleModel 
    m_consoleModel = QSharedPointer<TabViewModel>(new TabViewModel(getTabModelFactory<Console::Model>()));

    connect(m_connections.data(), &ConnectionsManager::openConsole,
            m_consoleModel.data(), &TabViewModel::openTab);

    m_serverStatsModel = QSharedPointer<TabViewModel>(new TabViewModel(getTabModelFactory<ServerStats::Model>()));

    connect(m_connections.data(), &ConnectionsManager::openServerStats,
            this, [this](QSharedPointer<RedisClient::Connection> c)
    {
        m_serverStatsModel->openTab(c);
    });

    m_formattersManager = QSharedPointer<ValueEditor::FormattersManager>(new ValueEditor::FormattersManager());
    m_formattersManager->loadFormatters();

    m_consoleAutocompleteModel = QSharedPointer<Console::AutocompleteModel>(new Console::AutocompleteModel());
}

4.2.4 initQml()初始化QML

void Application::initQml()
{             
    if (m_renderingBackend == "auto") {
        #if defined(Q_OS_WIN) || defined(Q_OS_LINUX)        
        // Use software renderer on Windows & Linux by default
        QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
        #endif
    } else {
        QQuickWindow::setSceneGraphBackend(m_renderingBackend);
    }

    registerQmlTypes();
    registerQmlRootObjects();

    try {
        //加載界面qml文件
        m_engine.load(QUrl(QStringLiteral("qrc:///app.qml")));
    } catch (...) {
        qDebug() << "Failed to load app window. Retrying with software renderer...";
        QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
        m_engine.load(QUrl(QStringLiteral("qrc:///app.qml")));
    }

    qDebug() << "Rendering backend:" << QQuickWindow::sceneGraphBackend();
}

5 第三方庫相關

閱讀源碼的時候發(fā)現(xiàn)很多的第三方庫,有些之前聽說過,但是具體的使用確不知道,有些實際就沒有聽說過,還是需要多看多記。

5.1 easyloging++

5.2 google breadpad

5.3 qredisclient

5.4 AsyncFuture

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Qt是屬于一個跨平臺的GUI開發(fā)軟件,支持的平臺有Unix、Linux、Windows/WinCE、IOS等。 Q...
    一葉之界閱讀 8,205評論 0 17
  • 說明本次redis集群安裝在rhel6.8 64位機器上,redis版本為3.2.8,redis的gem文件版本為...
    讀或寫閱讀 15,082評論 3 9
  • 回崇明(上·長篇小說連載三十二)作者 沈姜當小姨阿英從廂房里出來,準備去房后拿些柴草時,黑油衛(wèi)國眼睛使勁嘌望著小姨...
    姜蘇閱讀 132評論 0 0
  • 有一天,你突然想要學吉他。于是你興致勃勃買了吉他,跟著網絡教程自學。然后沒過幾天便開始懈怠,漸漸地練習吉他的次數(shù)越...
    無湦閱讀 212評論 0 0
  • 1、 我可以幫拿到比別的公司利息低的貸款; 2、 相同利息我可以幫你拿到高額度的貸款,甚至比銀行的還要高; 3、 ...
    南山石_0d4e閱讀 183評論 0 0