2016-03-18 16:07:39 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <Poco/Net/HTMLForm.h>
|
|
|
|
#include <Poco/Net/HTTPClientSession.h>
|
2016-04-14 13:32:56 -05:00
|
|
|
#include <Poco/Net/HTTPSClientSession.h>
|
2016-03-18 16:07:39 -05:00
|
|
|
#include <Poco/Net/HTTPRequest.h>
|
|
|
|
#include <Poco/Net/HTTPResponse.h>
|
|
|
|
#include <Poco/Net/FilePartSource.h>
|
2016-04-14 13:32:56 -05:00
|
|
|
#include <Poco/Net/SSLManager.h>
|
|
|
|
#include <Poco/Net/KeyConsoleHandler.h>
|
|
|
|
#include <Poco/Net/AcceptCertificateHandler.h>
|
2016-03-18 16:07:39 -05:00
|
|
|
#include <Poco/StreamCopier.h>
|
|
|
|
#include <Poco/Thread.h>
|
|
|
|
#include <Poco/URI.h>
|
|
|
|
#include <Poco/Util/Application.h>
|
|
|
|
#include <Poco/Util/HelpFormatter.h>
|
|
|
|
#include <Poco/Util/Option.h>
|
|
|
|
#include <Poco/Util/OptionSet.h>
|
|
|
|
|
|
|
|
#include "Common.hpp"
|
2016-11-24 08:56:06 -06:00
|
|
|
#include "Protocol.hpp"
|
2016-03-18 16:07:39 -05:00
|
|
|
#include "Util.hpp"
|
|
|
|
|
2016-08-13 23:01:13 -05:00
|
|
|
/// Simple command-line tool for file format conversion.
|
2016-03-18 16:07:39 -05:00
|
|
|
class Tool: public Poco::Util::Application
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Tool();
|
|
|
|
|
|
|
|
unsigned _numWorkers;
|
|
|
|
std::string _serverURI;
|
|
|
|
std::string _destinationFormat;
|
2016-04-14 15:41:09 -05:00
|
|
|
std::string _destinationDir;
|
2016-03-18 16:07:39 -05:00
|
|
|
|
|
|
|
protected:
|
|
|
|
void defineOptions(Poco::Util::OptionSet& options) override;
|
|
|
|
void handleOption(const std::string& name, const std::string& value) override;
|
|
|
|
int main(const std::vector<std::string>& args) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
using namespace LOOLProtocol;
|
|
|
|
|
|
|
|
using Poco::Net::HTTPClientSession;
|
|
|
|
using Poco::Net::HTTPRequest;
|
|
|
|
using Poco::Net::HTTPResponse;
|
|
|
|
using Poco::Runnable;
|
|
|
|
using Poco::Thread;
|
|
|
|
using Poco::URI;
|
|
|
|
using Poco::Util::Application;
|
|
|
|
using Poco::Util::HelpFormatter;
|
|
|
|
using Poco::Util::Option;
|
|
|
|
using Poco::Util::OptionSet;
|
|
|
|
|
2016-08-13 23:01:13 -05:00
|
|
|
/// Thread class which performs the conversion.
|
2016-03-18 16:07:39 -05:00
|
|
|
class Worker: public Runnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Tool& _app;
|
|
|
|
std::vector< std::string > _files;
|
|
|
|
Worker(Tool& app, const std::vector< std::string > & files) :
|
|
|
|
_app(app), _files(files)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void run() override
|
|
|
|
{
|
2016-04-27 07:58:33 -05:00
|
|
|
for (const auto& i : _files)
|
2016-03-18 16:07:39 -05:00
|
|
|
convertFile(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
void convertFile(const std::string& document)
|
|
|
|
{
|
|
|
|
std::cerr << "convert file " << document << "\n";
|
|
|
|
|
|
|
|
Poco::URI uri(_app._serverURI);
|
2016-04-14 13:32:56 -05:00
|
|
|
|
|
|
|
Poco::Net::HTTPClientSession *session;
|
|
|
|
if (_app._serverURI.compare(0, 5, "https"))
|
|
|
|
session = new Poco::Net::HTTPSClientSession(uri.getHost(), uri.getPort());
|
|
|
|
else
|
|
|
|
session = new Poco::Net::HTTPClientSession(uri.getHost(), uri.getPort());
|
|
|
|
|
2016-03-18 16:07:39 -05:00
|
|
|
Poco::Net::HTTPRequest request(Poco::Net::HTTPRequest::HTTP_POST, "/convert-to");
|
|
|
|
|
|
|
|
try {
|
|
|
|
Poco::Net::HTMLForm form;
|
|
|
|
form.setEncoding(Poco::Net::HTMLForm::ENCODING_MULTIPART);
|
|
|
|
form.set("format", _app._destinationFormat);
|
|
|
|
form.addPart("data", new Poco::Net::FilePartSource(document));
|
|
|
|
form.prepareSubmit(request);
|
|
|
|
|
|
|
|
// If this results in a Poco::Net::ConnectionRefusedException, loolwsd is not running.
|
2016-04-14 13:32:56 -05:00
|
|
|
form.write(session->sendRequest(request));
|
2016-03-18 16:07:39 -05:00
|
|
|
}
|
|
|
|
catch (const Poco::Exception &e)
|
|
|
|
{
|
2016-04-14 13:32:56 -05:00
|
|
|
std::cerr << "Failed to write data: " << e.name() <<
|
2016-03-18 16:07:39 -05:00
|
|
|
" " << e.message() << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Poco::Net::HTTPResponse response;
|
2016-04-14 13:32:56 -05:00
|
|
|
|
|
|
|
try {
|
|
|
|
std::cerr << "try to get response\n";
|
|
|
|
|
|
|
|
// receiveResponse() resulted in a Poco::Net::NoMessageException.
|
|
|
|
std::istream& responseStream = session->receiveResponse(response);
|
|
|
|
|
|
|
|
std::cerr << "Get response\n";
|
|
|
|
|
|
|
|
Poco::Path path(document);
|
2016-04-14 15:41:09 -05:00
|
|
|
std::string outPath = _app._destinationDir + "/" + path.getBaseName() + "." + _app._destinationFormat;
|
2016-04-14 13:32:56 -05:00
|
|
|
std::ofstream fileStream(outPath);
|
|
|
|
|
|
|
|
std::cerr << "write to " << outPath << "\n";
|
|
|
|
|
|
|
|
Poco::StreamCopier::copyStream(responseStream, fileStream);
|
|
|
|
|
|
|
|
std::cerr << "Copied stream\n";
|
|
|
|
}
|
|
|
|
catch (const Poco::Exception &e)
|
|
|
|
{
|
|
|
|
std::cerr << "Exception converting: " << e.name() <<
|
|
|
|
" " << e.message() << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete session;
|
2016-03-18 16:07:39 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
Tool::Tool() :
|
|
|
|
_numWorkers(4),
|
|
|
|
#if ENABLE_SSL
|
2016-04-14 13:32:56 -05:00
|
|
|
_serverURI("https://127.0.0.1:" + std::to_string(DEFAULT_CLIENT_PORT_NUMBER)),
|
2016-03-18 16:07:39 -05:00
|
|
|
#else
|
2016-04-14 13:32:56 -05:00
|
|
|
_serverURI("http://127.0.0.1:" + std::to_string(DEFAULT_CLIENT_PORT_NUMBER)),
|
2016-03-18 16:07:39 -05:00
|
|
|
#endif
|
|
|
|
_destinationFormat("txt")
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void Tool::defineOptions(OptionSet& optionSet)
|
|
|
|
{
|
|
|
|
Application::defineOptions(optionSet);
|
|
|
|
|
|
|
|
optionSet.addOption(Option("help", "", "Display help information on command line arguments.")
|
|
|
|
.required(false).repeatable(false));
|
|
|
|
optionSet.addOption(Option("extension", "", "file format extension to convert to")
|
|
|
|
.required(false).repeatable(false)
|
|
|
|
.argument("format"));
|
|
|
|
optionSet.addOption(Option("outdir", "", "output directory for converted files")
|
2016-04-14 13:32:56 -05:00
|
|
|
.required(false).repeatable(false).argument("outdir"));
|
2016-03-18 16:07:39 -05:00
|
|
|
optionSet.addOption(Option("parallelism", "", "number of simultaneous threads to use")
|
2016-04-14 15:41:09 -05:00
|
|
|
.required(false).repeatable(false)
|
2016-03-18 16:07:39 -05:00
|
|
|
.argument("threads"));
|
|
|
|
optionSet.addOption(Option("server", "", "URI of LOOL server")
|
|
|
|
.required(false).repeatable(false)
|
|
|
|
.argument("uri"));
|
2016-04-14 13:32:56 -05:00
|
|
|
optionSet.addOption(Option("no-check-certificate", "", "Disable checking of SSL certs")
|
|
|
|
.required(false).repeatable(false));
|
2016-03-18 16:07:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void Tool::handleOption(const std::string& optionName,
|
2016-04-14 15:41:09 -05:00
|
|
|
const std::string& value)
|
2016-03-18 16:07:39 -05:00
|
|
|
{
|
|
|
|
Application::handleOption(optionName, value);
|
|
|
|
|
|
|
|
if (optionName == "help")
|
|
|
|
{
|
|
|
|
HelpFormatter helpFormatter(options());
|
|
|
|
|
|
|
|
helpFormatter.setCommand(commandName());
|
|
|
|
helpFormatter.setUsage("OPTIONS");
|
|
|
|
helpFormatter.setHeader("LibreOffice On-Line tool.");
|
|
|
|
helpFormatter.format(std::cout);
|
|
|
|
std::exit(Application::EXIT_OK);
|
|
|
|
}
|
2016-04-14 15:41:09 -05:00
|
|
|
else if (optionName == "extension")
|
2016-03-18 16:07:39 -05:00
|
|
|
_destinationFormat = value;
|
|
|
|
else if (optionName == "outdir")
|
|
|
|
_destinationDir = value;
|
2016-04-14 15:41:09 -05:00
|
|
|
else if (optionName == "parallelism")
|
|
|
|
_numWorkers = std::max(std::stoi(value), 1);
|
2016-03-18 16:07:39 -05:00
|
|
|
else if (optionName == "uri")
|
|
|
|
_serverURI = value;
|
2016-04-14 13:32:56 -05:00
|
|
|
else if (optionName == "no-check-certificate")
|
|
|
|
{
|
|
|
|
Poco::SharedPtr<Poco::Net::PrivateKeyPassphraseHandler> consoleClientHandler = new Poco::Net::KeyConsoleHandler(false);
|
|
|
|
Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> invalidClientCertHandler = new Poco::Net::AcceptCertificateHandler(false);
|
|
|
|
Poco::Net::Context::Ptr sslClientContext = new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "");
|
|
|
|
Poco::Net::SSLManager::instance().initializeClient(consoleClientHandler, invalidClientCertHandler, sslClientContext);
|
|
|
|
}
|
2016-03-18 16:07:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int Tool::main(const std::vector<std::string>& args)
|
|
|
|
{
|
2016-04-21 01:37:21 -05:00
|
|
|
std::vector<std::unique_ptr<Thread>> clients(_numWorkers);
|
2016-03-18 16:07:39 -05:00
|
|
|
|
|
|
|
size_t chunk = (args.size() + _numWorkers - 1) / _numWorkers;
|
|
|
|
size_t offset = 0;
|
|
|
|
for (unsigned i = 0; i < _numWorkers; i++)
|
|
|
|
{
|
2016-04-21 01:37:21 -05:00
|
|
|
clients[i].reset(new Thread());
|
2016-03-18 16:07:39 -05:00
|
|
|
size_t toCopy = std::min(args.size() - offset, chunk);
|
|
|
|
if (toCopy > 0)
|
|
|
|
{
|
|
|
|
std::vector< std::string > files( toCopy );
|
2016-04-15 07:55:34 -05:00
|
|
|
std::copy( args.begin() + offset, args.begin() + offset + toCopy, files.begin() );
|
2016-03-18 16:07:39 -05:00
|
|
|
offset += toCopy;
|
|
|
|
clients[i]->start(*(new Worker(*this, files)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < _numWorkers; i++)
|
|
|
|
{
|
|
|
|
clients[i]->join();
|
|
|
|
}
|
|
|
|
|
|
|
|
return Application::EXIT_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
POCO_APP_MAIN(Tool)
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|