mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-17 11:28:16 +00:00
Merge branch 'feature/campaignd-refactoring'
Refactors most of campaignd's code to ease future feature additions and bug fixes, making the code slightly more organized and readable. No behavior changes expected or observed from the state previous to this merge.
This commit is contained in:
commit
52f71d900f
@ -1098,6 +1098,7 @@ if(ENABLE_CAMPAIGN_SERVER)
|
||||
set(campaignd_SRC
|
||||
network_worker.cpp # NEEDED when compiling with ANA support
|
||||
addon/validation.cpp
|
||||
campaign_server/addon_utils.cpp
|
||||
campaign_server/blacklist.cpp
|
||||
campaign_server/campaign_server.cpp
|
||||
server/input_stream.cpp
|
||||
|
@ -582,6 +582,7 @@ if env["host"] in ["x86_64-nacl", "i686-nacl"]:
|
||||
client_env.WesnothProgram("wesnoth", wesnoth_objects, have_client_prereqs)
|
||||
|
||||
campaignd_sources = Split("""
|
||||
campaign_server/addon_utils.cpp
|
||||
campaign_server/blacklist.cpp
|
||||
server/input_stream.cpp
|
||||
""")
|
||||
|
138
src/campaign_server/addon_utils.cpp
Normal file
138
src/campaign_server/addon_utils.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||
2013 - 2014 by Ignacio Riquelme Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "campaign_server/addon_utils.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
static lg::log_domain log_network("network");
|
||||
#define LOG_CS if (lg::err.dont_log(log_network)) ; else lg::err(log_network, false)
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::map<std::string, std::string> plain_string_map;
|
||||
|
||||
/**
|
||||
* Quick and dirty alternative to @a utils::interpolate_variables_into_string
|
||||
* that doesn't require formula AI code. It is definitely NOT safe for normal
|
||||
* use since it doesn't do strict checks on where variable placeholders
|
||||
* ("$foobar") end and doesn't support pipe ("|") terminators.
|
||||
*
|
||||
* @param str The format string.
|
||||
* @param symbols The symbols table.
|
||||
*/
|
||||
std::string fast_interpolate_variables_into_string(const std::string &str, const plain_string_map * const symbols)
|
||||
{
|
||||
std::string res = str;
|
||||
|
||||
if(symbols) {
|
||||
BOOST_FOREACH(const plain_string_map::value_type& sym, *symbols) {
|
||||
res = utils::replace(res, "$" + sym.first, sym.second);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace campaignd {
|
||||
|
||||
// Markup characters recognized by GUI1 code. These must be
|
||||
// the same as the constants defined in marked-up_text.cpp.
|
||||
const std::string illegal_markup_chars = "*`~{^}|@#<&";
|
||||
|
||||
std::string format_addon_feedback_url(const std::string& format, const config& params)
|
||||
{
|
||||
if(!format.empty() && !params.empty()) {
|
||||
plain_string_map escaped;
|
||||
|
||||
config::const_attr_itors attrs = params.attribute_range();
|
||||
|
||||
// Percent-encode parameter values for URL interpolation. This is
|
||||
// VERY important since otherwise people could e.g. alter query
|
||||
// strings from the format string.
|
||||
BOOST_FOREACH(const config::attribute& a, attrs) {
|
||||
escaped[a.first] = utils::urlencode(a.second.str());
|
||||
}
|
||||
|
||||
// FIXME: We cannot use utils::interpolate_variables_into_string
|
||||
// because it is implemented using a lot of formula AI junk
|
||||
// that really doesn't belong in campaignd.
|
||||
const std::string& res =
|
||||
fast_interpolate_variables_into_string(format, &escaped);
|
||||
|
||||
if(res != format) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// If we get here, that means that no interpolation took place; in
|
||||
// that case, the parameters table probably contains entries that
|
||||
// do not match the format string expectations.
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void find_translations(const config& base_dir, config& addon)
|
||||
{
|
||||
BOOST_FOREACH(const config &dir, base_dir.child_range("dir"))
|
||||
{
|
||||
if(dir["name"] == "LC_MESSAGES") {
|
||||
addon.add_child("translation")["language"] = base_dir["name"];
|
||||
} else {
|
||||
find_translations(dir, addon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_license(config& cfg)
|
||||
{
|
||||
config& dir = cfg.find_child("dir", "name", cfg["campaign_name"]);
|
||||
|
||||
// No top-level directory? Hm..
|
||||
if(!dir) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't add if it already exists.
|
||||
if(dir.find_child("file", "name", "COPYING.txt")
|
||||
|| dir.find_child("file", "name", "COPYING")
|
||||
|| dir.find_child("file", "name", "copying.txt")
|
||||
|| dir.find_child("file", "name", "Copying.txt")
|
||||
|| dir.find_child("file", "name", "COPYING.TXT"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy over COPYING.txt
|
||||
const std::string& contents = read_file("COPYING.txt");
|
||||
if (contents.empty()) {
|
||||
LOG_CS << "Could not find COPYING.txt, path is \"" << game_config::path << "\"\n";
|
||||
return;
|
||||
}
|
||||
|
||||
config& copying = dir.add_child("file");
|
||||
copying["name"] = "COPYING.txt";
|
||||
copying["contents"] = contents;
|
||||
}
|
||||
|
||||
} // end namespace campaignd
|
84
src/campaign_server/addon_utils.hpp
Normal file
84
src/campaign_server/addon_utils.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||
2013 - 2014 by Ignacio Riquelme Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef CAMPAIGN_SERVER_ADDON_UTILS_HPP_INCLUDED
|
||||
#define CAMPAIGN_SERVER_ADDON_UTILS_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
class config;
|
||||
|
||||
namespace campaignd {
|
||||
|
||||
/**
|
||||
* Markup characters recognized by GUI1 code.
|
||||
*
|
||||
* These must be the same as the constants defined in marked-up_text.cpp.
|
||||
*/
|
||||
extern const std::string illegal_markup_chars;
|
||||
|
||||
inline bool is_text_markup_char(char c)
|
||||
{
|
||||
return illegal_markup_chars.find(c) != std::string::npos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a feedback URL for an add-on.
|
||||
*
|
||||
* @param format The format string for the URL, presumably obtained
|
||||
* from the add-ons server identification.
|
||||
*
|
||||
* @param params The URL format parameters table.
|
||||
*
|
||||
* @return A string containing a feedback URL or an empty string if that
|
||||
* is not possible (e.g. empty or invalid @a format, empty
|
||||
* @a params table, or a result that is identical in content to
|
||||
* the @a format suggesting that the @a params table contains
|
||||
* incorrect data).
|
||||
*/
|
||||
std::string format_addon_feedback_url(const std::string& format, const config& params);
|
||||
|
||||
|
||||
/**
|
||||
* Scans an add-on archive directory for translations.
|
||||
*
|
||||
* Any subdirectories of @a base_dir containing a subdirectory named
|
||||
* 'LC_MESSAGES' are assumed to be translation dirs. The names of the
|
||||
* subdirectories thus located are recorded into the @a addon WML node in
|
||||
* [translation] children nodes like the following (comments included for
|
||||
* documentation purposes):
|
||||
*
|
||||
* @verbatim
|
||||
* [translation]
|
||||
* language="es" # translations/es/LC_MESSAGES/
|
||||
* [/translation]
|
||||
* [translation]
|
||||
* language="ja" # translations/ja/LC_MESSAGES/
|
||||
* [/translation]
|
||||
* @endverbatim
|
||||
*/
|
||||
void find_translations(const config& base_dir, config& addon);
|
||||
|
||||
/**
|
||||
* Adds a COPYING.txt file with the full text of the GNU GPL to an add-on.
|
||||
*
|
||||
* This only has an effect if the add-on archive @a cfg does not already
|
||||
* contain an equivalent file ('copying.txt', 'COPYING', etc.).
|
||||
*/
|
||||
void add_license(config& cfg);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
184
src/campaign_server/campaign_server.hpp
Normal file
184
src/campaign_server/campaign_server.hpp
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright (C) 2003 - 2014 by David White <dave@whitevine.net>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef CAMPAIGN_SERVER_HPP_INCLUDED
|
||||
#define CAMPAIGN_SERVER_HPP_INCLUDED
|
||||
|
||||
#include "campaign_server/blacklist.hpp"
|
||||
#include "network.hpp"
|
||||
#include "server/input_stream.hpp"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace campaignd {
|
||||
|
||||
/**
|
||||
* Legacy add-ons server.
|
||||
*/
|
||||
class server : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
explicit server(const std::string& cfg_file,
|
||||
size_t min_threads = 10,
|
||||
size_t max_threads = 0);
|
||||
~server();
|
||||
|
||||
/**
|
||||
* Runs the server request processing loop.
|
||||
*/
|
||||
void run();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Client request information object.
|
||||
*
|
||||
* Contains data and metadata associated with a single request from a
|
||||
* remote add-ons client, in a light-weight format for passing to request
|
||||
* handlers.
|
||||
*/
|
||||
struct request
|
||||
{
|
||||
const std::string& cmd;
|
||||
const config& cfg;
|
||||
|
||||
const network::connection sock;
|
||||
const std::string addr;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param reqcmd Request command.
|
||||
* @param reqcfg Request WML body.
|
||||
* @param reqsock Client socket that initiated the request.
|
||||
*
|
||||
* @note Neither @a reqcmd nor @a reqcfg are copied into instances, so
|
||||
* they are required to exist for as long as every @a request
|
||||
* instance that uses them.
|
||||
*/
|
||||
request(const std::string& reqcmd,
|
||||
const config& reqcfg,
|
||||
network::connection reqsock)
|
||||
: cmd(reqcmd)
|
||||
, cfg(reqcfg)
|
||||
, sock(reqsock)
|
||||
, addr(network::ip_address(sock))
|
||||
{}
|
||||
};
|
||||
|
||||
typedef boost::function<void (const request& req)> request_handler;
|
||||
typedef std::pair<std::string, request_handler> request_handler_info;
|
||||
|
||||
config cfg_;
|
||||
const std::string cfg_file_;
|
||||
|
||||
bool read_only_;
|
||||
int compress_level_; /**< Used for add-on archives. */
|
||||
|
||||
boost::scoped_ptr<input_stream> input_; /**< Server control socket. */
|
||||
|
||||
std::map<std::string, std::string> hooks_;
|
||||
std::vector<request_handler_info> handlers_;
|
||||
|
||||
std::string feedback_url_format_;
|
||||
|
||||
blacklist blacklist_;
|
||||
std::string blacklist_file_;
|
||||
|
||||
const network::manager net_manager_;
|
||||
const network::server_manager server_manager_;
|
||||
|
||||
/**
|
||||
* Reads the server configuration from WML.
|
||||
*
|
||||
* @return The configured listening port number.
|
||||
*/
|
||||
int load_config();
|
||||
|
||||
/**
|
||||
* Writes the server configuration WML back to disk.
|
||||
*/
|
||||
void write_config();
|
||||
|
||||
/**
|
||||
* Reads the add-ons upload blacklist from WML.
|
||||
*/
|
||||
void load_blacklist();
|
||||
|
||||
/**
|
||||
* Fires a hook script.
|
||||
*/
|
||||
void fire(const std::string& hook, const std::string& addon);
|
||||
|
||||
/** Retrieves the contents of the [campaigns] WML node. */
|
||||
const config& campaigns() const { return cfg_.child("campaigns"); }
|
||||
|
||||
/** Retrieves the contents of the [campaigns] WML node. */
|
||||
config& campaigns() { return cfg_.child("campaigns"); }
|
||||
|
||||
/** Retrieves the contents of the [server_info] WML node. */
|
||||
const config& server_info() const { return cfg_.child("server_info"); }
|
||||
|
||||
/** Retrieves the contents of the [server_info] WML node. */
|
||||
config& server_info() { return cfg_.child("server_info"); }
|
||||
|
||||
//
|
||||
// Request handling.
|
||||
//
|
||||
|
||||
/**
|
||||
* Registers client request handlers.
|
||||
*
|
||||
* This is called by the class constructor. Individual handlers must be
|
||||
* methods of this class that take a single parameter of type @a request
|
||||
* and they are registered using the @a register_handler method.
|
||||
*
|
||||
* When adding new handlers, make sure to update the implementation of
|
||||
* this method accordingly so they are recognized and invoked at runtime.
|
||||
*/
|
||||
void register_handlers();
|
||||
|
||||
/**
|
||||
* Registers a single request handler.
|
||||
*
|
||||
* @param cmd The request command, corresponding to the name of the [tag}
|
||||
* with the request body (e.g. "handle_request_terms").
|
||||
* @param func The request function. This should be a class method passed
|
||||
* as a @a boost::bind function object that takes a single
|
||||
* parameter of type @a request.
|
||||
*/
|
||||
void register_handler(const std::string& cmd, const request_handler& func);
|
||||
|
||||
void handle_request_campaign_list(const request&);
|
||||
void handle_request_campaign(const request&);
|
||||
void handle_request_terms(const request&);
|
||||
void handle_upload(const request&);
|
||||
void handle_delete(const request&);
|
||||
void handle_change_passphrase(const request&);
|
||||
|
||||
//
|
||||
// Generic responses.
|
||||
//
|
||||
|
||||
/** Send a client an informational message. */
|
||||
void send_message(const std::string& msg, network::connection sock);
|
||||
|
||||
/** Send a client an error message. */
|
||||
void send_error(const std::string& msg, network::connection sock);
|
||||
};
|
||||
|
||||
} // end namespace campaignd
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user