summaryrefslogtreecommitdiff
path: root/builtin/mainmenu/dlg_version_info.lua
blob: 568fca3f493c81479e2418e76a99bb4b8bbcad20 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
--[[
Minetest
Copyright (C) 2018-2020 SmallJoker, 2022 rubenwardy

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
]]

if not core.get_http_api then
	function check_new_version()
	end
	return
end

local function version_info_formspec(data)
	local cur_ver = core.get_version()
	local title = fgettext("A new $1 version is available", cur_ver.project)
	local message =
		fgettext("Installed version: $1\nNew version: $2\n" ..
				"Visit $3 to find out how to get the newest version and stay up to date" ..
				" with features and bugfixes.",
			cur_ver.string, data.new_version or "", data.url or "")

	local fs = {
		"formspec_version[3]",
		"size[12.8,7]",
		"style_type[label;textcolor=#0E0]",
		"label[0.5,0.8;", core.formspec_escape(title), "]",
		"textarea[0.4,1.6;12,3.4;;;",
			core.formspec_escape(message), "]",
		"container[0.4,5.8]",
		"button[0.0,0;4.0,0.8;version_check_visit;", fgettext("Visit website"), "]",
		"button[4.5,0;3.5,0.8;version_check_remind;", fgettext("Later"), "]",
		"button[8.5.5,0;3.5,0.8;version_check_never;", fgettext("Never"), "]",
		"container_end[]",
	}

	return table.concat(fs, "")
end

local function version_info_buttonhandler(this, fields)
	if fields.version_check_remind then
		-- Erase last known, user will be reminded again at next check
		core.settings:set("update_last_known", "")
		this:delete()
		return true
	end
	if fields.version_check_never then
		core.settings:set("update_last_checked", "disabled")
		this:delete()
		return true
	end
	if fields.version_check_visit then
		if type(this.data.url) == "string" then
			core.open_url(this.data.url)
		end
		this:delete()
		return true
	end

	return false
end

local function create_version_info_dlg(new_version, url)
	assert(type(new_version) == "string")
	assert(type(url) == "string")

	local retval = dialog_create("version_info",
		version_info_formspec,
		version_info_buttonhandler,
		nil)

	retval.data.new_version = new_version
	retval.data.url = url

	return retval
end

local function get_current_version_code()
	-- Format: Major.Minor.Patch
	-- Convert to MMMNNNPPP
	local cur_string = core.get_version().string
	local cur_major, cur_minor, cur_patch = cur_string:match("^(%d+).(%d+).(%d+)")

	if not cur_patch then
		core.log("error", "Failed to parse version numbers (invalid tag format?)")
		return
	end

	return (cur_major * 1000 + cur_minor) * 1000 + cur_patch
end

local function on_version_info_received(json)
	local maintab = ui.find_by_name("maintab")
	if maintab.hidden then
		-- Another dialog is open, abort.
		return
	end

	local known_update = tonumber(core.settings:get("update_last_known")) or 0

	-- Format: MMNNPPP (Major, Minor, Patch)
	local new_number = type(json.latest) == "table" and json.latest.version_code
	if type(new_number) ~= "number" then
		core.log("error", "Failed to read version number (invalid response?)")
		return
	end

	local cur_number = get_current_version_code()
	if new_number <= known_update or new_number < cur_number then
		return
	end

	-- Also consider updating from 1.2.3-dev to 1.2.3
	if new_number == cur_number and not core.get_version().is_dev then
		return
	end

	core.settings:set("update_last_known", tostring(new_number))

	-- Show version info dialog (once)
	maintab:hide()

	local version_info_dlg = create_version_info_dlg(json.latest.version, json.latest.url)
	version_info_dlg:set_parent(maintab)
	version_info_dlg:show()

	ui.update()
end

function check_new_version()
	local url = core.settings:get("update_information_url")
	if core.settings:get("update_last_checked") == "disabled" or
			url == "" then
		-- Never show any updates
		return
	end

	local time_now = os.time()
	local time_checked = tonumber(core.settings:get("update_last_checked")) or 0
	if time_now - time_checked < 2 * 24 * 3600 then
		-- Check interval of 2 entire days
		return
	end

	core.settings:set("update_last_checked", tostring(time_now))

	core.handle_async(function(params)
		local http = core.get_http_api()
		return http.fetch_sync(params)
	end, { url = url }, function(result)
		local json = result.succeeded and core.parse_json(result.data)
		if type(json) ~= "table" or not json.latest then
			core.log("error", "Failed to read JSON output from " .. url ..
					", status code = " .. result.code)
			return
		end

		on_version_info_received(json)
	end)
end