File indexing completed on 2024-04-14 05:34:15

0001 /*
0002     SPDX-FileCopyrightText: 2011 Vishesh Yadav <vishesh3y@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef HG_SERVE_WRAPPER_H
0008 #define HG_SERVE_WRAPPER_H
0009 
0010 #include <QHash>
0011 #include <QProcess>
0012 #include <QTextCodec>
0013 #include <QString>
0014 #include <KLocalizedString>
0015 
0016 class ServerProcessType;
0017 
0018 /**
0019  * Wrapper to manage web server instances of mercurial repository. More than one 
0020  * server can be handled. 
0021  *
0022  * This wrapper should be singleton hence only one instance should be created 
0023  * and used. Hence, never create an object statically or use 'new' operator.
0024  * Use instance() method to get(create) an instance.
0025  */
0026 class HgServeWrapper : public QObject
0027 {
0028     Q_OBJECT
0029 
0030 public: 
0031     explicit HgServeWrapper(QObject *parent=nullptr);
0032     ~HgServeWrapper() override;
0033 
0034     /**
0035      * Returns pointer to singleton instance of the wrapper. An instance is 
0036      * created if none exists. 
0037      *
0038      * @return Pointer to the instance 
0039      */
0040     static HgServeWrapper *instance();
0041 
0042     /**
0043      * Starts a new instance of server.
0044      *
0045      * @param repoLocation Path to repository which is to be hosted on server
0046      * @param portNumber Port to create server on.
0047      *
0048      */
0049     void startServer(const QString &repoLocation, int portNumber);
0050 
0051     /**
0052      * Stops a server.
0053      *
0054      * @param repoLocation Path to repository whose server instance in this
0055      *                 has to be stopped.
0056      */
0057     void stopServer(const QString &repoLocation);
0058 
0059     /**
0060      * Checks whether a web server for given repository is running under this
0061      * wrapper.
0062      *
0063      * @param repoLocation Path to repository
0064      * @return true if running/started else false
0065      */
0066     bool running(const QString &repoLocation);
0067 
0068     /**
0069      * Cleans all resources in this wrapper used by non-running servers
0070      */
0071     void cleanUnused();
0072 
0073     /**
0074      * If terminated, get error message of that server instances
0075      */
0076     QString errorMessage(const QString &repoLocation);
0077 
0078     /**
0079      * Check if the just stopped server for given repository was
0080      * exited successfully.
0081      *
0082      * @param repoLocation Path to repository
0083      * @return true if exitCode == 0 and exitStatus == Normal, otherwise false
0084      */
0085     bool normalExit(const QString &repoLocation);
0086 
0087 Q_SIGNALS:
0088     // These signals are emitted for every ServerProcessType in list. Its upto
0089     // the owner of this wrapper to decide which server was updated. If any of
0090     // these signals are emitted cleanUnused() is called and every initiater
0091     // of server should check status and act according.
0092     void finished();
0093     void error();
0094     void started();
0095     void readyReadLine(const QString &repoLocation, const QString &line);
0096 
0097 private:
0098 
0099 private Q_SLOTS:
0100     void slotFinished(int exitCode, QProcess::ExitStatus status);
0101 
0102 private:
0103     QHash<QString, ServerProcessType*> m_serverList;
0104     static HgServeWrapper *m_instance;
0105 };
0106 
0107 //FIXME: Had to change struct to class and make it unnested. 
0108 // Hide member variables.
0109 
0110 /**
0111  * Represents a Mercurial Server instance. 
0112  */
0113 class ServerProcessType : public QObject {
0114     Q_OBJECT
0115 
0116 public:
0117     QProcess process;
0118     int port;
0119 
0120     ServerProcessType() 
0121     {
0122         connect(&process, &QProcess::readyReadStandardOutput,
0123                 this, &ServerProcessType::slotAppendOutput);
0124         connect(&process, &QProcess::readyReadStandardError,
0125                 this, &ServerProcessType::slotAppendRemainingOutput);
0126         connect(&process, &QProcess::finished,
0127                 this, &ServerProcessType::slotFinished);
0128     }
0129 
0130 Q_SIGNALS:    
0131     void readyReadLine(const QString &repoLocation, const QString &line);
0132 
0133 private Q_SLOTS:
0134     void slotAppendOutput() 
0135     {
0136         if (process.canReadLine()) {
0137             Q_EMIT readyReadLine(process.workingDirectory(),
0138                 QTextCodec::codecForLocale()->toUnicode(process.readAllStandardOutput()).trimmed());
0139         }
0140     }
0141 
0142     void slotAppendRemainingOutput() 
0143     {
0144             Q_EMIT readyReadLine(process.workingDirectory(),
0145                 QTextCodec::codecForLocale()->toUnicode(process.readAllStandardError()).trimmed());
0146     }
0147 
0148     void slotFinished() 
0149     {
0150         Q_EMIT readyReadLine(process.workingDirectory(),
0151                                i18n("## Server Stopped! ##\n"));
0152     }
0153 };
0154 
0155 #endif /* HG_SERVE_WRAPPER_H */
0156 
0157