annotate vamp-client/ProcessQtTransport.h @ 106:a0edd7c97d2d

Add generated files -- they aren't supposed to change (much?) I think and it's better than expecting the compiler to be present on every platform
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 17 Oct 2016 18:56:18 +0100
parents 8c449824e08d
children 247d8d533a9c
rev   line source
c@94 1
c@94 2 #ifndef PIPER_PROCESS_QT_TRANSPORT_H
c@94 3 #define PIPER_PROCESS_QT_TRANSPORT_H
c@94 4
c@94 5 #include "SynchronousTransport.h"
c@94 6
c@94 7 #include <QProcess>
c@94 8 #include <QString>
c@100 9 #include <QMutex>
c@94 10
c@94 11 #include <iostream>
c@94 12
c@97 13 namespace piper_vamp {
c@97 14 namespace client {
c@94 15
c@100 16 /**
c@100 17 * A SynchronousTransport implementation that spawns a sub-process
c@100 18 * using Qt's QProcess abstraction and talks to it via stdin/stdout
c@100 19 * channels. Calls are completely serialized; the protocol only
c@100 20 * supports one call in process at a time, and therefore the transport
c@100 21 * only allows one at a time. This class is thread-safe because it
c@100 22 * serializes explicitly using a mutex.
c@100 23 */
c@94 24 class ProcessQtTransport : public SynchronousTransport
c@94 25 {
c@94 26 public:
c@101 27 ProcessQtTransport(std::string processName) :
c@94 28 m_completenessChecker(0) {
c@94 29 m_process = new QProcess();
c@94 30 m_process->setReadChannel(QProcess::StandardOutput);
c@94 31 m_process->setProcessChannelMode(QProcess::ForwardedErrorChannel);
c@101 32 m_process->start(QString::fromStdString(processName));
c@94 33 if (!m_process->waitForStarted()) {
c@94 34 std::cerr << "server failed to start" << std::endl;
c@94 35 delete m_process;
c@94 36 m_process = nullptr;
c@94 37 }
c@94 38 }
c@94 39
c@94 40 ~ProcessQtTransport() {
c@94 41 if (m_process) {
c@94 42 if (m_process->state() != QProcess::NotRunning) {
c@94 43 m_process->closeWriteChannel();
c@94 44 m_process->waitForFinished(200);
c@94 45 m_process->close();
c@94 46 m_process->waitForFinished();
c@94 47 std::cerr << "server exited" << std::endl;
c@94 48 }
c@94 49 delete m_process;
c@94 50 }
c@94 51 }
c@94 52
c@94 53 void
c@94 54 setCompletenessChecker(MessageCompletenessChecker *checker) {
c@94 55 //!!! ownership?
c@94 56 m_completenessChecker = checker;
c@94 57 }
c@94 58
c@94 59 bool
c@94 60 isOK() const override {
c@94 61 return m_process != nullptr;
c@94 62 }
c@94 63
c@94 64 std::vector<char>
c@94 65 call(const char *ptr, size_t size) override {
c@94 66
c@100 67 QMutexLocker locker(&m_mutex);
c@100 68
c@94 69 if (!m_completenessChecker) {
c@94 70 throw std::logic_error("No completeness checker set on transport");
c@94 71 }
c@94 72
c@94 73 m_process->write(ptr, size);
c@94 74
c@94 75 std::vector<char> buffer;
c@94 76 bool complete = false;
c@94 77
c@94 78 while (!complete) {
c@94 79
c@94 80 qint64 byteCount = m_process->bytesAvailable();
c@94 81
c@101 82 if (!byteCount) {
c@101 83 std::cerr << "waiting for data from server..." << endl;
c@101 84 m_process->waitForReadyRead(1000);
c@94 85 if (m_process->state() == QProcess::NotRunning) {
c@94 86 std::cerr << "ERROR: Subprocess exited: Load failed" << std::endl;
c@94 87 throw std::runtime_error("Piper server exited unexpectedly");
c@94 88 }
c@94 89 } else {
c@94 90 size_t formerSize = buffer.size();
c@94 91 buffer.resize(formerSize + byteCount);
c@94 92 m_process->read(buffer.data() + formerSize, byteCount);
c@94 93 complete = m_completenessChecker->isComplete(buffer);
c@94 94 }
c@94 95 }
c@94 96
c@94 97 return buffer;
c@94 98 }
c@94 99
c@94 100 private:
c@94 101 MessageCompletenessChecker *m_completenessChecker; //!!! I don't own this (currently)
c@94 102 QProcess *m_process; // I own this
c@100 103 QMutex m_mutex;
c@94 104 };
c@94 105
c@94 106 }
c@94 107 }
c@94 108
c@94 109 #endif