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