-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathadd_install_dlg_derived.cpp
More file actions
254 lines (219 loc) · 7.75 KB
/
Copy pathadd_install_dlg_derived.cpp
File metadata and controls
254 lines (219 loc) · 7.75 KB
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#include "interface_derived.hpp"
#include <thread>
#include "HTTP.hpp"
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <format>
using namespace std;
#define UPDATEEVT 2004
#define REENABLEEVT 2005
#define EXECUTEEVT 2006
wxDEFINE_EVENT(updateEvt, wxCommandEvent);
wxDEFINE_EVENT(reenableEvt, wxCommandEvent);
wxDEFINE_EVENT(executeEvt, wxCommandEvent);
//Declare events here
wxBEGIN_EVENT_TABLE(AddNewInstallDlg, wxDialog)
EVT_COMMAND(UPDATEEVT, updateEvt, AddNewInstallDlg::PopulateTable)
EVT_COMMAND(REENABLEEVT, reenableEvt, AddNewInstallDlg::Reenable)
EVT_COMMAND(EXECUTEEVT, executeEvt, AddNewInstallDlg::ExecuteProc)
EVT_BUTTON(wxID_FILE,AddNewInstallDlg::InstallSelected)
EVT_BUTTON(INSTALLVIAHUB,AddNewInstallDlg::InstallSelectedWithHub)
EVT_SEARCHCTRL_SEARCH_BTN(wxID_FIND,AddNewInstallDlg::Filter)
wxEND_EVENT_TABLE()
static inline string remove_quotes(const std::string& str){
return str.substr(1,str.length()-2);
}
AddNewInstallDlg::AddNewInstallDlg(wxWindow* parent) : AddNewInstallDlgBase(parent){
#if defined _WIN32
//high DPI scaling fixes
fitWindowMinSize(this);
#endif
// get all the versions available to install
std::thread th([&]{
this->GetAllVersions();
});
th.detach();
}
void AddNewInstallDlg::PopulateTable(wxCommandEvent&){
// populate the data view
PopulateWithFilter([](const version&){return true;});
installBtn->SetLabel("Install Selected");
installBtn->Enable();
installViaHubBtn->Enable();
installBtn->Fit();
installSearchSizer->Layout();
}
#define TRYCATCH 1
void AddNewInstallDlg::GetAllVersions(){
#ifndef __linux__
// version date info
unordered_map<string,string> versionDates;
{
#if TRYCATCH
try
#endif
{
auto r = fetch("https://symbolserver.unity3d.com/000Admin/history.txt");
if (r.code != 200){
wxMessageBox("Unable to access Unity version metadata", "Download error", wxOK | wxICON_ERROR);
}
else{
// parse the CSV
stringstream stream(r.text);
string str;
string last_date;
while(getline(stream,str,'\n')){
int i = 0;
stringstream line(str);
while(getline(line,str,',')){
i++;
if (i % 4 == 0){
last_date = str;
}
else if (i % 7 == 0){
versionDates.insert(make_pair(remove_quotes(str), last_date));
break;
}
}
}
// installation URLs
{
auto r = fetch("https://unity.com/releases/editor/archive");
// check if succeeded
if (r.code != 200){
wxMessageBox("Unable to access Unity versions", "Download error", wxOK | wxICON_ERROR);
}
else{
// get all the Unity versions
// they are prefixed with unityhub:// links
constexpr std::string_view match("unityhub://");
for(size_t i = 0; i < r.text.size(); i++){
std::string_view section(r.text.data() + i,match.size());
if (strncmp(r.text.data() + i, match.data(), match.size()) == 0){
// we have found a version, extract its data
auto begin = i + match.size();
auto end = std::min(r.text.find_first_of("\"", i + match.size()), r.text.find_first_of("\\", i + match.size()));
std::string_view versiondata(r.text.data() + begin,end-begin);
// get the version and hashcode
auto slashpos = versiondata.find_first_of("/");
if (slashpos == versiondata.npos){
continue;
}
auto version = string(string_view(versiondata.data(),slashpos));
if (versionDates.find(version) != versionDates.end()){
auto hashcode = string(string_view(versiondata.data() + slashpos + 1, versiondata.size() - slashpos - 1));
versions.emplace_back(version,hashcode, versionDates.at(version));
}
}
}
// post to main thread to update table
wxCommandEvent evt(updateEvt);
evt.SetId(UPDATEEVT);
wxPostEvent(this, evt);
}
}
}
}
#if TRYCATCH
catch(std::exception& e){
wxMessageBox(std::format("Network error: {}", e.what()), "Error", wxOK | wxICON_ERROR);
}
#endif
}
#endif
}
void AddNewInstallDlg::Filter(wxCommandEvent& evt){
// get filter string
auto filter = evt.GetString();
versionsListCtrl->DeleteAllItems();
PopulateWithFilter([&](const version& item) -> bool{
return item.name.find(filter) != string::npos;
});
}
void AddNewInstallDlg::PopulateWithFilter(const std::function<bool (const version &)> func){
for(const auto& version : versions){
if (func(version)){
wxVector<wxVariant> data;
data.push_back(version.name);
data.push_back(version.date);
versionsListCtrl->AppendItem(data,reinterpret_cast<wxUIntPtr>(&version));
}
}
}
void AddNewInstallDlg::InstallSelected(wxCommandEvent&){
#ifndef __linux__
// get the selected item
auto item = versionsListCtrl->GetSelection();
auto data = *(reinterpret_cast<version*>(versionsListCtrl->GetItemData(item)));
installBtn->Disable();
installBtn->SetLabel("Downloading...");
if (item.IsOk()){
thread th([=]{
// download the file
string url = "https://download.unity3d.com/download_unity/" + data.hashcode + "/UnityDownloadAssistant" +
#ifdef __APPLE__
".dmg";
#elif defined _WIN32
".exe";
#elif __linux__
#else
#error This platform is not supported.
#endif
auto r = fetch(url);
if (r.code != 200){
// TODO: post that download failed
throw runtime_error("Unable to download installer");
}
else{
// create the temp location if it does not exist
#if defined __APPLE__ || defined __linux__
int status = mkdir(cachedir.string().c_str(),S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#elif defined _WIN32
int status = mkdir(cachedir.string().c_str());
#endif
// write the file to temp location
auto outpath = std::format("{}{}{}.{}", cachedir.string(), "UnityDownloadAssistant", data.hashcode, installerExt);
ofstream outfile(outpath, std::ios::binary);
outfile.write(r.text.c_str(),r.text.size());
// open the file
wxCommandEvent lnevt(executeEvt);
#ifdef __APPLE__
lnevt.SetString(std::format("open \"{}\"", outpath));
#elif defined _WIN32
lnevt.SetString(std::format("\"{}\"", outpath));
#endif
lnevt.SetId(EXECUTEEVT);
wxPostEvent(this,lnevt);
wxCommandEvent evt(reenableEvt);
evt.SetId(REENABLEEVT);
wxPostEvent(this, evt);
}
});
th.detach();
}
else{
wxMessageBox("Select a version", "Error", wxOK | wxICON_ERROR);
}
#endif
}
void AddNewInstallDlg::InstallSelectedWithHub(wxCommandEvent &){
auto item = versionsListCtrl->GetSelection();
auto data = *(reinterpret_cast<version*>(versionsListCtrl->GetItemData(item)));
auto url = std::format("unityhub://{}/{}", data.name,data.hashcode);
wxLaunchDefaultBrowser(url);
}
void AddNewInstallDlg::Reenable(wxCommandEvent &){
installBtn->Enable();
installViaHubBtn->Enable();
installBtn->SetLabel("Install Selected");
}
void AddNewInstallDlg::ExecuteProc(wxCommandEvent& evt)
{
auto cmd = evt.GetString();
#ifdef _WIN32
ShellExecute(0, 0, cmd.c_str(), NULL, 0, SW_SHOW);
#else
launch_process(cmd.ToStdString());
#endif
}