c@31: c@31: #include "VampnProto.h" c@31: c@31: #include "bits/RequestOrResponse.h" c@31: c@31: #include c@31: #include c@31: #include c@31: c@32: #include c@32: #include c@32: c@31: using namespace std; c@31: using namespace vampipe; c@32: using namespace Vamp; c@32: using namespace Vamp::HostExt; c@31: c@31: void usage() c@31: { c@31: string myname = "vampipe-server"; c@31: cerr << "\n" << myname << c@31: ": Load and run Vamp plugins in response to messages from stdin\n\n" c@31: " Usage: " << myname << "\n\n" c@31: "Expects Vamp request messages in Cap'n Proto packed format on stdin,\n" c@31: "and writes Vamp response messages in the same format to stdout.\n\n"; c@31: c@31: exit(2); c@31: } c@31: c@32: class Mapper : public PluginHandleMapper c@32: { c@32: public: c@32: Mapper() : m_nextHandle(1) { } c@32: c@32: void addPlugin(Plugin *p) { c@32: if (m_rplugins.find(p) == m_rplugins.end()) { c@32: int32_t h = m_nextHandle++; c@32: m_plugins[h] = p; c@32: m_rplugins[p] = h; c@32: } c@32: } c@32: c@32: int32_t pluginToHandle(Plugin *p) { c@32: if (m_rplugins.find(p) == m_rplugins.end()) { c@32: throw NotFound(); c@32: } c@32: return m_rplugins[p]; c@32: } c@32: c@32: Plugin *handleToPlugin(int32_t h) { c@32: if (m_plugins.find(h) == m_plugins.end()) { c@32: throw NotFound(); c@32: } c@32: return m_plugins[h]; c@32: } c@32: c@32: bool isInitialised(int32_t h) { c@32: return m_initialisedPlugins.find(h) != m_initialisedPlugins.end(); c@32: } c@32: c@32: void markInitialised(int32_t h) { c@32: m_initialisedPlugins.insert(h); c@32: } c@32: c@32: private: c@32: int32_t m_nextHandle; // NB plugin handle type must fit in JSON number c@32: map m_plugins; c@32: map m_rplugins; c@32: set m_initialisedPlugins; c@32: }; c@32: c@32: static Mapper mapper; c@32: c@31: RequestOrResponse c@31: readRequestCapnp() c@31: { c@31: RequestOrResponse rr; c@31: rr.direction = RequestOrResponse::Request; c@31: c@31: ::capnp::PackedFdMessageReader message(0); // stdin c@31: VampRequest::Reader reader = message.getRoot(); c@31: c@31: rr.type = VampnProto::getRequestResponseType(reader); c@31: c@31: switch (rr.type) { c@31: c@31: case RRType::List: c@31: VampnProto::readVampRequest_List(reader); // type check only c@31: break; c@31: case RRType::Load: c@31: VampnProto::readVampRequest_Load(rr.loadRequest, reader); c@31: break; c@31: case RRType::Configure: c@32: VampnProto::readVampRequest_Configure(rr.configurationRequest, c@32: reader, mapper); c@31: break; c@31: case RRType::Process: c@32: VampnProto::readVampRequest_Process(rr.processRequest, reader, mapper); c@31: break; c@31: case RRType::Finish: c@32: VampnProto::readVampRequest_Finish(rr.finishPlugin, reader, mapper); c@31: break; c@31: case RRType::NotValid: c@31: break; c@31: } c@31: c@31: return rr; c@31: } c@31: c@31: void c@31: writeResponseCapnp(RequestOrResponse &rr) c@31: { c@31: ::capnp::MallocMessageBuilder message; c@31: VampResponse::Builder builder = message.initRoot(); c@31: c@31: switch (rr.type) { c@31: c@31: case RRType::List: c@31: VampnProto::buildVampResponse_List(builder, "", rr.listResponse); c@31: break; c@31: case RRType::Load: c@32: VampnProto::buildVampResponse_Load(builder, rr.loadResponse, mapper); c@31: break; c@31: case RRType::Configure: c@31: VampnProto::buildVampResponse_Configure(builder, rr.configurationResponse); c@31: break; c@31: case RRType::Process: c@31: VampnProto::buildVampResponse_Process(builder, rr.processResponse); c@31: break; c@31: case RRType::Finish: c@31: VampnProto::buildVampResponse_Finish(builder, rr.finishResponse); c@31: break; c@31: case RRType::NotValid: c@31: break; c@31: } c@31: c@31: writePackedMessageToFd(1, message); c@31: } c@31: c@31: RequestOrResponse c@31: processRequest(const RequestOrResponse &request) c@31: { c@31: RequestOrResponse response; c@31: response.direction = RequestOrResponse::Response; c@32: response.type = request.type; c@32: c@32: auto loader = PluginLoader::getInstance(); c@32: c@32: switch (request.type) { c@32: c@32: case RRType::List: c@32: response.listResponse = loader->listPluginData(); c@32: response.success = true; c@32: break; c@32: c@32: case RRType::Load: c@32: response.loadResponse = loader->loadPlugin(request.loadRequest); c@32: if (response.loadResponse.plugin != nullptr) { c@32: mapper.addPlugin(response.loadResponse.plugin); c@32: response.success = true; c@32: } c@32: break; c@32: c@32: default: c@32: //!!! c@32: ; c@32: } c@32: c@31: return response; c@31: } c@31: c@31: int main(int argc, char **argv) c@31: { c@31: if (argc != 1) { c@31: usage(); c@31: } c@31: c@31: while (true) { c@31: c@31: try { c@31: c@31: RequestOrResponse request = readRequestCapnp(); c@31: c@31: // NotValid without an exception indicates EOF: c@31: c@31: //!!! not yet it doesn't -- have to figure out how to c@31: //!!! handle this with capnp c@31: if (request.type == RRType::NotValid) break; c@31: c@31: RequestOrResponse response = processRequest(request); c@31: c@31: writeResponseCapnp(response); c@31: c@31: } catch (std::exception &e) { c@31: cerr << "Error: " << e.what() << endl; c@31: exit(1); c@31: } c@31: } c@31: c@31: exit(0); c@31: }