]> git.lizzy.rs Git - dragonfireclient.git/blob - builtin/mainmenu/serverlistmgr.lua
Merge pull request #35 from arydevy/patch-1
[dragonfireclient.git] / builtin / mainmenu / serverlistmgr.lua
1 --Minetest
2 --Copyright (C) 2020 rubenwardy
3 --
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 --
9 --This program is distributed in the hope that it will be useful,
10 --but WITHOUT ANY WARRANTY; without even the implied warranty of
11 --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 --GNU Lesser General Public License for more details.
13 --
14 --You should have received a copy of the GNU Lesser General Public License along
15 --with this program; if not, write to the Free Software Foundation, Inc.,
16 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 serverlistmgr = {}
19
20 --------------------------------------------------------------------------------
21 local function order_server_list(list)
22         local res = {}
23         --orders the favorite list after support
24         for i = 1, #list do
25                 local fav = list[i]
26                 if is_server_protocol_compat(fav.proto_min, fav.proto_max) then
27                         res[#res + 1] = fav
28                 end
29         end
30         for i = 1, #list do
31                 local fav = list[i]
32                 if not is_server_protocol_compat(fav.proto_min, fav.proto_max) then
33                         res[#res + 1] = fav
34                 end
35         end
36         return res
37 end
38
39 local public_downloading = false
40
41 --------------------------------------------------------------------------------
42 function serverlistmgr.sync()
43         if not serverlistmgr.servers then
44                 serverlistmgr.servers = {{
45                         name = fgettext("Loading..."),
46                         description = fgettext_ne("Try reenabling public serverlist and check your internet connection.")
47                 }}
48         end
49
50         local serverlist_url = core.settings:get("serverlist_url") or ""
51         if not core.get_http_api or serverlist_url == "" then
52                 serverlistmgr.servers = {{
53                         name = fgettext("Public server list is disabled"),
54                         description = ""
55                 }}
56                 return
57         end
58
59         if public_downloading then
60                 return
61         end
62         public_downloading = true
63
64         core.handle_async(
65                 function(param)
66                         local http = core.get_http_api()
67                         local url = ("%s/list?proto_version_min=%d&proto_version_max=%d"):format(
68                                 core.settings:get("serverlist_url"),
69                                 core.get_min_supp_proto(),
70                                 core.get_max_supp_proto())
71
72                         local response = http.fetch_sync({ url = url })
73                         if not response.succeeded then
74                                 return {}
75                         end
76
77                         local retval = core.parse_json(response.data)
78                         return retval and retval.list or {}
79                 end,
80                 nil,
81                 function(result)
82                         public_downloading = nil
83                         local favs = order_server_list(result)
84                         if favs[1] then
85                                 serverlistmgr.servers = favs
86                         end
87                         core.event_handler("Refresh")
88                 end
89         )
90 end
91
92 --------------------------------------------------------------------------------
93 local function get_favorites_path(folder)
94         local base = core.get_user_path() .. DIR_DELIM .. "client" .. DIR_DELIM .. "serverlist" .. DIR_DELIM
95         if folder then
96                 return base
97         end
98         return base .. core.settings:get("serverlist_file")
99 end
100
101 --------------------------------------------------------------------------------
102 local function save_favorites(favorites)
103         local filename = core.settings:get("serverlist_file")
104         -- If setting specifies legacy format change the filename to the new one
105         if filename:sub(#filename - 3):lower() == ".txt" then
106                 core.settings:set("serverlist_file", filename:sub(1, #filename - 4) .. ".json")
107         end
108
109         assert(core.create_dir(get_favorites_path(true)))
110         core.safe_file_write(get_favorites_path(), core.write_json(favorites))
111 end
112
113 --------------------------------------------------------------------------------
114 function serverlistmgr.read_legacy_favorites(path)
115         local file = io.open(path, "r")
116         if not file then
117                 return nil
118         end
119
120         local lines = {}
121         for line in file:lines() do
122                 lines[#lines + 1] = line
123         end
124         file:close()
125
126         local favorites = {}
127
128         local i = 1
129         while i < #lines do
130                 local function pop()
131                         local line = lines[i]
132                         i = i + 1
133                         return line and line:trim()
134                 end
135
136                 if pop():lower() == "[server]" then
137                         local name = pop()
138                         local address = pop()
139                         local port = tonumber(pop())
140                         local description = pop()
141
142                         if name == "" then
143                                 name = nil
144                         end
145
146                         if description == "" then
147                                 description = nil
148                         end
149
150                         if not address or #address < 3 then
151                                 core.log("warning", "Malformed favorites file, missing address at line " .. i)
152                         elseif not port or port < 1 or port > 65535 then
153                                 core.log("warning", "Malformed favorites file, missing port at line " .. i)
154                         elseif (name and name:upper() == "[SERVER]") or
155                                         (address and address:upper() == "[SERVER]") or
156                                         (description and description:upper() == "[SERVER]") then
157                                 core.log("warning", "Potentially malformed favorites file, overran at line " .. i)
158                         else
159                                 favorites[#favorites + 1] = {
160                                         name = name,
161                                         address = address,
162                                         port = port,
163                                         description = description
164                                 }
165                         end
166                 end
167         end
168
169         return favorites
170 end
171
172 --------------------------------------------------------------------------------
173 local function read_favorites()
174         local path = get_favorites_path()
175
176         -- If new format configured fall back to reading the legacy file
177         if path:sub(#path - 4):lower() == ".json" then
178                 local file = io.open(path, "r")
179                 if file then
180                         local json = file:read("*all")
181                         file:close()
182                         return core.parse_json(json)
183                 end
184
185                 path = path:sub(1, #path - 5) .. ".txt"
186         end
187
188         local favs = serverlistmgr.read_legacy_favorites(path)
189         if favs then
190                 save_favorites(favs)
191                 os.remove(path)
192         end
193         return favs
194 end
195
196 --------------------------------------------------------------------------------
197 local function delete_favorite(favorites, del_favorite)
198         for i=1, #favorites do
199                 local fav = favorites[i]
200
201                 if fav.address == del_favorite.address and fav.port == del_favorite.port then
202                         table.remove(favorites, i)
203                         return
204                 end
205         end
206 end
207
208 --------------------------------------------------------------------------------
209 function serverlistmgr.get_favorites()
210         if serverlistmgr.favorites then
211                 return serverlistmgr.favorites
212         end
213
214         serverlistmgr.favorites = {}
215
216         -- Add favorites, removing duplicates
217         local seen = {}
218         for _, fav in ipairs(read_favorites() or {}) do
219                 local key = ("%s:%d"):format(fav.address:lower(), fav.port)
220                 if not seen[key] then
221                         seen[key] = true
222                         serverlistmgr.favorites[#serverlistmgr.favorites + 1] = fav
223                 end
224         end
225
226         return serverlistmgr.favorites
227 end
228
229 --------------------------------------------------------------------------------
230 function serverlistmgr.add_favorite(new_favorite)
231         assert(type(new_favorite.port) == "number")
232
233         -- Whitelist favorite keys
234         new_favorite = {
235                 name = new_favorite.name,
236                 address = new_favorite.address,
237                 port = new_favorite.port,
238                 description = new_favorite.description,
239         }
240
241         local favorites = serverlistmgr.get_favorites()
242         delete_favorite(favorites, new_favorite)
243         table.insert(favorites, 1, new_favorite)
244         save_favorites(favorites)
245 end
246
247 --------------------------------------------------------------------------------
248 function serverlistmgr.delete_favorite(del_favorite)
249         local favorites = serverlistmgr.get_favorites()
250         delete_favorite(favorites, del_favorite)
251         save_favorites(favorites)
252 end