<commit_before>// Copyright (c) 2015, Galaxy Authors. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: wangtaize@baidu.com

#include "agent/task_manager.h"

#include "common/logging.h"
#include "agent/cgroup.h"

extern std::string FLAGS_container;
namespace galaxy {
int TaskManager::Add(const ::galaxy::TaskInfo& task_info,
                     DefaultWorkspace *  workspace) {
    MutexLock lock(m_mutex);
    LOG(INFO, "add task with id %d", task_info.task_id());
    if (m_task_runner_map.find(task_info.task_id()) != m_task_runner_map.end()) {
        LOG(WARNING, "task with id %d has exist", task_info.task_id());
        return 0;
    }
    // do download

    TaskRunner* runner = NULL;
    if(FLAGS_container.compare("cgroup") == 0){
        LOG(INFO,"use cgroup task runner for task %d",task_info.task_id());
        runner = new ContainerTaskRunner(task_info,"/cgroup", workspace);
    }else{
        LOG(INFO,"use command task runner for task %d",task_info.task_id());
        runner = new CommandTaskRunner(task_info,workspace);
    }
    int ret = runner->Prepare();
    if(ret != 0 ){
        LOG(INFO,"fail to prepare runner ,ret is %d",ret);
        return ret;
    }
    m_task_runner_map[task_info.task_id()] = runner;
    //ret = runner->Start();
    //if (ret == 0) {
    //    LOG(INFO, "add task with id %d successfully", task_info.task_id());
    //    m_task_runner_map[task_info.task_id()] = runner;
    //} else {
    //    LOG(FATAL, "fail to add task with %d", task_info.task_id());
    //}
    return ret;
}

int TaskManager::Remove(const int64_t& task_info_id) {
    MutexLock lock(m_mutex);
    if (m_task_runner_map.find(task_info_id) == m_task_runner_map.end()) {
        LOG(WARNING, "task with id %d does not exist", task_info_id);
        return 0;
    }
    TaskRunner* runner = m_task_runner_map[task_info_id];
    if(NULL == runner){
        return 0;
    }
    int status = runner->Stop();
    if(status == 0){
        LOG(INFO,"stop task %d successfully",task_info_id);
    }
    m_task_runner_map.erase(task_info_id);
    delete runner;
    return status;
}

int TaskManager::Status(std::vector< TaskStatus >& task_status_vector) {
    std::map<int64_t, TaskRunner*>::iterator it = m_task_runner_map.begin();
    for (; it != m_task_runner_map.end(); ++it) {
        TaskStatus status;
        status.set_task_id(it->first);
        int ret = it->second->IsRunning();
        if(ret == 0){
            status.set_status(RUNNING);
        }else if(ret == 1){
            status.set_status(COMPLETE);
            Remove(it->first);
        }else{
            if (it->second->ReStart() == 0) {
                status.set_status(RESTART);
            } else {
                // if restart failed,
                // 1. retry times more than limit, no need retry any more.
                // 2. stop failed
                // 3. start failed
                status.set_status(ERROR);
            }
        }

        task_status_vector.push_back(status);
    }
    return 0;
}
}

<commit_msg>add mutex when check task status<commit_after>// Copyright (c) 2015, Galaxy Authors. All Rights Reserved
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Author: wangtaize@baidu.com

#include "agent/task_manager.h"

#include "common/logging.h"
#include "agent/cgroup.h"

extern std::string FLAGS_container;
namespace galaxy {
int TaskManager::Add(const ::galaxy::TaskInfo& task_info,
                     DefaultWorkspace *  workspace) {
    MutexLock lock(m_mutex);
    LOG(INFO, "add task with id %d", task_info.task_id());
    if (m_task_runner_map.find(task_info.task_id()) != m_task_runner_map.end()) {
        LOG(WARNING, "task with id %d has exist", task_info.task_id());
        return 0;
    }
    // do download

    TaskRunner* runner = NULL;
    if(FLAGS_container.compare("cgroup") == 0){
        LOG(INFO,"use cgroup task runner for task %d",task_info.task_id());
        runner = new ContainerTaskRunner(task_info,"/cgroup", workspace);
    }else{
        LOG(INFO,"use command task runner for task %d",task_info.task_id());
        runner = new CommandTaskRunner(task_info,workspace);
    }
    int ret = runner->Prepare();
    if(ret != 0 ){
        LOG(INFO,"fail to prepare runner ,ret is %d",ret);
        return ret;
    }
    m_task_runner_map[task_info.task_id()] = runner;
    //ret = runner->Start();
    //if (ret == 0) {
    //    LOG(INFO, "add task with id %d successfully", task_info.task_id());
    //    m_task_runner_map[task_info.task_id()] = runner;
    //} else {
    //    LOG(FATAL, "fail to add task with %d", task_info.task_id());
    //}
    return ret;
}

int TaskManager::Remove(const int64_t& task_info_id) {
    MutexLock lock(m_mutex);
    if (m_task_runner_map.find(task_info_id) == m_task_runner_map.end()) {
        LOG(WARNING, "task with id %d does not exist", task_info_id);
        return 0;
    }
    TaskRunner* runner = m_task_runner_map[task_info_id];
    if(NULL == runner){
        return 0;
    }
    int status = runner->Stop();
    if(status == 0){
        LOG(INFO,"stop task %d successfully",task_info_id);
    }
    m_task_runner_map.erase(task_info_id);
    delete runner;
    return status;
}

int TaskManager::Status(std::vector< TaskStatus >& task_status_vector) {
    MutexLock lock(m_mutex);
    std::map<int64_t, TaskRunner*>::iterator it = m_task_runner_map.begin();
    for (; it != m_task_runner_map.end(); ++it) {
        TaskStatus status;
        status.set_task_id(it->first);
        int ret = it->second->IsRunning();
        if(ret == 0){
            status.set_status(RUNNING);
        }else if(ret == 1){
            status.set_status(COMPLETE);
            Remove(it->first);
        }else{
            if (it->second->ReStart() == 0) {
                status.set_status(RESTART);
            } else {
                // if restart failed,
                // 1. retry times more than limit, no need retry any more.
                // 2. stop failed
                // 3. start failed
                status.set_status(ERROR);
            }
        }

        task_status_vector.push_back(status);
    }
    return 0;
}
}

<|endoftext|>


<commit_before>#ifndef EVEREST_TYPES_HPP_
#define EVEREST_TYPES_HPP_

#include <http_parser.h>
#include <list>
#include <functional>

namespace everest {

/// Log level used in the logging callback
enum class LogLevel : int {
	TRACE,
	DEBUG,
	INFO,
	WARN,
	ERROR,
};

typedef std::function<void(LogLevel, const std::string& message)> LogCallback;

typedef ::http_method HTTPMethod;

typedef std::list<std::pair<std::string, std::string>> headers_t;

} // namespace everest

#endif // EVEREST_TYPES_HPP_<commit_msg>Copied HTTP Method enum<commit_after>#ifndef EVEREST_TYPES_HPP_
#define EVEREST_TYPES_HPP_

#include <list>
#include <functional>

namespace everest {

/// Log level used in the logging callback
enum class LogLevel : int {
	TRACE,
	DEBUG,
	INFO,
	WARN,
	ERROR,
};

typedef std::function<void(LogLevel, const std::string& message)> LogCallback;

typedef std::list<std::pair<std::string, std::string>> headers_t;

// Copied from http-parser
#define HTTP_METHOD_MAP(XX)         \
  XX(0,  DELETE,      DELETE)       \
  XX(1,  GET,         GET)          \
  XX(2,  HEAD,        HEAD)         \
  XX(3,  POST,        POST)         \
  XX(4,  PUT,         PUT)          \
  /* pathological */                \
  XX(5,  CONNECT,     CONNECT)      \
  XX(6,  OPTIONS,     OPTIONS)      \
  XX(7,  TRACE,       TRACE)        \
  /* WebDAV */                      \
  XX(8,  COPY,        COPY)         \
  XX(9,  LOCK,        LOCK)         \
  XX(10, MKCOL,       MKCOL)        \
  XX(11, MOVE,        MOVE)         \
  XX(12, PROPFIND,    PROPFIND)     \
  XX(13, PROPPATCH,   PROPPATCH)    \
  XX(14, SEARCH,      SEARCH)       \
  XX(15, UNLOCK,      UNLOCK)       \
  XX(16, BIND,        BIND)         \
  XX(17, REBIND,      REBIND)       \
  XX(18, UNBIND,      UNBIND)       \
  XX(19, ACL,         ACL)          \
  /* subversion */                  \
  XX(20, REPORT,      REPORT)       \
  XX(21, MKACTIVITY,  MKACTIVITY)   \
  XX(22, CHECKOUT,    CHECKOUT)     \
  XX(23, MERGE,       MERGE)        \
  /* upnp */                        \
  XX(24, MSEARCH,     M-SEARCH)     \
  XX(25, NOTIFY,      NOTIFY)       \
  XX(26, SUBSCRIBE,   SUBSCRIBE)    \
  XX(27, UNSUBSCRIBE, UNSUBSCRIBE)  \
  /* RFC-5789 */                    \
  XX(28, PATCH,       PATCH)        \
  XX(29, PURGE,       PURGE)        \
  /* CalDAV */                      \
  XX(30, MKCALENDAR,  MKCALENDAR)   \
  /* RFC-2068, section 19.6.1.2 */  \
  XX(31, LINK,        LINK)         \
  XX(32, UNLINK,      UNLINK)       \

enum HTTPMethod {
#define XX(num, name, string) HTTP_##name = num,
	HTTP_METHOD_MAP(XX)
#undef XX
};

} // namespace everest

#endif // EVEREST_TYPES_HPP_<|endoftext|>


<commit_before>#include <string>
#include <map>
#include "Config.h"
#include "Log.h"
#include "NetDb.hpp"
#include "Transports.h"
#include "Tunnel.h"
#include "RouterContext.h"
#include "Identity.h"
#include "Destination.h"
#include "Crypto.h"
#include "FS.h"
#include "api.h"

namespace i2p
{
namespace api
{
	void InitI2P (int argc, char* argv[], const char * appName)
	{
		i2p::config::Init ();
		i2p::config::ParseCmdline (argc, argv, true); // ignore unknown options and help
		i2p::config::Finalize ();

		std::string datadir; i2p::config::GetOption("datadir", datadir);

		i2p::fs::SetAppName (appName);
		i2p::fs::DetectDataDir(datadir, false);
		i2p::fs::Init();

#if defined(__x86_64__)
		i2p::crypto::InitCrypto (false);
#else
		i2p::crypto::InitCrypto (true);
#endif

                int netID; i2p::config::GetOption("netid", netID);
                i2p::context.SetNetID (netID);

		i2p::context.Init ();
	}

	void TerminateI2P ()
	{
		i2p::crypto::TerminateCrypto ();
	}

	void StartI2P (std::shared_ptr<std::ostream> logStream)
	{
		if (logStream)
			i2p::log::Logger().SendTo (logStream);
		else
			i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
		i2p::log::Logger().Start ();
		LogPrint(eLogInfo, "API: starting NetDB");
		i2p::data::netdb.Start();
		LogPrint(eLogInfo, "API: starting Transports");
		i2p::transport::transports.Start();
		LogPrint(eLogInfo, "API: starting Tunnels");
		i2p::tunnel::tunnels.Start();
	}

	void StopI2P ()
	{
		LogPrint(eLogInfo, "API: shutting down");
		LogPrint(eLogInfo, "API: stopping Tunnels");
		i2p::tunnel::tunnels.Stop();
		LogPrint(eLogInfo, "API: stopping Transports");
		i2p::transport::transports.Stop();
		LogPrint(eLogInfo, "API: stopping NetDB");
		i2p::data::netdb.Stop();
		i2p::log::Logger().Stop ();
	}

	void RunPeerTest ()
	{
		i2p::transport::transports.PeerTest ();
	}

	std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
		const std::map<std::string, std::string> * params)
	{
		auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
		localDestination->Start ();
		return localDestination;
	}

	std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
		const std::map<std::string, std::string> * params)
	{
		i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
		auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
		localDestination->Start ();
		return localDestination;
	}

	void DestroyLocalDestination (std::shared_ptr<i2p::client::ClientDestination> dest)
	{
		if (dest)
			dest->Stop ();
	}

	void RequestLeaseSet (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::data::IdentHash& remote)
	{
		if (dest)
			dest->RequestDestination (remote);
	}

	std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::data::IdentHash& remote)
	{
		if (!dest) return nullptr;
		auto leaseSet = dest->FindLeaseSet (remote);
		if (leaseSet)
		{
			auto stream = dest->CreateStream (leaseSet);
			stream->Send (nullptr, 0); // connect
			return stream;
		}
		else
		{
			RequestLeaseSet (dest, remote);
			return nullptr;
		}
	}

	void AcceptStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
	{
		if (dest)
			dest->AcceptStreams (acceptor);
	}

	void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
	{
		if (stream)
			stream->Close ();
	}
}
}

<commit_msg>take elgamal percomputation from config<commit_after>#include <string>
#include <map>
#include "Config.h"
#include "Log.h"
#include "NetDb.hpp"
#include "Transports.h"
#include "Tunnel.h"
#include "RouterContext.h"
#include "Identity.h"
#include "Destination.h"
#include "Crypto.h"
#include "FS.h"
#include "api.h"

namespace i2p
{
namespace api
{
	void InitI2P (int argc, char* argv[], const char * appName)
	{
		i2p::config::Init ();
		i2p::config::ParseCmdline (argc, argv, true); // ignore unknown options and help
		i2p::config::Finalize ();

		std::string datadir; i2p::config::GetOption("datadir", datadir);

		i2p::fs::SetAppName (appName);
		i2p::fs::DetectDataDir(datadir, false);
		i2p::fs::Init();

		bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
		i2p::crypto::InitCrypto (precomputation);

        int netID; i2p::config::GetOption("netid", netID);
        i2p::context.SetNetID (netID);

		i2p::context.Init ();
	}

	void TerminateI2P ()
	{
		i2p::crypto::TerminateCrypto ();
	}

	void StartI2P (std::shared_ptr<std::ostream> logStream)
	{
		if (logStream)
			i2p::log::Logger().SendTo (logStream);
		else
			i2p::log::Logger().SendTo (i2p::fs::DataDirPath (i2p::fs::GetAppName () + ".log"));
		i2p::log::Logger().Start ();
		LogPrint(eLogInfo, "API: starting NetDB");
		i2p::data::netdb.Start();
		LogPrint(eLogInfo, "API: starting Transports");
		i2p::transport::transports.Start();
		LogPrint(eLogInfo, "API: starting Tunnels");
		i2p::tunnel::tunnels.Start();
	}

	void StopI2P ()
	{
		LogPrint(eLogInfo, "API: shutting down");
		LogPrint(eLogInfo, "API: stopping Tunnels");
		i2p::tunnel::tunnels.Stop();
		LogPrint(eLogInfo, "API: stopping Transports");
		i2p::transport::transports.Stop();
		LogPrint(eLogInfo, "API: stopping NetDB");
		i2p::data::netdb.Stop();
		i2p::log::Logger().Stop ();
	}

	void RunPeerTest ()
	{
		i2p::transport::transports.PeerTest ();
	}

	std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
		const std::map<std::string, std::string> * params)
	{
		auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
		localDestination->Start ();
		return localDestination;
	}

	std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType,
		const std::map<std::string, std::string> * params)
	{
		i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType);
		auto localDestination = std::make_shared<i2p::client::ClientDestination> (keys, isPublic, params);
		localDestination->Start ();
		return localDestination;
	}

	void DestroyLocalDestination (std::shared_ptr<i2p::client::ClientDestination> dest)
	{
		if (dest)
			dest->Stop ();
	}

	void RequestLeaseSet (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::data::IdentHash& remote)
	{
		if (dest)
			dest->RequestDestination (remote);
	}

	std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::data::IdentHash& remote)
	{
		if (!dest) return nullptr;
		auto leaseSet = dest->FindLeaseSet (remote);
		if (leaseSet)
		{
			auto stream = dest->CreateStream (leaseSet);
			stream->Send (nullptr, 0); // connect
			return stream;
		}
		else
		{
			RequestLeaseSet (dest, remote);
			return nullptr;
		}
	}

	void AcceptStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
	{
		if (dest)
			dest->AcceptStreams (acceptor);
	}

	void DestroyStream (std::shared_ptr<i2p::stream::Stream> stream)
	{
		if (stream)
			stream->Close ();
	}
}
}

<|endoftext|>


<commit_before>#include "utils.h"

#include <sys/stat.h>

#include <algorithm>
#include <cctype> // ::isspace
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>

#include <glibmm/fileutils.h>
#include <glibmm/uriutils.h>

#include "debug.h"
#include "ui.h"
#include "gettext.h"

using namespace std;
using namespace Glib;

const DB_playItem_t *last;

static const ustring LW_FMT = "http://lyrics.wikia.com/api.php?action=lyrics&fmt=xml&artist=%1&song=%2";
static const char *home_cache = getenv("XDG_CACHE_HOME");
static const string lyrics_dir = (home_cache ? string(home_cache) : string(getenv("HOME")) + "/.cache")
                               + "/deadbeef/lyrics/";

static experimental::optional<ustring>(*const providers[])(DB_playItem_t *) = {&download_lyrics_from_lyricwiki};

inline string cached_filename(string artist, string title) {
	replace(artist.begin(), artist.end(), '/', '_');
	replace(title.begin(), title.end(), '/', '_');

	return lyrics_dir + artist + '-' + title;
}

extern "C"
bool is_cached(const char *artist, const char *title) {
	return artist && title && access(cached_filename(artist, title).c_str(), 0) == 0;
}

extern "C"
void ensure_lyrics_path_exists() {
	mkpath(lyrics_dir, 0755);
}

/**
 * Loads the cached lyrics
 * @param artist The artist name
 * @param title  The song title
 * @note         Have no idea about the encodings, so a bug possible here
 */
experimental::optional<ustring> load_cached_lyrics(const char *artist, const char *title) {
	string filename = cached_filename(artist, title);
	debug_out << "filename = '" << filename << "'\n";
	try {
		return {file_get_contents(filename)};
	} catch (const FileError& error) {
		debug_out << error.what();
		return {};
	}
}

bool save_cached_lyrics(const string &artist, const string &title, const string &lyrics) {
	string filename = cached_filename(artist, title);
	ofstream t(filename);
	if (!t) {
		cerr << "lyricbar: could not open file for writing: " << filename << endl;
		return false;
	}
	t << lyrics;
	return true;
}

bool is_playing(DB_playItem_t *track) {
	DB_playItem_t *pl_track = deadbeef->streamer_get_playing_track();
	if (!pl_track)
		return false;

	deadbeef->pl_item_unref(pl_track);
	return pl_track == track;
}

static
experimental::optional<ustring> get_lyrics_from_id3v2(DB_playItem_t *track) {
	const char *path;
	{
		pl_lock_guard guard;
		path = deadbeef->pl_find_meta(track, ":URI");
	}

	DB_FILE *fp = deadbeef->fopen(path);
	if (!fp) {
		cerr << "lyricbar: tried to get lyrics from tag but couldn't fopen the file" << endl;
		return {};
	}

	id3v2_tag id3;
	int res = deadbeef->junk_id3v2_read_full(track, &id3.tag, fp);

	deadbeef->fclose(fp);

	if (res != 0) {
		debug_out << "junk_id3v2_read_full returned " << res << endl;
		return {};
	}

	for (auto frame = id3.tag.frames; frame; frame = frame->next) {
		if (!strcmp(frame->id, "USLT") && frame->size > 5)
			return ustring{reinterpret_cast<const char*>(frame->data + 5)};
	}

	return {};
}

static
experimental::optional<ustring> get_lyrics_from_metadata(DB_playItem_t *track) {
	pl_lock_guard guard;
	const char *lyrics = deadbeef->pl_find_meta(track, "lyrics");
	if (lyrics)
		return ustring{lyrics};
	else return {};
}

experimental::optional<ustring> get_lyrics_from_tag(DB_playItem_t *track) {
	if (auto ans = get_lyrics_from_metadata(track))
		return ans;
	else return get_lyrics_from_id3v2(track);
}

experimental::optional<ustring> download_lyrics_from_lyricwiki(DB_playItem_t *track) {
	const char *artist;
	const char *title;
	{
		pl_lock_guard guard;
		artist = deadbeef->pl_find_meta(track, "artist");
		title  = deadbeef->pl_find_meta(track, "title");
	}

	ustring api_url = ustring::compose(LW_FMT, uri_escape_string(artist, {}, false)
	                                         , uri_escape_string(title, {}, false));

	string url;
	try {
		xmlpp::TextReader reader{api_url};

		while (reader.read()) {
			if (reader.get_node_type() == xmlpp::TextReader::NodeType::Element
			        && reader.get_name() == "lyrics") {
				reader.read();
				// got the cropped version of lyrics — display it before the complete one is got
				if (reader.get_value() == "Not found")
					return {};
				else
					set_lyrics(track, reader.get_value());
			} else if (reader.get_name() == "url") {
				reader.read();
				url = reader.get_value();
				break;
			}
		}
	} catch (const exception &e) {
		cerr << "lyricbar: couldn't parse XML (URI is '" << api_url << "'), what(): " << e.what() << endl;
		return {};
	}

	url.replace(0, strlen("http://lyrics.wikia.com/"),
	            "http://lyrics.wikia.com/api.php?action=query&prop=revisions&rvprop=content&format=xml&titles=");

	string raw_lyrics;
	try {
		xmlpp::TextReader reader{url};
		while (reader.read()) {
			if (reader.get_name() == "rev") {
				reader.read();
				raw_lyrics = reader.get_value();
				break;
			}
		}
	} catch (const exception &e) {
		cerr << "lyricbar: couldn't parse XML, what(): " << e.what() << endl;
		return {};
	}

	// although counter-intuitive, this seems to be the right way to do the parsing
	const static regex r{R"(<lyrics>\s*([^]*?)\s*</lyrics>)"};
	smatch match;
	regex_search(raw_lyrics, match, r);
	if (match.size() < 2) {
		return {};
	}

	return ustring{match[1]};
}

void update_lyrics(void *tr) {
	DB_playItem_t *track = static_cast<DB_playItem_t*>(tr);
	if (track == last)
		return;

	if (auto lyrics = get_lyrics_from_tag(track)) {
		set_lyrics(track, *lyrics);
		return;
	}

	set_lyrics(track, _("Loading..."));

	const char *artist;
	const char *title;
	{
		pl_lock_guard guard;
		artist = deadbeef->pl_find_meta(track, "artist");
		title  = deadbeef->pl_find_meta(track, "title");
	}

	if (artist && title) {
		if (auto lyrics = load_cached_lyrics(artist, title)) {
			set_lyrics(track, *lyrics);
			return;
		}

		// No lyrics in the tag or cache; try to get some and cache if succeeded
		for (auto f : providers) {
			if (auto lyrics = f(track)) {
				set_lyrics(track, *lyrics);
				save_cached_lyrics(artist, title, *lyrics);
				return;
			}
		}
	}
	set_lyrics(track, _("Lyrics not found"));
}

/**
 * Creates the directory tree.
 * @param name the directory path, including trailing slash
 * @return 0 on success; errno after mkdir call if something went wrong
 */
int mkpath(const string &name, mode_t mode) {
	string dir;
	size_t pos = 0;
	while ((pos = name.find_first_of('/', pos)) != string::npos){
		dir = name.substr(0, pos++);
		if (dir.empty())
			continue; // ignore the leading slash
		if (mkdir(dir.c_str(), mode) && errno != EEXIST)
			return errno;
	}
	return 0;
}

int remove_from_cache_action(DB_plugin_action_t *, int ctx) {
	if (ctx == DDB_ACTION_CTX_SELECTION) {
		pl_lock_guard guard;

		ddb_playlist_t *playlist = deadbeef->plt_get_curr();
		if (playlist) {
			DB_playItem_t *current = deadbeef->plt_get_first(playlist, PL_MAIN);
			while (current) {
				if (deadbeef->pl_is_selected (current)) {
					const char *artist = deadbeef->pl_find_meta(current, "artist");
					const char *title  = deadbeef->pl_find_meta(current, "title");
					if (is_cached(artist, title))
						remove(cached_filename(artist, title).c_str());
				}
				DB_playItem_t *next = deadbeef->pl_get_next(current, PL_MAIN);
				deadbeef->pl_item_unref(current);
				current = next;
			}
			deadbeef->plt_unref(playlist);
		}
	}
	return 0;
}
<commit_msg>Fix memory management<commit_after>#include "utils.h"

#include <sys/stat.h>

#include <algorithm>
#include <cctype> // ::isspace
#include <cstring>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <stdexcept>

#include <glibmm/fileutils.h>
#include <glibmm/uriutils.h>

#include "debug.h"
#include "ui.h"
#include "gettext.h"

using namespace std;
using namespace Glib;

const DB_playItem_t *last;

static const ustring LW_FMT = "http://lyrics.wikia.com/api.php?action=lyrics&fmt=xml&artist=%1&song=%2";
static const char *home_cache = getenv("XDG_CACHE_HOME");
static const string lyrics_dir = (home_cache ? string(home_cache) : string(getenv("HOME")) + "/.cache")
                               + "/deadbeef/lyrics/";

static experimental::optional<ustring>(*const providers[])(DB_playItem_t *) = {&download_lyrics_from_lyricwiki};

inline string cached_filename(string artist, string title) {
	replace(artist.begin(), artist.end(), '/', '_');
	replace(title.begin(), title.end(), '/', '_');

	return lyrics_dir + artist + '-' + title;
}

extern "C"
bool is_cached(const char *artist, const char *title) {
	return artist && title && access(cached_filename(artist, title).c_str(), 0) == 0;
}

extern "C"
void ensure_lyrics_path_exists() {
	mkpath(lyrics_dir, 0755);
}

/**
 * Loads the cached lyrics
 * @param artist The artist name
 * @param title  The song title
 * @note         Have no idea about the encodings, so a bug possible here
 */
experimental::optional<ustring> load_cached_lyrics(const char *artist, const char *title) {
	string filename = cached_filename(artist, title);
	debug_out << "filename = '" << filename << "'\n";
	try {
		return {file_get_contents(filename)};
	} catch (const FileError& error) {
		debug_out << error.what();
		return {};
	}
}

bool save_cached_lyrics(const string &artist, const string &title, const string &lyrics) {
	string filename = cached_filename(artist, title);
	ofstream t(filename);
	if (!t) {
		cerr << "lyricbar: could not open file for writing: " << filename << endl;
		return false;
	}
	t << lyrics;
	return true;
}

bool is_playing(DB_playItem_t *track) {
	DB_playItem_t *pl_track = deadbeef->streamer_get_playing_track();
	if (!pl_track)
		return false;

	deadbeef->pl_item_unref(pl_track);
	return pl_track == track;
}

static
experimental::optional<ustring> get_lyrics_from_id3v2(DB_playItem_t *track) {
	const char *path;
	{
		pl_lock_guard guard;
		path = deadbeef->pl_find_meta(track, ":URI");
	}

	DB_FILE *fp = deadbeef->fopen(path);
	if (!fp) {
		cerr << "lyricbar: tried to get lyrics from tag but couldn't fopen the file" << endl;
		return {};
	}

	id3v2_tag id3;
	int res = deadbeef->junk_id3v2_read_full(track, &id3.tag, fp);

	deadbeef->fclose(fp);

	if (res != 0) {
		debug_out << "junk_id3v2_read_full returned " << res << endl;
		return {};
	}

	for (auto frame = id3.tag.frames; frame; frame = frame->next) {
		if (!strcmp(frame->id, "USLT") && frame->size > 5)
			return ustring{reinterpret_cast<const char*>(frame->data + 5)};
	}

	return {};
}

static
experimental::optional<ustring> get_lyrics_from_metadata(DB_playItem_t *track) {
	pl_lock_guard guard;
	const char *lyrics = deadbeef->pl_find_meta(track, "lyrics");
	if (lyrics)
		return ustring{lyrics};
	else return {};
}

experimental::optional<ustring> get_lyrics_from_tag(DB_playItem_t *track) {
	if (auto ans = get_lyrics_from_metadata(track))
		return ans;
	else return get_lyrics_from_id3v2(track);
}

experimental::optional<ustring> download_lyrics_from_lyricwiki(DB_playItem_t *track) {
	ustring artist;
	ustring title;
	{
		pl_lock_guard guard;
		artist = deadbeef->pl_find_meta(track, "artist");
		title  = deadbeef->pl_find_meta(track, "title");
	}

	ustring api_url = ustring::compose(LW_FMT, uri_escape_string(artist, {}, false)
	                                         , uri_escape_string(title, {}, false));

	string url;
	try {
		xmlpp::TextReader reader{api_url};

		while (reader.read()) {
			if (reader.get_node_type() == xmlpp::TextReader::NodeType::Element
			        && reader.get_name() == "lyrics") {
				reader.read();
				// got the cropped version of lyrics — display it before the complete one is got
				if (reader.get_value() == "Not found")
					return {};
				else
					set_lyrics(track, reader.get_value());
			} else if (reader.get_name() == "url") {
				reader.read();
				url = reader.get_value();
				break;
			}
		}
	} catch (const exception &e) {
		cerr << "lyricbar: couldn't parse XML (URI is '" << api_url << "'), what(): " << e.what() << endl;
		return {};
	}

	url.replace(0, strlen("http://lyrics.wikia.com/"),
	            "http://lyrics.wikia.com/api.php?action=query&prop=revisions&rvprop=content&format=xml&titles=");

	string raw_lyrics;
	try {
		xmlpp::TextReader reader{url};
		while (reader.read()) {
			if (reader.get_name() == "rev") {
				reader.read();
				raw_lyrics = reader.get_value();
				break;
			}
		}
	} catch (const exception &e) {
		cerr << "lyricbar: couldn't parse XML, what(): " << e.what() << endl;
		return {};
	}

	// although counter-intuitive, this seems to be the right way to do the parsing
	const static regex r{R"(<lyrics>\s*([^]*?)\s*</lyrics>)"};
	smatch match;
	regex_search(raw_lyrics, match, r);
	if (match.size() < 2) {
		return {};
	}

	return ustring{match[1]};
}

void update_lyrics(void *tr) {
	DB_playItem_t *track = static_cast<DB_playItem_t*>(tr);
	if (track == last)
		return;

	if (auto lyrics = get_lyrics_from_tag(track)) {
		set_lyrics(track, *lyrics);
		return;
	}

	set_lyrics(track, _("Loading..."));

	const char *artist;
	const char *title;
	{
		pl_lock_guard guard;
		artist = deadbeef->pl_find_meta(track, "artist");
		title  = deadbeef->pl_find_meta(track, "title");
	}

	if (artist && title) {
		if (auto lyrics = load_cached_lyrics(artist, title)) {
			set_lyrics(track, *lyrics);
			return;
		}

		// No lyrics in the tag or cache; try to get some and cache if succeeded
		for (auto f : providers) {
			if (auto lyrics = f(track)) {
				set_lyrics(track, *lyrics);
				save_cached_lyrics(artist, title, *lyrics);
				return;
			}
		}
	}
	set_lyrics(track, _("Lyrics not found"));
}

/**
 * Creates the directory tree.
 * @param name the directory path, including trailing slash
 * @return 0 on success; errno after mkdir call if something went wrong
 */
int mkpath(const string &name, mode_t mode) {
	string dir;
	size_t pos = 0;
	while ((pos = name.find_first_of('/', pos)) != string::npos){
		dir = name.substr(0, pos++);
		if (dir.empty())
			continue; // ignore the leading slash
		if (mkdir(dir.c_str(), mode) && errno != EEXIST)
			return errno;
	}
	return 0;
}

int remove_from_cache_action(DB_plugin_action_t *, int ctx) {
	if (ctx == DDB_ACTION_CTX_SELECTION) {
		pl_lock_guard guard;

		ddb_playlist_t *playlist = deadbeef->plt_get_curr();
		if (playlist) {
			DB_playItem_t *current = deadbeef->plt_get_first(playlist, PL_MAIN);
			while (current) {
				if (deadbeef->pl_is_selected (current)) {
					const char *artist = deadbeef->pl_find_meta(current, "artist");
					const char *title  = deadbeef->pl_find_meta(current, "title");
					if (is_cached(artist, title))
						remove(cached_filename(artist, title).c_str());
				}
				DB_playItem_t *next = deadbeef->pl_get_next(current, PL_MAIN);
				deadbeef->pl_item_unref(current);
				current = next;
			}
			deadbeef->plt_unref(playlist);
		}
	}
	return 0;
}
<|endoftext|>


<commit_before>#include "utils.h"

#include <QDebug>
#include <QSettings>
#include <QStandardPaths>

#include <math.h>

using namespace Utils;

GetDirInfoTask::GetDirInfoTask(QDir dir) : _dir(dir)
{
}

void GetDirInfoTask::run()
{
    quint64 size  = 0;
    quint64 count = 0;

    size  = getDirSize(_dir);
    count = getDirCount(_dir);

    emit result(size, count);
}

quint64 GetDirInfoTask::getDirSize(QDir dir)
{
    quint64 size = 0;
    if(dir.exists())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot
                      | QDir::Hidden | QDir::NoSymLinks);

        QFileInfoList list = dir.entryInfoList();
        for(int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.isDir())
            {
                size += getDirSize(QDir(fileInfo.absoluteFilePath()));
            }
            else
                size += static_cast<quint64>(fileInfo.size());
        }
    }
    return size;
}

quint64 GetDirInfoTask::getDirCount(QDir dir)
{
    quint64 count = 0;
    if(dir.exists())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot
                      | QDir::Hidden | QDir::NoSymLinks);

        QFileInfoList list = dir.entryInfoList();
        for(int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.isDir())
            {
                count += getDirCount(QDir(fileInfo.absoluteFilePath()));
            }
            ++count;
        }
    }
    return count;
}

QString Utils::humanBytes(quint64 bytes, int fieldWidth)
{
    QSettings settings;
    bool      IEC  = settings.value("app/iec_prefixes", false).toBool();
    quint64   unit = IEC ? 1024 : 1000;
    if(bytes < unit)
        return QString::number(bytes) + " B";
    int     exp = static_cast<int>(log(bytes) / log(unit));
    QString pre = QString(IEC ? "KMGTPE" : "kMGTPE").at(exp - 1)
                  + QString(IEC ? "i" : "");
    return QString("%1 %2B")
        .arg(bytes / pow(unit, exp), fieldWidth, 'f', 2)
        .arg(pre);
}

QString Utils::validateTarsnapCache(QString path)
{
    QString result;
    if(!path.isEmpty())
    {
        QFileInfo candidate(path);
        if(candidate.exists() && candidate.isDir() && candidate.isWritable())
            result = candidate.canonicalFilePath();
    }
    return result;
}

QString Utils::validateAppDataDir(QString path)
{
    QString result;
    if(!path.isEmpty())
    {
        QFileInfo candidate(path);
        if(candidate.exists() && candidate.isDir() && candidate.isWritable())
            result = candidate.canonicalFilePath();
    }
    return result;
}

QString Utils::findTarsnapClientInPath(QString path, bool keygenToo)
{
    QStringList searchPaths;
    QString     executable;

    if(!path.isEmpty())
        searchPaths << path;

    executable = QStandardPaths::findExecutable(CMD_TARSNAP, searchPaths);
    if(executable.isEmpty() || !QFileInfo(executable).isReadable()
       || !QFileInfo(executable).isExecutable())
        return "";
    else if(keygenToo)
    {
        executable =
            QStandardPaths::findExecutable(CMD_TARSNAPKEYGEN, searchPaths);
    }

    if(executable.isEmpty() || !QFileInfo(executable).isReadable()
       || !QFileInfo(executable).isExecutable())
        return "";
    else if(path.isEmpty())
        path = QFileInfo(executable).absolutePath();

    return path;
}

QFileInfoList Utils::findKeysInPath(QString path)
{
    QFileInfoList result;
    QDir          dir(path);
    if(!dir.exists())
        return result;
    dir.setFilter(QDir::Files | QDir::Readable);
    dir.setSorting(QDir::Time);
    dir.setNameFilters(QStringList("*.key"));
    return dir.entryInfoList();
}

bool Utils::tarsnapVersionMinimum(const QString &minVersion)
{
    QSettings settings;
    QString   tarsnapVersion = settings.value("tarsnap/version", "").toString();
    QRegExp   versionRx("(\\d+\\.\\d+\\.\\d+(\\.\\d+)?)");
    return (-1 != versionRx.indexIn(tarsnapVersion))
           && (versionRx.cap(0) >= minVersion);
}

QString Utils::quoteCommandLine(QStringList args)
{
    QStringList escaped;
    QRegExp     rx("^[0-9a-z-A-Z/._-]*$");
    QString     cmdLine;

    for(int i = 0; i < args.size(); ++i)
    {
        QString arg = args.at(i);
        if(rx.indexIn(arg) >= 0)
        {
            escaped.append(arg);
        }
        else
        {
            escaped.append(arg.prepend("\'").append("\'"));
        }
    }

    cmdLine = escaped.join(' ');
    return (cmdLine);
}
<commit_msg>findTarsnapClientInPath(): also search /usr/local/bin<commit_after>#include "utils.h"

#include <QDebug>
#include <QSettings>
#include <QStandardPaths>

#include <math.h>

using namespace Utils;

GetDirInfoTask::GetDirInfoTask(QDir dir) : _dir(dir)
{
}

void GetDirInfoTask::run()
{
    quint64 size  = 0;
    quint64 count = 0;

    size  = getDirSize(_dir);
    count = getDirCount(_dir);

    emit result(size, count);
}

quint64 GetDirInfoTask::getDirSize(QDir dir)
{
    quint64 size = 0;
    if(dir.exists())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot
                      | QDir::Hidden | QDir::NoSymLinks);

        QFileInfoList list = dir.entryInfoList();
        for(int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.isDir())
            {
                size += getDirSize(QDir(fileInfo.absoluteFilePath()));
            }
            else
                size += static_cast<quint64>(fileInfo.size());
        }
    }
    return size;
}

quint64 GetDirInfoTask::getDirCount(QDir dir)
{
    quint64 count = 0;
    if(dir.exists())
    {
        dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot
                      | QDir::Hidden | QDir::NoSymLinks);

        QFileInfoList list = dir.entryInfoList();
        for(int i = 0; i < list.size(); ++i)
        {
            QFileInfo fileInfo = list.at(i);
            if(fileInfo.isDir())
            {
                count += getDirCount(QDir(fileInfo.absoluteFilePath()));
            }
            ++count;
        }
    }
    return count;
}

QString Utils::humanBytes(quint64 bytes, int fieldWidth)
{
    QSettings settings;
    bool      IEC  = settings.value("app/iec_prefixes", false).toBool();
    quint64   unit = IEC ? 1024 : 1000;
    if(bytes < unit)
        return QString::number(bytes) + " B";
    int     exp = static_cast<int>(log(bytes) / log(unit));
    QString pre = QString(IEC ? "KMGTPE" : "kMGTPE").at(exp - 1)
                  + QString(IEC ? "i" : "");
    return QString("%1 %2B")
        .arg(bytes / pow(unit, exp), fieldWidth, 'f', 2)
        .arg(pre);
}

QString Utils::validateTarsnapCache(QString path)
{
    QString result;
    if(!path.isEmpty())
    {
        QFileInfo candidate(path);
        if(candidate.exists() && candidate.isDir() && candidate.isWritable())
            result = candidate.canonicalFilePath();
    }
    return result;
}

QString Utils::validateAppDataDir(QString path)
{
    QString result;
    if(!path.isEmpty())
    {
        QFileInfo candidate(path);
        if(candidate.exists() && candidate.isDir() && candidate.isWritable())
            result = candidate.canonicalFilePath();
    }
    return result;
}

QString Utils::findTarsnapClientInPath(QString path, bool keygenToo)
{
    QStringList searchPaths;
    QString     executable;

    if(!path.isEmpty())
        searchPaths << path;

    executable = QStandardPaths::findExecutable(CMD_TARSNAP, searchPaths);
#if defined(Q_OS_OSX)
    // If we haven't found the command in the default PATH, look
    // in /usr/local/bin because that's where brew puts it.
    QStringList brew_bin = {"/usr/local/bin"};
    if(executable.isEmpty() && searchPaths.isEmpty())
        executable = QStandardPaths::findExecutable(CMD_TARSNAP, brew_bin);
#endif
    if(executable.isEmpty() || !QFileInfo(executable).isReadable()
       || !QFileInfo(executable).isExecutable())
        return "";
    else if(keygenToo)
    {
        executable =
            QStandardPaths::findExecutable(CMD_TARSNAPKEYGEN, searchPaths);
#if defined(Q_OS_OSX)
        if(executable.isEmpty() && searchPaths.isEmpty())
            executable =
                QStandardPaths::findExecutable(CMD_TARSNAPKEYGEN, brew_bin);
#endif
    }

    if(executable.isEmpty() || !QFileInfo(executable).isReadable()
       || !QFileInfo(executable).isExecutable())
        return "";
    else if(path.isEmpty())
        path = QFileInfo(executable).absolutePath();

    return path;
}

QFileInfoList Utils::findKeysInPath(QString path)
{
    QFileInfoList result;
    QDir          dir(path);
    if(!dir.exists())
        return result;
    dir.setFilter(QDir::Files | QDir::Readable);
    dir.setSorting(QDir::Time);
    dir.setNameFilters(QStringList("*.key"));
    return dir.entryInfoList();
}

bool Utils::tarsnapVersionMinimum(const QString &minVersion)
{
    QSettings settings;
    QString   tarsnapVersion = settings.value("tarsnap/version", "").toString();
    QRegExp   versionRx("(\\d+\\.\\d+\\.\\d+(\\.\\d+)?)");
    return (-1 != versionRx.indexIn(tarsnapVersion))
           && (versionRx.cap(0) >= minVersion);
}

QString Utils::quoteCommandLine(QStringList args)
{
    QStringList escaped;
    QRegExp     rx("^[0-9a-z-A-Z/._-]*$");
    QString     cmdLine;

    for(int i = 0; i < args.size(); ++i)
    {
        QString arg = args.at(i);
        if(rx.indexIn(arg) >= 0)
        {
            escaped.append(arg);
        }
        else
        {
            escaped.append(arg.prepend("\'").append("\'"));
        }
    }

    cmdLine = escaped.join(' ');
    return (cmdLine);
}
<|endoftext|>


<commit_before>// Chemfiles, a modern library for chemistry file reading and writing
// Copyright (C) Guillaume Fraux and contributors -- BSD license

#include <cerrno>
#include <string>
#include <vector>

#include "chemfiles/utils.hpp"

#ifdef CHEMFILES_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>  // GetUserName & GetComputerNameEx
#include <direct.h>  // _getcwd
#define getcwd _getcwd
#else
#include <unistd.h>
#include <pwd.h>
#endif

std::string chemfiles::user_name() {
#ifdef CHEMFILES_WINDOWS
    char name[1024] = {0};
    DWORD size = 1024;
    if (!GetUserName(name, &size)) {
        return "";
    }
    return name;
#else
    auto user = getpwuid(getuid());
    if (user != nullptr) {
        return user->pw_name;
    } else {
        return "";
    }
#endif
}

std::string chemfiles::hostname() {
#ifdef CHEMFILES_WINDOWS
    char name[1024] = {0};
    DWORD size = 1024;
    if (!GetComputerNameEx(ComputerNameDnsHostname, name, &size)) {
        return "";
    }
    return name;
#else
    #if defined(_POSIX_HOST_NAME_MAX)
    #define BUFFSIZE _POSIX_HOST_NAME_MAX
    #elif defined(MAXHOSTNAMELEN)
    #define BUFFSIZE MAXHOSTNAMELEN
    #else
    #define BUFFSIZE 1024
    #endif

    char name[BUFFSIZE];
    if (gethostname(name, sizeof(name)) != 0) {
        return "";
    }
    return name;
#endif
}

std::string chemfiles::current_directory() {
    // loop util buffer large enough
    for (size_t size = 128;; size *=2) {
        std::vector<char> buffer(size, '\0');
#ifdef CHEMFILES_WINDOWS
        auto result = getcwd(buffer.data(), static_cast<int>(size));
#else
        auto result = getcwd(buffer.data(), size);
#endif
        if (result == nullptr) {
            if (errno == ERANGE) {
                continue;
            } else {
                return "";
            }
        }
        // Remove additional '\0' from the string
        return std::string(buffer.data());
    }
}
<commit_msg>Make calls to utils::username() thread-safe<commit_after>// Chemfiles, a modern library for chemistry file reading and writing
// Copyright (C) Guillaume Fraux and contributors -- BSD license

#include <cerrno>
#include <string>
#include <vector>

#include "chemfiles/utils.hpp"

#ifdef CHEMFILES_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <windows.h>  // GetUserName & GetComputerNameEx
#include <direct.h>  // _getcwd
#define getcwd _getcwd
#else
#include <unistd.h>
#endif

std::string chemfiles::user_name() {
#ifdef CHEMFILES_WINDOWS
    char name[1024] = {0};
    DWORD size = 1024;
    if (!GetUserName(name, &size)) {
        return "";
    }
    return name;
#else
    char user[1024];
    if (getlogin_r(user, sizeof(user)) != 0) {
        return "";
    }
    return user;
#endif
}

std::string chemfiles::hostname() {
#ifdef CHEMFILES_WINDOWS
    char name[1024] = {0};
    DWORD size = 1024;
    if (!GetComputerNameEx(ComputerNameDnsHostname, name, &size)) {
        return "";
    }
    return name;
#else
    #if defined(_POSIX_HOST_NAME_MAX)
    #define BUFFSIZE _POSIX_HOST_NAME_MAX
    #elif defined(MAXHOSTNAMELEN)
    #define BUFFSIZE MAXHOSTNAMELEN
    #else
    #define BUFFSIZE 1024
    #endif

    char name[BUFFSIZE];
    if (gethostname(name, sizeof(name)) != 0) {
        return "";
    }
    return name;
#endif
}

std::string chemfiles::current_directory() {
    // loop util buffer large enough
    for (size_t size = 128;; size *=2) {
        std::vector<char> buffer(size, '\0');
#ifdef CHEMFILES_WINDOWS
        auto result = getcwd(buffer.data(), static_cast<int>(size));
#else
        auto result = getcwd(buffer.data(), size);
#endif
        if (result == nullptr) {
            if (errno == ERANGE) {
                continue;
            } else {
                return "";
            }
        }
        // Remove additional '\0' from the string
        return std::string(buffer.data());
    }
}
<|endoftext|>


<commit_before>#include "worker.h"

#include <chrono>
#include <thread>

#include "utils.h"

#include <pynumbuf/serialize.h>

extern "C" {
  static PyObject *RayError;
}

Status WorkerServiceImpl::ExecuteTask(ServerContext* context, const ExecuteTaskRequest* request, ExecuteTaskReply* reply) {
  task_ = request->task(); // Copy task
  RAY_LOG(RAY_INFO, "invoked task " << request->task().name());
  Task* taskptr = &task_;
  send_queue_.send(&taskptr);
  return Status::OK;
}

Worker::Worker(const std::string& worker_address, std::shared_ptr<Channel> scheduler_channel, std::shared_ptr<Channel> objstore_channel)
    : worker_address_(worker_address),
      scheduler_stub_(Scheduler::NewStub(scheduler_channel)) {
  receive_queue_.connect(worker_address_, true);
  connected_ = true;
}

SubmitTaskReply Worker::submit_task(SubmitTaskRequest* request, int max_retries, int retry_wait_milliseconds) {
  RAY_CHECK(connected_, "Attempted to perform submit_task but failed.");
  SubmitTaskReply reply;
  Status status;
  for (int i = 0; i < 1 + max_retries; ++i) {
    ClientContext context;
    status = scheduler_stub_->SubmitTask(&context, *request, &reply);
    if (reply.function_registered()) {
      break;
    }
    RAY_LOG(RAY_INFO, "The function " << request->task().name() << " was not registered, so attempting to resubmit the task.");
    std::this_thread::sleep_for(std::chrono::milliseconds(retry_wait_milliseconds));
  }
  return reply;
}

void Worker::register_worker(const std::string& worker_address, const std::string& objstore_address) {
  RegisterWorkerRequest request;
  request.set_worker_address(worker_address);
  request.set_objstore_address(objstore_address);
  RegisterWorkerReply reply;
  ClientContext context;
  Status status = scheduler_stub_->RegisterWorker(&context, request, &reply);
  workerid_ = reply.workerid();
  objstoreid_ = reply.objstoreid();
  segmentpool_ = std::make_shared<MemorySegmentPool>(objstoreid_, false);
  request_obj_queue_.connect(std::string("queue:") + objstore_address + std::string(":obj"), false);
  std::string queue_name = std::string("queue:") + objstore_address + std::string(":worker:") + std::to_string(workerid_) + std::string(":obj");
  receive_obj_queue_.connect(queue_name, true);
  return;
}

void Worker::request_object(ObjRef objref) {
  RAY_CHECK(connected_, "Attempted to perform request_object but failed.");
  RequestObjRequest request;
  request.set_workerid(workerid_);
  request.set_objref(objref);
  AckReply reply;
  ClientContext context;
  Status status = scheduler_stub_->RequestObj(&context, request, &reply);
  return;
}

ObjRef Worker::get_objref() {
  // first get objref for the new object
  RAY_CHECK(connected_, "Attempted to perform get_objref but failed.");
  PutObjRequest request;
  PutObjReply reply;
  ClientContext context;
  Status status = scheduler_stub_->PutObj(&context, request, &reply);
  return reply.objref();
}

slice Worker::get_object(ObjRef objref) {
  // get_object assumes that objref is a canonical objref
  RAY_CHECK(connected_, "Attempted to perform get_object but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  slice slice;
  slice.data = segmentpool_->get_address(result);
  slice.len = result.size();
  slice.segmentid = result.segmentid();
  return slice;
}

// TODO(pcm): More error handling
// contained_objrefs is a vector of all the objrefs contained in obj
void Worker::put_object(ObjRef objref, const Obj* obj, std::vector<ObjRef> &contained_objrefs) {
  RAY_CHECK(connected_, "Attempted to perform put_object but failed.");
  std::string data;
  obj->SerializeToString(&data); // TODO(pcm): get rid of this serialization
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::ALLOC;
  request.objref = objref;
  request.size = data.size();
  request_obj_queue_.send(&request);
  if (contained_objrefs.size() > 0) {
    RAY_LOG(RAY_REFCOUNT, "In put_object, calling increment_reference_count for contained objrefs");
    increment_reference_count(contained_objrefs); // Notify the scheduler that some object references are serialized in the objstore.
  }
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  uint8_t* target = segmentpool_->get_address(result);
  std::memcpy(target, &data[0], data.size());
  // We immediately unmap here; if the object is going to be accessed again, it will be mapped again;
  // This is reqired because we do not have a mechanism to unmap the object later.
  segmentpool_->unmap_segment(result.segmentid());
  request.type = ObjRequestType::WORKER_DONE;
  request.metadata_offset = 0;
  request_obj_queue_.send(&request);

  // Notify the scheduler about the objrefs that we are serializing in the objstore.
  AddContainedObjRefsRequest contained_objrefs_request;
  contained_objrefs_request.set_objref(objref);
  for (int i = 0; i < contained_objrefs.size(); ++i) {
    contained_objrefs_request.add_contained_objref(contained_objrefs[i]); // TODO(rkn): The naming here is bad
  }
  AckReply reply;
  ClientContext context;
  scheduler_stub_->AddContainedObjRefs(&context, contained_objrefs_request, &reply);
}

#define CHECK_ARROW_STATUS(s, msg)                              \
  do {                                                          \
    arrow::Status _s = (s);                                     \
    if (!_s.ok()) {                                             \
      std::string _errmsg = std::string(msg) + _s.ToString();   \
      PyErr_SetString(RayError, _errmsg.c_str());            \
      return NULL;                                              \
    }                                                           \
  } while (0);

PyObject* Worker::put_arrow(ObjRef objref, PyObject* value) {
  RAY_CHECK(connected_, "Attempted to perform put_arrow but failed.");
  ObjRequest request;
  pynumbuf::PythonObjectWriter writer;
  int64_t size;
  CHECK_ARROW_STATUS(writer.AssemblePayload(value), "error during AssemblePayload: ");
  CHECK_ARROW_STATUS(writer.GetTotalSize(&size), "error during GetTotalSize: ");
  request.workerid = workerid_;
  request.type = ObjRequestType::ALLOC;
  request.objref = objref;
  request.size = size;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  int64_t metadata_offset;
  uint8_t* address = segmentpool_->get_address(result);
  auto source = std::make_shared<BufferMemorySource>(address, size);
  CHECK_ARROW_STATUS(writer.Write(source.get(), &metadata_offset), "error during Write: ");
  // We immediately unmap here; if the object is going to be accessed again, it will be mapped again;
  // This is reqired because we do not have a mechanism to unmap the object later.
  segmentpool_->unmap_segment(result.segmentid());
  request.type = ObjRequestType::WORKER_DONE;
  request.metadata_offset = metadata_offset;
  request_obj_queue_.send(&request);
  Py_RETURN_NONE;
}

// returns python list containing the value represented by objref and the
// segmentid in which the object is stored
PyObject* Worker::get_arrow(ObjRef objref, SegmentId& segmentid) {
  RAY_CHECK(connected_, "Attempted to perform get_arrow but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  uint8_t* address = segmentpool_->get_address(result);
  auto source = std::make_shared<BufferMemorySource>(address, result.size());
  segmentid = result.segmentid();
  PyObject* value;
  CHECK_ARROW_STATUS(pynumbuf::ReadPythonObjectFrom(source.get(), result.metadata_offset(), &value), "error during ReadPythonObjectFrom: ");
  return value;
}

bool Worker::is_arrow(ObjRef objref) {
  RAY_CHECK(connected_, "Attempted to perform is_arrow but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  return result.metadata_offset() != 0;
}

void Worker::unmap_object(ObjRef objref) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempted to perform unmap_object but failed.");
    return;
  }
  segmentpool_->unmap_segment(objref);
}

void Worker::alias_objrefs(ObjRef alias_objref, ObjRef target_objref) {
  RAY_CHECK(connected_, "Attempted to perform alias_objrefs but failed.");
  ClientContext context;
  AliasObjRefsRequest request;
  request.set_alias_objref(alias_objref);
  request.set_target_objref(target_objref);
  AckReply reply;
  scheduler_stub_->AliasObjRefs(&context, request, &reply);
}

void Worker::increment_reference_count(std::vector<ObjRef> &objrefs) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempting to increment_reference_count for objrefs, but connected_ = " << connected_ << " so returning instead.");
    return;
  }
  if (objrefs.size() > 0) {
    ClientContext context;
    IncrementRefCountRequest request;
    for (int i = 0; i < objrefs.size(); ++i) {
      RAY_LOG(RAY_REFCOUNT, "Incrementing reference count for objref " << objrefs[i]);
      request.add_objref(objrefs[i]);
    }
    AckReply reply;
    scheduler_stub_->IncrementRefCount(&context, request, &reply);
  }
}

void Worker::decrement_reference_count(std::vector<ObjRef> &objrefs) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempting to decrement_reference_count, but connected_ = " << connected_ << " so returning instead.");
    return;
  }
  if (objrefs.size() > 0) {
    ClientContext context;
    DecrementRefCountRequest request;
    for (int i = 0; i < objrefs.size(); ++i) {
      RAY_LOG(RAY_REFCOUNT, "Decrementing reference count for objref " << objrefs[i]);
      request.add_objref(objrefs[i]);
    }
    AckReply reply;
    scheduler_stub_->DecrementRefCount(&context, request, &reply);
  }
}

void Worker::register_function(const std::string& name, size_t num_return_vals) {
  RAY_CHECK(connected_, "Attempted to perform register_function but failed.");
  ClientContext context;
  RegisterFunctionRequest request;
  request.set_fnname(name);
  request.set_num_return_vals(num_return_vals);
  request.set_workerid(workerid_);
  AckReply reply;
  scheduler_stub_->RegisterFunction(&context, request, &reply);
}

Task* Worker::receive_next_task() {
  Task* task;
  receive_queue_.receive(&task);
  return task;
}

void Worker::notify_task_completed(bool task_succeeded, std::string error_message) {
  RAY_CHECK(connected_, "Attempted to perform notify_task_completed but failed.");
  ClientContext context;
  ReadyForNewTaskRequest request;
  request.set_workerid(workerid_);
  ReadyForNewTaskRequest::PreviousTaskInfo* previous_task_info = request.mutable_previous_task_info();
  previous_task_info->set_task_succeeded(task_succeeded);
  previous_task_info->set_error_message(error_message);
  AckReply reply;
  scheduler_stub_->ReadyForNewTask(&context, request, &reply);
}

void Worker::disconnect() {
  connected_ = false;
}

bool Worker::connected() {
  return connected_;
}

// TODO(rkn): Should we be using pointers or references? And should they be const?
void Worker::scheduler_info(ClientContext &context, SchedulerInfoRequest &request, SchedulerInfoReply &reply) {
  RAY_CHECK(connected_, "Attempted to get scheduler info but failed.");
  scheduler_stub_->SchedulerInfo(&context, request, &reply);
}

void Worker::task_info(ClientContext &context, TaskInfoRequest &request, TaskInfoReply &reply) {
  RAY_CHECK(connected_, "Attempted to get worker info but failed.");
  scheduler_stub_->TaskInfo(&context, request, &reply);
}

// Communication between the WorkerServer and the Worker happens via a message
// queue. This is because the Python interpreter needs to be single threaded
// (in our case running in the main thread), whereas the WorkerService will
// run in a separate thread and potentially utilize multiple threads.
void Worker::start_worker_service() {
  const char* service_addr = worker_address_.c_str();
  worker_server_thread_ = std::thread([this, service_addr]() {
    std::string service_address(service_addr);
    std::string::iterator split_point = split_ip_address(service_address);
    std::string port;
    port.assign(split_point, service_address.end());
    WorkerServiceImpl service(service_address);
    ServerBuilder builder;
    builder.AddListeningPort(std::string("0.0.0.0:") + port, grpc::InsecureServerCredentials());
    builder.RegisterService(&service);
    std::unique_ptr<Server> server(builder.BuildAndStart());
    RAY_LOG(RAY_INFO, "worker server listening on " << service_address);

    ClientContext context;
    ReadyForNewTaskRequest request;
    request.set_workerid(workerid_);
    AckReply reply;
    scheduler_stub_->ReadyForNewTask(&context, request, &reply);

    server->Wait();
  });
}
<commit_msg>Set the workerid in submit_task and get_objref<commit_after>#include "worker.h"

#include <chrono>
#include <thread>

#include "utils.h"

#include <pynumbuf/serialize.h>

extern "C" {
  static PyObject *RayError;
}

Status WorkerServiceImpl::ExecuteTask(ServerContext* context, const ExecuteTaskRequest* request, ExecuteTaskReply* reply) {
  task_ = request->task(); // Copy task
  RAY_LOG(RAY_INFO, "invoked task " << request->task().name());
  Task* taskptr = &task_;
  send_queue_.send(&taskptr);
  return Status::OK;
}

Worker::Worker(const std::string& worker_address, std::shared_ptr<Channel> scheduler_channel, std::shared_ptr<Channel> objstore_channel)
    : worker_address_(worker_address),
      scheduler_stub_(Scheduler::NewStub(scheduler_channel)) {
  receive_queue_.connect(worker_address_, true);
  connected_ = true;
}

SubmitTaskReply Worker::submit_task(SubmitTaskRequest* request, int max_retries, int retry_wait_milliseconds) {
  RAY_CHECK(connected_, "Attempted to perform submit_task but failed.");
  SubmitTaskReply reply;
  Status status;
  request->set_workerid(workerid_);
  for (int i = 0; i < 1 + max_retries; ++i) {
    ClientContext context;
    status = scheduler_stub_->SubmitTask(&context, *request, &reply);
    if (reply.function_registered()) {
      break;
    }
    RAY_LOG(RAY_INFO, "The function " << request->task().name() << " was not registered, so attempting to resubmit the task.");
    std::this_thread::sleep_for(std::chrono::milliseconds(retry_wait_milliseconds));
  }
  return reply;
}

void Worker::register_worker(const std::string& worker_address, const std::string& objstore_address) {
  RegisterWorkerRequest request;
  request.set_worker_address(worker_address);
  request.set_objstore_address(objstore_address);
  RegisterWorkerReply reply;
  ClientContext context;
  Status status = scheduler_stub_->RegisterWorker(&context, request, &reply);
  workerid_ = reply.workerid();
  objstoreid_ = reply.objstoreid();
  segmentpool_ = std::make_shared<MemorySegmentPool>(objstoreid_, false);
  request_obj_queue_.connect(std::string("queue:") + objstore_address + std::string(":obj"), false);
  std::string queue_name = std::string("queue:") + objstore_address + std::string(":worker:") + std::to_string(workerid_) + std::string(":obj");
  receive_obj_queue_.connect(queue_name, true);
  return;
}

void Worker::request_object(ObjRef objref) {
  RAY_CHECK(connected_, "Attempted to perform request_object but failed.");
  RequestObjRequest request;
  request.set_workerid(workerid_);
  request.set_objref(objref);
  AckReply reply;
  ClientContext context;
  Status status = scheduler_stub_->RequestObj(&context, request, &reply);
  return;
}

ObjRef Worker::get_objref() {
  // first get objref for the new object
  RAY_CHECK(connected_, "Attempted to perform get_objref but failed.");
  PutObjRequest request;
  request.set_workerid(workerid_);
  PutObjReply reply;
  ClientContext context;
  Status status = scheduler_stub_->PutObj(&context, request, &reply);
  return reply.objref();
}

slice Worker::get_object(ObjRef objref) {
  // get_object assumes that objref is a canonical objref
  RAY_CHECK(connected_, "Attempted to perform get_object but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  slice slice;
  slice.data = segmentpool_->get_address(result);
  slice.len = result.size();
  slice.segmentid = result.segmentid();
  return slice;
}

// TODO(pcm): More error handling
// contained_objrefs is a vector of all the objrefs contained in obj
void Worker::put_object(ObjRef objref, const Obj* obj, std::vector<ObjRef> &contained_objrefs) {
  RAY_CHECK(connected_, "Attempted to perform put_object but failed.");
  std::string data;
  obj->SerializeToString(&data); // TODO(pcm): get rid of this serialization
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::ALLOC;
  request.objref = objref;
  request.size = data.size();
  request_obj_queue_.send(&request);
  if (contained_objrefs.size() > 0) {
    RAY_LOG(RAY_REFCOUNT, "In put_object, calling increment_reference_count for contained objrefs");
    increment_reference_count(contained_objrefs); // Notify the scheduler that some object references are serialized in the objstore.
  }
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  uint8_t* target = segmentpool_->get_address(result);
  std::memcpy(target, &data[0], data.size());
  // We immediately unmap here; if the object is going to be accessed again, it will be mapped again;
  // This is reqired because we do not have a mechanism to unmap the object later.
  segmentpool_->unmap_segment(result.segmentid());
  request.type = ObjRequestType::WORKER_DONE;
  request.metadata_offset = 0;
  request_obj_queue_.send(&request);

  // Notify the scheduler about the objrefs that we are serializing in the objstore.
  AddContainedObjRefsRequest contained_objrefs_request;
  contained_objrefs_request.set_objref(objref);
  for (int i = 0; i < contained_objrefs.size(); ++i) {
    contained_objrefs_request.add_contained_objref(contained_objrefs[i]); // TODO(rkn): The naming here is bad
  }
  AckReply reply;
  ClientContext context;
  scheduler_stub_->AddContainedObjRefs(&context, contained_objrefs_request, &reply);
}

#define CHECK_ARROW_STATUS(s, msg)                              \
  do {                                                          \
    arrow::Status _s = (s);                                     \
    if (!_s.ok()) {                                             \
      std::string _errmsg = std::string(msg) + _s.ToString();   \
      PyErr_SetString(RayError, _errmsg.c_str());            \
      return NULL;                                              \
    }                                                           \
  } while (0);

PyObject* Worker::put_arrow(ObjRef objref, PyObject* value) {
  RAY_CHECK(connected_, "Attempted to perform put_arrow but failed.");
  ObjRequest request;
  pynumbuf::PythonObjectWriter writer;
  int64_t size;
  CHECK_ARROW_STATUS(writer.AssemblePayload(value), "error during AssemblePayload: ");
  CHECK_ARROW_STATUS(writer.GetTotalSize(&size), "error during GetTotalSize: ");
  request.workerid = workerid_;
  request.type = ObjRequestType::ALLOC;
  request.objref = objref;
  request.size = size;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  int64_t metadata_offset;
  uint8_t* address = segmentpool_->get_address(result);
  auto source = std::make_shared<BufferMemorySource>(address, size);
  CHECK_ARROW_STATUS(writer.Write(source.get(), &metadata_offset), "error during Write: ");
  // We immediately unmap here; if the object is going to be accessed again, it will be mapped again;
  // This is reqired because we do not have a mechanism to unmap the object later.
  segmentpool_->unmap_segment(result.segmentid());
  request.type = ObjRequestType::WORKER_DONE;
  request.metadata_offset = metadata_offset;
  request_obj_queue_.send(&request);
  Py_RETURN_NONE;
}

// returns python list containing the value represented by objref and the
// segmentid in which the object is stored
PyObject* Worker::get_arrow(ObjRef objref, SegmentId& segmentid) {
  RAY_CHECK(connected_, "Attempted to perform get_arrow but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  uint8_t* address = segmentpool_->get_address(result);
  auto source = std::make_shared<BufferMemorySource>(address, result.size());
  segmentid = result.segmentid();
  PyObject* value;
  CHECK_ARROW_STATUS(pynumbuf::ReadPythonObjectFrom(source.get(), result.metadata_offset(), &value), "error during ReadPythonObjectFrom: ");
  return value;
}

bool Worker::is_arrow(ObjRef objref) {
  RAY_CHECK(connected_, "Attempted to perform is_arrow but failed.");
  ObjRequest request;
  request.workerid = workerid_;
  request.type = ObjRequestType::GET;
  request.objref = objref;
  request_obj_queue_.send(&request);
  ObjHandle result;
  receive_obj_queue_.receive(&result);
  return result.metadata_offset() != 0;
}

void Worker::unmap_object(ObjRef objref) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempted to perform unmap_object but failed.");
    return;
  }
  segmentpool_->unmap_segment(objref);
}

void Worker::alias_objrefs(ObjRef alias_objref, ObjRef target_objref) {
  RAY_CHECK(connected_, "Attempted to perform alias_objrefs but failed.");
  ClientContext context;
  AliasObjRefsRequest request;
  request.set_alias_objref(alias_objref);
  request.set_target_objref(target_objref);
  AckReply reply;
  scheduler_stub_->AliasObjRefs(&context, request, &reply);
}

void Worker::increment_reference_count(std::vector<ObjRef> &objrefs) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempting to increment_reference_count for objrefs, but connected_ = " << connected_ << " so returning instead.");
    return;
  }
  if (objrefs.size() > 0) {
    ClientContext context;
    IncrementRefCountRequest request;
    for (int i = 0; i < objrefs.size(); ++i) {
      RAY_LOG(RAY_REFCOUNT, "Incrementing reference count for objref " << objrefs[i]);
      request.add_objref(objrefs[i]);
    }
    AckReply reply;
    scheduler_stub_->IncrementRefCount(&context, request, &reply);
  }
}

void Worker::decrement_reference_count(std::vector<ObjRef> &objrefs) {
  if (!connected_) {
    RAY_LOG(RAY_DEBUG, "Attempting to decrement_reference_count, but connected_ = " << connected_ << " so returning instead.");
    return;
  }
  if (objrefs.size() > 0) {
    ClientContext context;
    DecrementRefCountRequest request;
    for (int i = 0; i < objrefs.size(); ++i) {
      RAY_LOG(RAY_REFCOUNT, "Decrementing reference count for objref " << objrefs[i]);
      request.add_objref(objrefs[i]);
    }
    AckReply reply;
    scheduler_stub_->DecrementRefCount(&context, request, &reply);
  }
}

void Worker::register_function(const std::string& name, size_t num_return_vals) {
  RAY_CHECK(connected_, "Attempted to perform register_function but failed.");
  ClientContext context;
  RegisterFunctionRequest request;
  request.set_fnname(name);
  request.set_num_return_vals(num_return_vals);
  request.set_workerid(workerid_);
  AckReply reply;
  scheduler_stub_->RegisterFunction(&context, request, &reply);
}

Task* Worker::receive_next_task() {
  Task* task;
  receive_queue_.receive(&task);
  return task;
}

void Worker::notify_task_completed(bool task_succeeded, std::string error_message) {
  RAY_CHECK(connected_, "Attempted to perform notify_task_completed but failed.");
  ClientContext context;
  ReadyForNewTaskRequest request;
  request.set_workerid(workerid_);
  ReadyForNewTaskRequest::PreviousTaskInfo* previous_task_info = request.mutable_previous_task_info();
  previous_task_info->set_task_succeeded(task_succeeded);
  previous_task_info->set_error_message(error_message);
  AckReply reply;
  scheduler_stub_->ReadyForNewTask(&context, request, &reply);
}

void Worker::disconnect() {
  connected_ = false;
}

bool Worker::connected() {
  return connected_;
}

// TODO(rkn): Should we be using pointers or references? And should they be const?
void Worker::scheduler_info(ClientContext &context, SchedulerInfoRequest &request, SchedulerInfoReply &reply) {
  RAY_CHECK(connected_, "Attempted to get scheduler info but failed.");
  scheduler_stub_->SchedulerInfo(&context, request, &reply);
}

void Worker::task_info(ClientContext &context, TaskInfoRequest &request, TaskInfoReply &reply) {
  RAY_CHECK(connected_, "Attempted to get worker info but failed.");
  scheduler_stub_->TaskInfo(&context, request, &reply);
}

// Communication between the WorkerServer and the Worker happens via a message
// queue. This is because the Python interpreter needs to be single threaded
// (in our case running in the main thread), whereas the WorkerService will
// run in a separate thread and potentially utilize multiple threads.
void Worker::start_worker_service() {
  const char* service_addr = worker_address_.c_str();
  worker_server_thread_ = std::thread([this, service_addr]() {
    std::string service_address(service_addr);
    std::string::iterator split_point = split_ip_address(service_address);
    std::string port;
    port.assign(split_point, service_address.end());
    WorkerServiceImpl service(service_address);
    ServerBuilder builder;
    builder.AddListeningPort(std::string("0.0.0.0:") + port, grpc::InsecureServerCredentials());
    builder.RegisterService(&service);
    std::unique_ptr<Server> server(builder.BuildAndStart());
    RAY_LOG(RAY_INFO, "worker server listening on " << service_address);

    ClientContext context;
    ReadyForNewTaskRequest request;
    request.set_workerid(workerid_);
    AckReply reply;
    scheduler_stub_->ReadyForNewTask(&context, request, &reply);

    server->Wait();
  });
}
<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
   Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
   Copyright (C) 2007 Mirko Stocker <me@misto.ch>
   Copyright (C) 2009 Dominik Haumann <dhaumann kde org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

//BEGIN Includes
#include "katefilebrowser.h"
#include "katefilebrowser.moc"

#include "katebookmarkhandler.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>

#include <KActionCollection>
#include <KActionMenu>
#include <KConfigGroup>
#include <KDebug>
#include <KDirOperator>
#include <KFilePlacesModel>
#include <KHistoryComboBox>
#include <KLocale>
#include <KToolBar>
#include <KUrlNavigator>
#include <QAbstractItemView>
#include <QDir>
#include <QLabel>
#include <QLineEdit>
#include <QToolButton>

#include <kdeversion.h>

//END Includes

KateFileBrowser::KateFileBrowser(Kate::MainWindow *mainWindow,
                                 QWidget * parent, const char * name)
  : KVBox (parent)
  , m_mainWindow(mainWindow)
{
  setObjectName(name);

  m_toolbar = new KToolBar(this);
  m_toolbar->setMovable(false);
  m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
  m_toolbar->setContextMenuPolicy(Qt::NoContextMenu);

  // includes some actions, but not hooked into the shortcut dialog atm
  m_actionCollection = new KActionCollection(this);
  m_actionCollection->addAssociatedWidget(this);

  KFilePlacesModel* model = new KFilePlacesModel(this);
  m_urlNavigator = new KUrlNavigator(model, KUrl(QDir::homePath()), this);
  connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), SLOT(updateDirOperator(const KUrl&)));

  m_dirOperator = new KDirOperator(KUrl(), this);
  m_dirOperator->setView(KFile::/* Simple */Detail);
  m_dirOperator->view()->setSelectionMode(QAbstractItemView::ExtendedSelection);
  m_dirOperator->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));

  // Mime filter for the KDirOperator
  QStringList filter;
  filter << "text/plain" << "text/html" << "inode/directory";
#if KDE_IS_VERSION(4, 4, 60)
  m_dirOperator->setNewFileMenuSupportedMimeTypes(filter);
#endif

  setFocusProxy(m_dirOperator);
  connect(m_dirOperator, SIGNAL(viewChanged(QAbstractItemView *)),
          this, SLOT(selectorViewChanged(QAbstractItemView *)));
  connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)),
          m_dirOperator, SLOT(setFocus()));
  // now all actions exist in dir operator and we can use them in the toolbar
  setupActions();
  setupToolbar();

  KHBox* filterBox = new KHBox(this);

  QLabel* filterLabel = new QLabel(i18n("Filter:"), filterBox);
  m_filter = new KHistoryComboBox(true, filterBox);
  filterLabel->setBuddy(m_filter);
  m_filter->setMaxCount(10);
  m_filter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));

  connect(m_filter, SIGNAL(editTextChanged(const QString&)),
          SLOT(slotFilterChange(const QString&)));
  connect(m_filter, SIGNAL(returnPressed(const QString&)),
          m_filter, SLOT(addToHistory(const QString&)));
  connect(m_filter, SIGNAL(returnPressed(const QString&)),
          m_dirOperator, SLOT(setFocus()));

  connect(m_dirOperator, SIGNAL(urlEntered(const KUrl&)),
          this, SLOT(updateUrlNavigator(const KUrl&)));

  // Connect the bookmark handler
  connect(m_bookmarkHandler, SIGNAL(openUrl(const QString&)),
          this, SLOT(setDir(const QString&)));

  m_filter->setWhatsThis(i18n("Enter a name filter to limit which files are displayed."));

  connect(m_dirOperator, SIGNAL(fileSelected(const KFileItem&)), this, SLOT(fileSelected(const KFileItem&)));
  connect(m_mainWindow, SIGNAL(viewChanged()), this, SLOT(autoSyncFolder()));
}

KateFileBrowser::~KateFileBrowser()
{
}
//END Constroctor/Destrctor

//BEGIN Public Methods
void KateFileBrowser::setupToolbar()
{
  KConfigGroup config(KGlobal::config(), "filebrowser");
  QStringList actions = config.readEntry( "toolbar actions", QStringList() );
  if ( actions.isEmpty() ) // default toolbar
    actions << "back" << "forward" << "bookmarks" << "sync_dir" << "configure";

  // remove all actions from the toolbar (there should be none)
  m_toolbar->clear();

  // now add all actions to the toolbar
  foreach (QString it, actions)
  {
    QAction *ac = 0;
    if (it.isEmpty()) continue;
    if (it == "bookmarks" || it == "sync_dir" || it == "configure")
      ac = actionCollection()->action(it);
    else
      ac = m_dirOperator->actionCollection()->action(it);

    if (ac)
      m_toolbar->addAction(ac);
  }
}

void KateFileBrowser::readSessionConfig(KConfigBase *config, const QString & name)
{
  KConfigGroup cgDir(config, name + ":dir");
  m_dirOperator->readConfig(cgDir);
  m_dirOperator->setView(KFile::Default);

  KConfigGroup cg(config, name);
  m_urlNavigator->setUrl(cg.readPathEntry("location", QDir::homePath()));
  setDir(cg.readPathEntry("location", QDir::homePath()));
  m_autoSyncFolder->setChecked(cg.readEntry("auto sync folder", false));
  m_filter->setHistoryItems(cg.readEntry("filter history", QStringList()), true);
}

void KateFileBrowser::writeSessionConfig(KConfigBase *config, const QString & name)
{
  KConfigGroup cgDir(config, name + ":dir");
  m_dirOperator->writeConfig(cgDir);

  KConfigGroup cg = KConfigGroup(config, name);
  cg.writePathEntry("location", m_urlNavigator->url().url());
  cg.writeEntry("auto sync folder", m_autoSyncFolder->isChecked());
  cg.writeEntry("filter history", m_filter->historyItems());
}

//END Public Methods

//BEGIN Public Slots

void KateFileBrowser::slotFilterChange(const QString & nf)
{
  QString f = nf.trimmed();
  const bool empty = f.isEmpty() || f == "*";

  if (empty) {
    m_dirOperator->clearFilter();
  } else {
    m_dirOperator->setNameFilter(f);
  }

  m_dirOperator->updateDir();
}

bool kateFileSelectorIsReadable (const KUrl& url)
{
  if (!url.isLocalFile())
    return true; // what else can we say?

  QDir dir(url.toLocalFile());
  return dir.exists ();
}

void KateFileBrowser::setDir(KUrl u)
{
  KUrl newurl;

  if (!u.isValid())
    newurl.setPath(QDir::homePath());
  else
    newurl = u;

  QString pathstr = newurl.path(KUrl::AddTrailingSlash);
  newurl.setPath(pathstr);

  if (!kateFileSelectorIsReadable (newurl))
    newurl.cd(QString::fromLatin1(".."));

  if (!kateFileSelectorIsReadable (newurl))
    newurl.setPath(QDir::homePath());

  m_dirOperator->setUrl(newurl, true);
}

//END Public Slots

//BEGIN Private Slots

void KateFileBrowser::fileSelected(const KFileItem & /*file*/)
{
  openSelectedFiles();
}

void KateFileBrowser::openSelectedFiles()
{
  const KFileItemList list = m_dirOperator->selectedItems();

  foreach (const KFileItem& item, list)
  {
    m_mainWindow->openUrl(item.url());
  }

  m_dirOperator->view()->selectionModel()->clear();
}

void KateFileBrowser::updateDirOperator(const KUrl& u)
{
  m_dirOperator->setUrl(u, true);
}

void KateFileBrowser::updateUrlNavigator(const KUrl& u)
{
  m_urlNavigator->setUrl(u);
}

void KateFileBrowser::setActiveDocumentDir()
{
//   kDebug(13001)<<"KateFileBrowser::setActiveDocumentDir()";
  KUrl u = activeDocumentUrl();
//   kDebug(13001)<<"URL: "<<u.prettyUrl();
  if (!u.isEmpty())
    setDir(u.upUrl());
//   kDebug(13001)<<"... setActiveDocumentDir() DONE!";
}

void KateFileBrowser::autoSyncFolder()
{
  if (m_autoSyncFolder->isChecked()) {
    setActiveDocumentDir();
  }
}

void KateFileBrowser::selectorViewChanged(QAbstractItemView * newView)
{
  newView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}

//END Private Slots

//BEGIN Protected

KUrl KateFileBrowser::activeDocumentUrl()
{
  KTextEditor::View *v = m_mainWindow->activeView();
  if (v)
    return v->document()->url();
  return KUrl();
}

void KateFileBrowser::setupActions()
{
  // bookmarks action!
  KActionMenu *acmBookmarks = new KActionMenu(KIcon("bookmarks"), i18n("Bookmarks"), this);
  acmBookmarks->setDelayed(false);
  m_bookmarkHandler = new KateBookmarkHandler(this, acmBookmarks->menu());
  acmBookmarks->setShortcutContext(Qt::WidgetWithChildrenShortcut);

  // action for synchronizing the dir operator with the current document path
  KAction* syncFolder = new KAction(this);
  syncFolder->setShortcutContext(Qt::WidgetWithChildrenShortcut);
  syncFolder->setText(i18n("Current Document Folder"));
  syncFolder->setIcon(KIcon("system-switch-user"));
  connect(syncFolder, SIGNAL(triggered()), this, SLOT(setActiveDocumentDir()));

  m_actionCollection->addAction("sync_dir", syncFolder);
  m_actionCollection->addAction("bookmarks", acmBookmarks);

  // section for settings menu
  KActionMenu *optionsMenu = new KActionMenu(KIcon("configure"), i18n("Options"), this);
  optionsMenu->setDelayed(false);
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("short view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("tree view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed tree view"));
  optionsMenu->addSeparator();
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("show hidden"));

  // action for synchronising the dir operator with the current document path
  m_autoSyncFolder = new KAction(this);
  m_autoSyncFolder->setCheckable(true);
  m_autoSyncFolder->setText(i18n("Automatically synchronize with current document"));
  m_autoSyncFolder->setIcon(KIcon("system-switch-user"));
  connect(m_autoSyncFolder, SIGNAL(triggered()), this, SLOT(autoSyncFolder()));
  optionsMenu->addAction(m_autoSyncFolder);

  m_actionCollection->addAction("configure", optionsMenu);
}
//END Protected

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>move ifdef<commit_after>/* This file is part of the KDE project
   Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
   Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
   Copyright (C) 2001 Anders Lund <anders.lund@lund.tdcadsl.dk>
   Copyright (C) 2007 Mirko Stocker <me@misto.ch>
   Copyright (C) 2009 Dominik Haumann <dhaumann kde org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

//BEGIN Includes
#include "katefilebrowser.h"
#include "katefilebrowser.moc"

#include "katebookmarkhandler.h"

#include <ktexteditor/document.h>
#include <ktexteditor/view.h>

#include <KActionCollection>
#include <KActionMenu>
#include <KConfigGroup>
#include <KDebug>
#include <KDirOperator>
#include <KFilePlacesModel>
#include <KHistoryComboBox>
#include <KLocale>
#include <KToolBar>
#include <KUrlNavigator>
#include <QAbstractItemView>
#include <QDir>
#include <QLabel>
#include <QLineEdit>
#include <QToolButton>

#include <kdeversion.h>

//END Includes

KateFileBrowser::KateFileBrowser(Kate::MainWindow *mainWindow,
                                 QWidget * parent, const char * name)
  : KVBox (parent)
  , m_mainWindow(mainWindow)
{
  setObjectName(name);

  m_toolbar = new KToolBar(this);
  m_toolbar->setMovable(false);
  m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
  m_toolbar->setContextMenuPolicy(Qt::NoContextMenu);

  // includes some actions, but not hooked into the shortcut dialog atm
  m_actionCollection = new KActionCollection(this);
  m_actionCollection->addAssociatedWidget(this);

  KFilePlacesModel* model = new KFilePlacesModel(this);
  m_urlNavigator = new KUrlNavigator(model, KUrl(QDir::homePath()), this);
  connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)), SLOT(updateDirOperator(const KUrl&)));

  m_dirOperator = new KDirOperator(KUrl(), this);
  m_dirOperator->setView(KFile::/* Simple */Detail);
  m_dirOperator->view()->setSelectionMode(QAbstractItemView::ExtendedSelection);
  m_dirOperator->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));

#if KDE_IS_VERSION(4, 4, 60)
  // Mime filter for the KDirOperator
  QStringList filter;
  filter << "text/plain" << "text/html" << "inode/directory";
  m_dirOperator->setNewFileMenuSupportedMimeTypes(filter);
#endif

  setFocusProxy(m_dirOperator);
  connect(m_dirOperator, SIGNAL(viewChanged(QAbstractItemView *)),
          this, SLOT(selectorViewChanged(QAbstractItemView *)));
  connect(m_urlNavigator, SIGNAL(urlChanged(const KUrl&)),
          m_dirOperator, SLOT(setFocus()));
  // now all actions exist in dir operator and we can use them in the toolbar
  setupActions();
  setupToolbar();

  KHBox* filterBox = new KHBox(this);

  QLabel* filterLabel = new QLabel(i18n("Filter:"), filterBox);
  m_filter = new KHistoryComboBox(true, filterBox);
  filterLabel->setBuddy(m_filter);
  m_filter->setMaxCount(10);
  m_filter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));

  connect(m_filter, SIGNAL(editTextChanged(const QString&)),
          SLOT(slotFilterChange(const QString&)));
  connect(m_filter, SIGNAL(returnPressed(const QString&)),
          m_filter, SLOT(addToHistory(const QString&)));
  connect(m_filter, SIGNAL(returnPressed(const QString&)),
          m_dirOperator, SLOT(setFocus()));

  connect(m_dirOperator, SIGNAL(urlEntered(const KUrl&)),
          this, SLOT(updateUrlNavigator(const KUrl&)));

  // Connect the bookmark handler
  connect(m_bookmarkHandler, SIGNAL(openUrl(const QString&)),
          this, SLOT(setDir(const QString&)));

  m_filter->setWhatsThis(i18n("Enter a name filter to limit which files are displayed."));

  connect(m_dirOperator, SIGNAL(fileSelected(const KFileItem&)), this, SLOT(fileSelected(const KFileItem&)));
  connect(m_mainWindow, SIGNAL(viewChanged()), this, SLOT(autoSyncFolder()));
}

KateFileBrowser::~KateFileBrowser()
{
}
//END Constroctor/Destrctor

//BEGIN Public Methods
void KateFileBrowser::setupToolbar()
{
  KConfigGroup config(KGlobal::config(), "filebrowser");
  QStringList actions = config.readEntry( "toolbar actions", QStringList() );
  if ( actions.isEmpty() ) // default toolbar
    actions << "back" << "forward" << "bookmarks" << "sync_dir" << "configure";

  // remove all actions from the toolbar (there should be none)
  m_toolbar->clear();

  // now add all actions to the toolbar
  foreach (QString it, actions)
  {
    QAction *ac = 0;
    if (it.isEmpty()) continue;
    if (it == "bookmarks" || it == "sync_dir" || it == "configure")
      ac = actionCollection()->action(it);
    else
      ac = m_dirOperator->actionCollection()->action(it);

    if (ac)
      m_toolbar->addAction(ac);
  }
}

void KateFileBrowser::readSessionConfig(KConfigBase *config, const QString & name)
{
  KConfigGroup cgDir(config, name + ":dir");
  m_dirOperator->readConfig(cgDir);
  m_dirOperator->setView(KFile::Default);

  KConfigGroup cg(config, name);
  m_urlNavigator->setUrl(cg.readPathEntry("location", QDir::homePath()));
  setDir(cg.readPathEntry("location", QDir::homePath()));
  m_autoSyncFolder->setChecked(cg.readEntry("auto sync folder", false));
  m_filter->setHistoryItems(cg.readEntry("filter history", QStringList()), true);
}

void KateFileBrowser::writeSessionConfig(KConfigBase *config, const QString & name)
{
  KConfigGroup cgDir(config, name + ":dir");
  m_dirOperator->writeConfig(cgDir);

  KConfigGroup cg = KConfigGroup(config, name);
  cg.writePathEntry("location", m_urlNavigator->url().url());
  cg.writeEntry("auto sync folder", m_autoSyncFolder->isChecked());
  cg.writeEntry("filter history", m_filter->historyItems());
}

//END Public Methods

//BEGIN Public Slots

void KateFileBrowser::slotFilterChange(const QString & nf)
{
  QString f = nf.trimmed();
  const bool empty = f.isEmpty() || f == "*";

  if (empty) {
    m_dirOperator->clearFilter();
  } else {
    m_dirOperator->setNameFilter(f);
  }

  m_dirOperator->updateDir();
}

bool kateFileSelectorIsReadable (const KUrl& url)
{
  if (!url.isLocalFile())
    return true; // what else can we say?

  QDir dir(url.toLocalFile());
  return dir.exists ();
}

void KateFileBrowser::setDir(KUrl u)
{
  KUrl newurl;

  if (!u.isValid())
    newurl.setPath(QDir::homePath());
  else
    newurl = u;

  QString pathstr = newurl.path(KUrl::AddTrailingSlash);
  newurl.setPath(pathstr);

  if (!kateFileSelectorIsReadable (newurl))
    newurl.cd(QString::fromLatin1(".."));

  if (!kateFileSelectorIsReadable (newurl))
    newurl.setPath(QDir::homePath());

  m_dirOperator->setUrl(newurl, true);
}

//END Public Slots

//BEGIN Private Slots

void KateFileBrowser::fileSelected(const KFileItem & /*file*/)
{
  openSelectedFiles();
}

void KateFileBrowser::openSelectedFiles()
{
  const KFileItemList list = m_dirOperator->selectedItems();

  foreach (const KFileItem& item, list)
  {
    m_mainWindow->openUrl(item.url());
  }

  m_dirOperator->view()->selectionModel()->clear();
}

void KateFileBrowser::updateDirOperator(const KUrl& u)
{
  m_dirOperator->setUrl(u, true);
}

void KateFileBrowser::updateUrlNavigator(const KUrl& u)
{
  m_urlNavigator->setUrl(u);
}

void KateFileBrowser::setActiveDocumentDir()
{
//   kDebug(13001)<<"KateFileBrowser::setActiveDocumentDir()";
  KUrl u = activeDocumentUrl();
//   kDebug(13001)<<"URL: "<<u.prettyUrl();
  if (!u.isEmpty())
    setDir(u.upUrl());
//   kDebug(13001)<<"... setActiveDocumentDir() DONE!";
}

void KateFileBrowser::autoSyncFolder()
{
  if (m_autoSyncFolder->isChecked()) {
    setActiveDocumentDir();
  }
}

void KateFileBrowser::selectorViewChanged(QAbstractItemView * newView)
{
  newView->setSelectionMode(QAbstractItemView::ExtendedSelection);
}

//END Private Slots

//BEGIN Protected

KUrl KateFileBrowser::activeDocumentUrl()
{
  KTextEditor::View *v = m_mainWindow->activeView();
  if (v)
    return v->document()->url();
  return KUrl();
}

void KateFileBrowser::setupActions()
{
  // bookmarks action!
  KActionMenu *acmBookmarks = new KActionMenu(KIcon("bookmarks"), i18n("Bookmarks"), this);
  acmBookmarks->setDelayed(false);
  m_bookmarkHandler = new KateBookmarkHandler(this, acmBookmarks->menu());
  acmBookmarks->setShortcutContext(Qt::WidgetWithChildrenShortcut);

  // action for synchronizing the dir operator with the current document path
  KAction* syncFolder = new KAction(this);
  syncFolder->setShortcutContext(Qt::WidgetWithChildrenShortcut);
  syncFolder->setText(i18n("Current Document Folder"));
  syncFolder->setIcon(KIcon("system-switch-user"));
  connect(syncFolder, SIGNAL(triggered()), this, SLOT(setActiveDocumentDir()));

  m_actionCollection->addAction("sync_dir", syncFolder);
  m_actionCollection->addAction("bookmarks", acmBookmarks);

  // section for settings menu
  KActionMenu *optionsMenu = new KActionMenu(KIcon("configure"), i18n("Options"), this);
  optionsMenu->setDelayed(false);
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("short view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("tree view"));
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("detailed tree view"));
  optionsMenu->addSeparator();
  optionsMenu->addAction(m_dirOperator->actionCollection()->action("show hidden"));

  // action for synchronising the dir operator with the current document path
  m_autoSyncFolder = new KAction(this);
  m_autoSyncFolder->setCheckable(true);
  m_autoSyncFolder->setText(i18n("Automatically synchronize with current document"));
  m_autoSyncFolder->setIcon(KIcon("system-switch-user"));
  connect(m_autoSyncFolder, SIGNAL(triggered()), this, SLOT(autoSyncFolder()));
  optionsMenu->addAction(m_autoSyncFolder);

  m_actionCollection->addAction("configure", optionsMenu);
}
//END Protected

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>//
//	Author:	Michael Cameron
//	Email:	chronokun@hotmail.com
//

// Libraries Include
#include "libraries.h"
// Local Includes
#include "objloader.h"
#include "brush.h"

static CObjLoader s_ObjLoader;

std::string StringFromBrush(const TBrush& _krBrush)
{
	std::stringstream ssOut;
	ssOut << "brush" << std::endl;
	ssOut << "\tvertices" << std::endl;
	ssOut << std::fixed;
	for(const TVector3d& krVertex : _krBrush.m_Positions)
	{
		ssOut << "\t\t" << krVertex.m_dX << " " << krVertex.m_dY << " " << krVertex.m_dZ << std::endl;
	}
	ssOut << "\tfaces" << std::endl;
	for(const std::vector<size_t>& krFace : _krBrush.m_Faces)
	{
		ssOut << "\t\t" << 0.0f << " " << 0.0f << " " << 1.0f << " " << 1.0f << " " << 0.0f;
		for(const size_t kIndex : krFace)
		{
			ssOut << " " << kIndex;
		}
		ssOut << std::endl;
	}

	return(ssOut.str());
}

int main()
{
	const bool kbLoaded = s_ObjLoader.LoadFile("monkey.obj");
	if(!kbLoaded)
	{
		return(2);
	}

	std::vector<TBrush> Brushes;
	for(size_t i = 0; i < s_ObjLoader.GetFaceCount(0); ++i)
	{
		std::vector<TVector3d> Face;
		s_ObjLoader.GetFace(Face, 0, i);
		Brushes.push_back(ExtrudeBrushFromFace(Face));
	}

	std::ofstream OutFile;
	OutFile.open("output.map");
	if(OutFile.is_open())
	{
		OutFile << "reflex map version 6\n"
				<< "entity\n"
				<< "\ttype WorldSpawn\n"
				<< "\tColourXRGB32 clearColor ffffff\n"
				<< "\tColourXRGB32 worldColor0 0\n"
				<< "\tColourXRGB32 worldColor1 0\n";

		for(const TBrush& krBrush : Brushes)
		{
			OutFile << StringFromBrush(krBrush);
		}
		OutFile.close();
	}
	else
	{
		return(1);
	}

	return(0);
}<commit_msg>Modified to take commandline arguments for file names.<commit_after>//
//	Author:	Michael Cameron
//	Email:	chronokun@hotmail.com
//

// Libraries Include
#include "libraries.h"
// Local Includes
#include "objloader.h"
#include "brush.h"

static CObjLoader s_ObjLoader;

std::string StringFromBrush(const TBrush& _krBrush)
{
	std::stringstream ssOut;
	ssOut << "brush" << std::endl;
	ssOut << "\tvertices" << std::endl;
	ssOut << std::fixed;
	for(const TVector3d& krVertex : _krBrush.m_Positions)
	{
		ssOut << "\t\t" << krVertex.m_dX << " " << krVertex.m_dY << " " << krVertex.m_dZ << std::endl;
	}
	ssOut << "\tfaces" << std::endl;
	for(const std::vector<size_t>& krFace : _krBrush.m_Faces)
	{
		ssOut << "\t\t" << 0.0f << " " << 0.0f << " " << 1.0f << " " << 1.0f << " " << 0.0f;
		for(const size_t kIndex : krFace)
		{
			ssOut << " " << kIndex;
		}
		ssOut << std::endl;
	}

	return(ssOut.str());
}

int main(const int _kiArgC, const char** _kppcArgv)
{
	// Check we have correct number of parameters
	if(_kiArgC < 3)
	{
		return(3);
	}

	const bool kbLoaded = s_ObjLoader.LoadFile(_kppcArgv[1]);
	if(!kbLoaded)
	{
		return(2);
	}

	std::vector<TBrush> Brushes;
	for(size_t i = 0; i < s_ObjLoader.GetFaceCount(0); ++i)
	{
		std::vector<TVector3d> Face;
		s_ObjLoader.GetFace(Face, 0, i);
		Brushes.push_back(ExtrudeBrushFromFace(Face));
	}

	std::ofstream OutFile;
	OutFile.open(_kppcArgv[2]);
	if(OutFile.is_open())
	{
		OutFile << "reflex map version 6\n"
				<< "entity\n"
				<< "\ttype WorldSpawn\n"
				<< "\tColourXRGB32 clearColor ffffff\n"
				<< "\tColourXRGB32 worldColor0 0\n"
				<< "\tColourXRGB32 worldColor1 0\n";

		for(const TBrush& krBrush : Brushes)
		{
			OutFile << StringFromBrush(krBrush);
		}
		OutFile.close();
	}
	else
	{
		return(1);
	}

	return(0);
}<|endoftext|>