serverlist.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include <fstream>
  17. #include <iostream>
  18. #include <sstream>
  19. #include <algorithm>
  20. #include "version.h"
  21. #include "settings.h"
  22. #include "serverlist.h"
  23. #include "filesys.h"
  24. #include "porting.h"
  25. #include "log.h"
  26. #include "network/networkprotocol.h"
  27. #include <json/json.h>
  28. #include "convert_json.h"
  29. #include "httpfetch.h"
  30. #include "util/string.h"
  31. namespace ServerList
  32. {
  33. std::string getFilePath()
  34. {
  35. std::string serverlist_file = g_settings->get("serverlist_file");
  36. std::string dir_path = "client" DIR_DELIM "serverlist" DIR_DELIM;
  37. fs::CreateDir(porting::path_user + DIR_DELIM "client");
  38. fs::CreateDir(porting::path_user + DIR_DELIM + dir_path);
  39. return porting::path_user + DIR_DELIM + dir_path + serverlist_file;
  40. }
  41. std::vector<ServerListSpec> getLocal()
  42. {
  43. std::string path = ServerList::getFilePath();
  44. std::string liststring;
  45. if (fs::PathExists(path)) {
  46. std::ifstream istream(path.c_str());
  47. if (istream.is_open()) {
  48. std::ostringstream ostream;
  49. ostream << istream.rdbuf();
  50. liststring = ostream.str();
  51. istream.close();
  52. }
  53. }
  54. return deSerialize(liststring);
  55. }
  56. std::vector<ServerListSpec> getOnline()
  57. {
  58. std::ostringstream geturl;
  59. u16 proto_version_min = CLIENT_PROTOCOL_VERSION_MIN;
  60. geturl << g_settings->get("serverlist_url") <<
  61. "/list?proto_version_min=" << proto_version_min <<
  62. "&proto_version_max=" << CLIENT_PROTOCOL_VERSION_MAX;
  63. Json::Value root = fetchJsonValue(geturl.str(), NULL);
  64. std::vector<ServerListSpec> server_list;
  65. if (!root.isObject()) {
  66. return server_list;
  67. }
  68. root = root["list"];
  69. if (!root.isArray()) {
  70. return server_list;
  71. }
  72. for (const Json::Value &i : root) {
  73. if (i.isObject()) {
  74. server_list.push_back(i);
  75. }
  76. }
  77. return server_list;
  78. }
  79. // Delete a server from the local favorites list
  80. bool deleteEntry(const ServerListSpec &server)
  81. {
  82. std::vector<ServerListSpec> serverlist = ServerList::getLocal();
  83. for (std::vector<ServerListSpec>::iterator it = serverlist.begin();
  84. it != serverlist.end();) {
  85. if ((*it)["address"] == server["address"] &&
  86. (*it)["port"] == server["port"]) {
  87. it = serverlist.erase(it);
  88. } else {
  89. ++it;
  90. }
  91. }
  92. std::string path = ServerList::getFilePath();
  93. std::ostringstream ss(std::ios_base::binary);
  94. ss << ServerList::serialize(serverlist);
  95. if (!fs::safeWriteToFile(path, ss.str()))
  96. return false;
  97. return true;
  98. }
  99. // Insert a server to the local favorites list
  100. bool insert(const ServerListSpec &server)
  101. {
  102. // Remove duplicates
  103. ServerList::deleteEntry(server);
  104. std::vector<ServerListSpec> serverlist = ServerList::getLocal();
  105. // Insert new server at the top of the list
  106. serverlist.insert(serverlist.begin(), server);
  107. std::string path = ServerList::getFilePath();
  108. std::ostringstream ss(std::ios_base::binary);
  109. ss << ServerList::serialize(serverlist);
  110. if (!fs::safeWriteToFile(path, ss.str()))
  111. return false;
  112. return true;
  113. }
  114. std::vector<ServerListSpec> deSerialize(const std::string &liststring)
  115. {
  116. std::vector<ServerListSpec> serverlist;
  117. std::istringstream stream(liststring);
  118. std::string line, tmp;
  119. while (std::getline(stream, line)) {
  120. std::transform(line.begin(), line.end(), line.begin(), ::toupper);
  121. if (line == "[SERVER]") {
  122. ServerListSpec server;
  123. std::getline(stream, tmp);
  124. server["name"] = tmp;
  125. std::getline(stream, tmp);
  126. server["address"] = tmp;
  127. std::getline(stream, tmp);
  128. server["port"] = tmp;
  129. std::getline(stream, tmp);
  130. server["description"] = tmp;
  131. serverlist.push_back(server);
  132. }
  133. }
  134. return serverlist;
  135. }
  136. const std::string serialize(const std::vector<ServerListSpec> &serverlist)
  137. {
  138. std::string liststring;
  139. for (const ServerListSpec &it : serverlist) {
  140. liststring += "[server]\n";
  141. liststring += it["name"].asString() + '\n';
  142. liststring += it["address"].asString() + '\n';
  143. liststring += it["port"].asString() + '\n';
  144. liststring += it["description"].asString() + '\n';
  145. liststring += '\n';
  146. }
  147. return liststring;
  148. }
  149. const std::string serializeJson(const std::vector<ServerListSpec> &serverlist)
  150. {
  151. Json::Value root;
  152. Json::Value list(Json::arrayValue);
  153. for (const ServerListSpec &it : serverlist) {
  154. list.append(it);
  155. }
  156. root["list"] = list;
  157. return fastWriteJson(root);
  158. }
  159. #if USE_CURL
  160. void sendAnnounce(AnnounceAction action,
  161. const u16 port,
  162. const std::vector<std::string> &clients_names,
  163. const double uptime,
  164. const u32 game_time,
  165. const float lag,
  166. const std::string &gameid,
  167. const std::string &mg_name,
  168. const std::vector<ModSpec> &mods,
  169. bool dedicated)
  170. {
  171. static const char *aa_names[] = {"start", "update", "delete"};
  172. Json::Value server;
  173. server["action"] = aa_names[action];
  174. server["port"] = port;
  175. if (g_settings->exists("server_address")) {
  176. server["address"] = g_settings->get("server_address");
  177. }
  178. if (action != AA_DELETE) {
  179. bool strict_checking = g_settings->getBool("strict_protocol_version_checking");
  180. server["name"] = g_settings->get("server_name");
  181. server["description"] = g_settings->get("server_description");
  182. server["version"] = g_version_string;
  183. server["proto_min"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MIN;
  184. server["proto_max"] = strict_checking ? LATEST_PROTOCOL_VERSION : SERVER_PROTOCOL_VERSION_MAX;
  185. server["url"] = g_settings->get("server_url");
  186. server["creative"] = g_settings->getBool("creative_mode");
  187. server["damage"] = g_settings->getBool("enable_damage");
  188. server["password"] = g_settings->getBool("disallow_empty_password");
  189. server["pvp"] = g_settings->getBool("enable_pvp");
  190. server["uptime"] = (int) uptime;
  191. server["game_time"] = game_time;
  192. server["clients"] = (int) clients_names.size();
  193. server["clients_max"] = g_settings->getU16("max_users");
  194. server["clients_list"] = Json::Value(Json::arrayValue);
  195. for (const std::string &clients_name : clients_names) {
  196. server["clients_list"].append(clients_name);
  197. }
  198. if (!gameid.empty())
  199. server["gameid"] = gameid;
  200. }
  201. if (action == AA_START) {
  202. server["dedicated"] = dedicated;
  203. server["rollback"] = g_settings->getBool("enable_rollback_recording");
  204. server["mapgen"] = mg_name;
  205. server["privs"] = g_settings->get("default_privs");
  206. server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0;
  207. server["mods"] = Json::Value(Json::arrayValue);
  208. for (const ModSpec &mod : mods) {
  209. server["mods"].append(mod.name);
  210. }
  211. actionstream << "Announcing to " << g_settings->get("serverlist_url") << std::endl;
  212. } else if (action == AA_UPDATE) {
  213. if (lag)
  214. server["lag"] = lag;
  215. }
  216. HTTPFetchRequest fetch_request;
  217. fetch_request.url = g_settings->get("serverlist_url") + std::string("/announce");
  218. fetch_request.post_fields["json"] = fastWriteJson(server);
  219. fetch_request.multipart = true;
  220. httpfetch_async(fetch_request);
  221. }
  222. #endif
  223. } // namespace ServerList