Compare commits
2 commits
master
...
rng-improv
Author | SHA1 | Date | |
---|---|---|---|
|
d91b20d430 | ||
|
2a14872ae7 |
15 changed files with 1194 additions and 2 deletions
35
include/core/filedownload.hpp
Normal file
35
include/core/filedownload.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef _filedownload__hpp__included__
|
||||
#define _filedownload__hpp__included__
|
||||
|
||||
#include "library/threadtypes.hpp"
|
||||
#include "library/httpreq.hpp"
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
struct file_download
|
||||
{
|
||||
//Variables.
|
||||
std::string url;
|
||||
std::string target_slot;
|
||||
//Ctor
|
||||
file_download();
|
||||
~file_download();
|
||||
//Lauch.
|
||||
void do_async();
|
||||
void cancel();
|
||||
//Status.
|
||||
volatile bool finished; //This signals download finishing, call finish().
|
||||
std::string errormsg;
|
||||
http_async_request req;
|
||||
std::string statusmsg();
|
||||
cv_class cond;
|
||||
mutex_class m;
|
||||
//Internal.
|
||||
void _do_async();
|
||||
std::string tempname;
|
||||
std::string tempname2;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -122,6 +122,11 @@ std::string safe_filename(const std::string& str);
|
|||
*/
|
||||
std::string mangle_name(const std::string& orig);
|
||||
|
||||
/**
|
||||
* Return a new temporary file. The file will be created.
|
||||
*/
|
||||
std::string get_temp_file();
|
||||
|
||||
/**
|
||||
* Mix some entropy.
|
||||
*/
|
||||
|
|
|
@ -213,6 +213,10 @@ struct moviefile
|
|||
* returns: Length of the movie in nanoseconds.
|
||||
*/
|
||||
uint64_t get_movie_length() throw();
|
||||
/**
|
||||
* Return reference to memory slot.
|
||||
*/
|
||||
static moviefile& memref(const std::string& slot);
|
||||
private:
|
||||
void binary_io(std::ostream& stream) throw(std::bad_alloc, std::runtime_error);
|
||||
void binary_io(std::istream& stream, struct core_type& romtype) throw(std::bad_alloc, std::runtime_error);
|
||||
|
|
|
@ -632,6 +632,9 @@ private:
|
|||
core_region& region;
|
||||
};
|
||||
|
||||
//Register a sysregion to name mapping.
|
||||
void register_sysregion_mapping(std::string from, std::string to);
|
||||
std::string lookup_sysregion_mapping(std::string from);
|
||||
|
||||
//Set to true if new core is detected.
|
||||
extern bool new_core_flag;
|
||||
|
|
37
include/platform/wxwidgets/menu_upload.hpp
Normal file
37
include/platform/wxwidgets/menu_upload.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _plat_wxwidgets__menu_upload__hpp__included__
|
||||
#define _plat_wxwidgets__menu_upload__hpp__included__
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/wx.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
class upload_menu : public wxMenu
|
||||
{
|
||||
public:
|
||||
upload_menu(wxWindow* win, int wxid_low, int wxid_high);
|
||||
~upload_menu();
|
||||
void on_select(wxCommandEvent& e);
|
||||
struct upload_entry
|
||||
{
|
||||
std::string name;
|
||||
std::string url;
|
||||
enum _auth
|
||||
{
|
||||
AUTH_DH25519
|
||||
} auth;
|
||||
wxMenuItem* item; //Internally used.
|
||||
};
|
||||
std::set<unsigned> entries();
|
||||
upload_entry get_entry(unsigned num);
|
||||
void configure_entry(unsigned num, struct upload_entry entry);
|
||||
void delete_entry(unsigned num);
|
||||
private:
|
||||
void save();
|
||||
wxWindow* pwin;
|
||||
int wxid_range_low;
|
||||
int wxid_range_high;
|
||||
std::map<int, upload_entry> destinations;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef _plat_wxwidgets__window_mainwindow__hpp__included__
|
||||
#define _plat_wxwidgets__window_mainwindow__hpp__included__
|
||||
|
||||
#include "core/filedownload.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "platform/wxwidgets/window_status.hpp"
|
||||
#include "platform/wxwidgets/menu_recent.hpp"
|
||||
|
@ -55,6 +56,7 @@ public:
|
|||
recent_menu<recentfile_path>* recent_movies;
|
||||
recent_menu<recentfile_path>* recent_scripts;
|
||||
loadrom_menu* loadroms;
|
||||
file_download* download_in_progress;
|
||||
private:
|
||||
void do_load_rom_image(core_type* t);
|
||||
void handle_menu_click_cancelable(wxCommandEvent& e);
|
||||
|
|
170
src/core/filedownload.cpp
Normal file
170
src/core/filedownload.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
#include "core/filedownload.hpp"
|
||||
#include "core/misc.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/zip.hpp"
|
||||
#include "core/moviedata.hpp"
|
||||
#include "core/rom.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include <fstream>
|
||||
|
||||
namespace
|
||||
{
|
||||
void file_download_thread_trampoline(file_download* d)
|
||||
{
|
||||
d->_do_async();
|
||||
}
|
||||
|
||||
class file_download_handler : public http_request::output_handler
|
||||
{
|
||||
public:
|
||||
file_download_handler(const std::string& filename)
|
||||
{
|
||||
fp.open(filename, std::ios::binary);
|
||||
tsize = 0;
|
||||
}
|
||||
~file_download_handler()
|
||||
{
|
||||
}
|
||||
void header(const std::string& name, const std::string& content)
|
||||
{
|
||||
//Ignore headers.
|
||||
}
|
||||
void write(const char* source, size_t srcsize)
|
||||
{
|
||||
fp.write(source, srcsize);
|
||||
tsize += srcsize;
|
||||
}
|
||||
private:
|
||||
std::ofstream fp;
|
||||
size_t tsize;
|
||||
};
|
||||
}
|
||||
|
||||
file_download::file_download()
|
||||
{
|
||||
finished = false;
|
||||
req.ohandler = NULL;
|
||||
}
|
||||
|
||||
file_download::~file_download()
|
||||
{
|
||||
if(req.ohandler) delete req.ohandler;
|
||||
}
|
||||
|
||||
void file_download::cancel()
|
||||
{
|
||||
req.cancel();
|
||||
errormsg = "Canceled";
|
||||
finished = true;
|
||||
}
|
||||
|
||||
void file_download::do_async()
|
||||
{
|
||||
tempname = get_temp_file();
|
||||
req.ihandler = NULL;
|
||||
req.ohandler = new file_download_handler(tempname);
|
||||
req.verb = "GET";
|
||||
req.url = url;
|
||||
try {
|
||||
req.lauch_async();
|
||||
(new thread_class(file_download_thread_trampoline, this))->detach();
|
||||
} catch(std::exception& e) {
|
||||
req.cancel();
|
||||
umutex_class h(m);
|
||||
errormsg = e.what();
|
||||
finished = true;
|
||||
cond.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
std::string file_download::statusmsg()
|
||||
{
|
||||
int64_t dn, dt, un, ut;
|
||||
if(finished)
|
||||
return (stringfmt() << "Downloading finished").str();
|
||||
req.get_xfer_status(dn, dt, un, ut);
|
||||
if(dn == 0)
|
||||
return "Connecting...";
|
||||
else if(dt == 0)
|
||||
return (stringfmt() << "Downloading (" << dn << "/<unknown>)").str();
|
||||
else if(dn < dt)
|
||||
return (stringfmt() << "Downloading (" << (100 * dn / dt) << "%)").str();
|
||||
else
|
||||
return (stringfmt() << "Downloading finished").str();
|
||||
}
|
||||
|
||||
void file_download::_do_async()
|
||||
{
|
||||
while(!req.finished) {
|
||||
umutex_class h(req.m);
|
||||
req.finished_cond.wait(h);
|
||||
if(!req.finished)
|
||||
continue;
|
||||
if(req.errormsg != "") {
|
||||
remove(tempname.c_str());
|
||||
umutex_class h(m);
|
||||
errormsg = req.errormsg;
|
||||
finished = true;
|
||||
cond.notify_all();
|
||||
return;
|
||||
}
|
||||
}
|
||||
delete req.ohandler;
|
||||
req.ohandler = NULL;
|
||||
if(req.http_code > 299) {
|
||||
umutex_class h(m);
|
||||
errormsg = (stringfmt() << "Got HTTP error " << req.http_code).str();
|
||||
finished = true;
|
||||
cond.notify_all();
|
||||
}
|
||||
//Okay, we got the file.
|
||||
std::istream* s = NULL;
|
||||
try {
|
||||
zip_reader r(tempname);
|
||||
unsigned count = 0;
|
||||
for(auto i : r) {
|
||||
count++;
|
||||
}
|
||||
if(count == 1) {
|
||||
std::istream& s = r[*r.begin()];
|
||||
std::ofstream out(tempname2 = get_temp_file(), std::ios::binary);
|
||||
while(s) {
|
||||
char buf[4096];
|
||||
s.read(buf, sizeof(buf));
|
||||
out.write(buf, s.gcount());
|
||||
}
|
||||
delete &s;
|
||||
} else {
|
||||
tempname2 = tempname;
|
||||
}
|
||||
} catch(...) {
|
||||
if(s) delete s;
|
||||
tempname2 = tempname;
|
||||
}
|
||||
if(tempname != tempname2) remove(tempname.c_str());
|
||||
try {
|
||||
core_type* gametype = NULL;
|
||||
if(!our_rom.rtype->isnull())
|
||||
gametype = our_rom.rtype;
|
||||
else {
|
||||
moviefile::brief_info info(tempname2);
|
||||
auto sysregs = core_sysregion::find_matching(info.sysregion);
|
||||
for(auto i : sysregs)
|
||||
gametype = &i->get_type();
|
||||
}
|
||||
moviefile::memref(target_slot) = moviefile(tempname2, *gametype);
|
||||
remove(tempname2.c_str());
|
||||
} catch(std::exception& e) {
|
||||
remove(tempname2.c_str());
|
||||
umutex_class h(m);
|
||||
errormsg = e.what();
|
||||
finished = true;
|
||||
cond.notify_all();
|
||||
return;
|
||||
}
|
||||
//We are done!
|
||||
umutex_class h(m);
|
||||
finished = true;
|
||||
cond.notify_all();
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "library/serialization.hpp"
|
||||
#include "library/arch-detect.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
@ -24,6 +25,9 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <boost/filesystem.hpp>
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIBGCRYPT_SHA256
|
||||
#include <gcrypt.h>
|
||||
|
@ -385,6 +389,27 @@ void highrandom_256(uint8_t* buf)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string get_temp_file()
|
||||
{
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
char tname[512];
|
||||
strcpy(tname, "/tmp/lsnestmp_XXXXXX");
|
||||
int h = mkstemp(tname);
|
||||
if(h < 0)
|
||||
throw std::runtime_error("Failed to get new tempfile name");
|
||||
close(h);
|
||||
return tname;
|
||||
#else
|
||||
char tpath[512];
|
||||
char tname[512];
|
||||
if(!GetTempPathA(512, tpath))
|
||||
throw std::runtime_error("Failed to get new tempfile name");
|
||||
if(!GetTempFileNameA(tpath, "lsn", 0, tname))
|
||||
throw std::runtime_error("Failed to get new tempfile name");
|
||||
return tname;
|
||||
#endif
|
||||
}
|
||||
|
||||
function_ptr_command<const std::string&> macro_test(lsnes_cmd, "test-macro", "", "",
|
||||
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
|
||||
regex_results r = regex("([0-9]+)[ \t](.*)", args);
|
||||
|
|
|
@ -1035,3 +1035,8 @@ uint64_t moviefile::get_movie_length() throw()
|
|||
t += frames * _magic[STEP_W] + (frames * _magic[STEP_N] / _magic[BLOCK_FRAMES]);
|
||||
return t;
|
||||
}
|
||||
|
||||
moviefile& moviefile::memref(const std::string& slot)
|
||||
{
|
||||
return memory_saves[slot];
|
||||
}
|
||||
|
|
|
@ -1344,9 +1344,21 @@ again2:
|
|||
L.pushlstring(disasm);
|
||||
return 1;
|
||||
});
|
||||
|
||||
#else
|
||||
void snesdbg_on_break() {}
|
||||
void snesdbg_on_trace() {}
|
||||
#endif
|
||||
|
||||
struct oninit {
|
||||
oninit()
|
||||
{
|
||||
register_sysregion_mapping("snes_pal", "SNES");
|
||||
register_sysregion_mapping("snes_ntsc", "SNES");
|
||||
register_sysregion_mapping("bsx", "SNES");
|
||||
register_sysregion_mapping("bsxslotted", "SNES");
|
||||
register_sysregion_mapping("sufamiturbo", "SNES");
|
||||
register_sysregion_mapping("sgb_ntsc", "SGB");
|
||||
register_sysregion_mapping("sgb_pal", "SGB");
|
||||
}
|
||||
} _oninit;
|
||||
}
|
||||
|
|
|
@ -562,4 +562,13 @@ namespace
|
|||
return;
|
||||
instance->saveState(x, cmp_save);
|
||||
});
|
||||
|
||||
struct oninit {
|
||||
oninit()
|
||||
{
|
||||
register_sysregion_mapping("gdmg", "GB");
|
||||
register_sysregion_mapping("ggbc", "GBC");
|
||||
register_sysregion_mapping("ggbca", "GBC");
|
||||
}
|
||||
} _oninit;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,12 @@ namespace
|
|||
{
|
||||
bool install_handlers_automatically;
|
||||
|
||||
std::map<std::string, std::string>& sysreg_mapping()
|
||||
{
|
||||
static std::map<std::string, std::string> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
std::set<core_core*>& all_cores_set()
|
||||
{
|
||||
static std::set<core_core*> x;
|
||||
|
@ -546,6 +552,19 @@ std::set<core_sysregion*> core_sysregion::find_matching(const std::string& name)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void register_sysregion_mapping(std::string from, std::string to)
|
||||
{
|
||||
sysreg_mapping()[from] = to;
|
||||
}
|
||||
|
||||
std::string lookup_sysregion_mapping(std::string from)
|
||||
{
|
||||
if(sysreg_mapping().count(from))
|
||||
return sysreg_mapping()[from];
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
struct emucore_callbacks* ecore_callbacks;
|
||||
|
||||
bool new_core_flag = false;
|
||||
|
|
|
@ -37,7 +37,7 @@ wxeditor_action::wxeditor_action(wxWindow* parent, const std::string& label,
|
|||
|
||||
{
|
||||
params = _params;
|
||||
Centre();
|
||||
Centre();
|
||||
wxBoxSizer* top_s = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(top_s);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <wx/dnd.h>
|
||||
#include "platform/wxwidgets/menu_dump.hpp"
|
||||
#include "platform/wxwidgets/menu_upload.hpp"
|
||||
#include "platform/wxwidgets/platform.hpp"
|
||||
#include "platform/wxwidgets/loadsave.hpp"
|
||||
#include "platform/wxwidgets/window_mainwindow.hpp"
|
||||
|
@ -126,6 +127,9 @@ enum
|
|||
wxID_CHDIR,
|
||||
wxID_RLUA_FIRST,
|
||||
wxID_RLUA_LAST = wxID_RLUA_FIRST + 16,
|
||||
wxID_UPLOAD_FIRST,
|
||||
wxID_UPLOAD_LAST = wxID_UPLOAD_FIRST + 256,
|
||||
wxID_DOWNLOAD,
|
||||
};
|
||||
|
||||
|
||||
|
@ -157,6 +161,37 @@ namespace
|
|||
int64_t last_update = 0;
|
||||
thread_class* emulation_thread;
|
||||
|
||||
class download_timer : public wxTimer
|
||||
{
|
||||
public:
|
||||
download_timer(wxwin_mainwindow* main)
|
||||
{
|
||||
w = main;
|
||||
Start(50);
|
||||
}
|
||||
void Notify()
|
||||
{
|
||||
if(w->download_in_progress->finished) {
|
||||
w->update_statusbar(std::map<std::string, std::u32string>());
|
||||
auto old = w->download_in_progress;
|
||||
w->download_in_progress = NULL;
|
||||
if(old->errormsg != "") {
|
||||
show_message_ok(w, "Error downloading movie", old->errormsg,
|
||||
wxICON_EXCLAMATION);
|
||||
} else {
|
||||
platform::queue("load-movie $MEMORY:wxwidgets_download_tmp");
|
||||
}
|
||||
delete old;
|
||||
Stop();
|
||||
delete this;
|
||||
} else {
|
||||
w->update_statusbar(std::map<std::string, std::u32string>());
|
||||
}
|
||||
}
|
||||
private:
|
||||
wxwin_mainwindow* w;
|
||||
};
|
||||
|
||||
template<typename T> void runemufn_async(T fn)
|
||||
{
|
||||
platform::queue(functor_call_helper2<T>, new T(fn), false);
|
||||
|
@ -928,6 +963,7 @@ wxwin_mainwindow::wxwin_mainwindow()
|
|||
: wxFrame(NULL, wxID_ANY, getname(), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
{
|
||||
download_in_progress = NULL;
|
||||
Centre();
|
||||
mwindow = NULL;
|
||||
toplevel = new wxFlexGridSizer(1, 2, 0, 0);
|
||||
|
@ -950,6 +986,7 @@ wxwin_mainwindow::wxwin_mainwindow()
|
|||
menu_start_sub(wxT("Load"));
|
||||
menu_entry(wxID_LOAD_STATE, wxT("State..."));
|
||||
menu_entry(wxID_LOAD_MOVIE, wxT("Movie..."));
|
||||
menu_entry(wxID_DOWNLOAD, wxT("Download movie..."));
|
||||
if(loaded_library::call_library() != "") {
|
||||
menu_separator();
|
||||
menu_entry(wxID_LOAD_LIBRARY, towxstring(std::string("Load ") + loaded_library::call_library()));
|
||||
|
@ -980,6 +1017,8 @@ wxwin_mainwindow::wxwin_mainwindow()
|
|||
menu_entry(wxID_CANCEL_SAVES, wxT("Cancel pending saves"));
|
||||
menu_separator();
|
||||
menu_entry(wxID_CHDIR, wxT("Change working directory..."));
|
||||
menu_separator();
|
||||
menu_special_sub(wxT("Upload"), new upload_menu(this, wxID_UPLOAD_FIRST, wxID_UPLOAD_LAST));
|
||||
menu_end_sub();
|
||||
menu_start_sub(wxT("Close"));
|
||||
menu_entry(wxID_CLOSE_PROJECT, wxT("Project"));
|
||||
|
@ -1128,6 +1167,10 @@ std::u32string read_variable_map(const std::map<std::string, std::u32string>& va
|
|||
|
||||
void wxwin_mainwindow::update_statusbar(const std::map<std::string, std::u32string>& vars)
|
||||
{
|
||||
if(download_in_progress) {
|
||||
statusbar->SetStatusText(download_in_progress->statusmsg());
|
||||
return;
|
||||
}
|
||||
if(hashing_in_progress) {
|
||||
//TODO: Display this as a dialog.
|
||||
std::ostringstream s;
|
||||
|
@ -1609,6 +1652,17 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
|
|||
d->Destroy();
|
||||
chdir(path.c_str());
|
||||
messages << "Changed working directory to '" << path << "'" << std::endl;
|
||||
return;
|
||||
}
|
||||
case wxID_DOWNLOAD: {
|
||||
if(download_in_progress) return;
|
||||
filename = pick_text(this, "Download movie", "Enter URL to download");
|
||||
download_in_progress = new file_download();
|
||||
download_in_progress->url = filename;
|
||||
download_in_progress->target_slot = "wxwidgets_download_tmp";
|
||||
download_in_progress->do_async();
|
||||
new download_timer(this);
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
812
src/platform/wxwidgets/window-fileupload.cpp
Normal file
812
src/platform/wxwidgets/window-fileupload.cpp
Normal file
|
@ -0,0 +1,812 @@
|
|||
#include "platform/wxwidgets/platform.hpp"
|
||||
#include "platform/wxwidgets/menu_upload.hpp"
|
||||
#include "core/fileupload.hpp"
|
||||
#include "core/misc.hpp"
|
||||
#include "core/rom.hpp"
|
||||
#include "core/project.hpp"
|
||||
#include "core/moviedata.hpp"
|
||||
#include "library/skein.hpp"
|
||||
#include "library/zip.hpp"
|
||||
#include "library/json.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <wx/wx.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/combobox.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <boost/iostreams/categories.hpp>
|
||||
#include <boost/iostreams/copy.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/iostreams/stream_buffer.hpp>
|
||||
#include <boost/iostreams/filter/symmetric.hpp>
|
||||
#include <boost/iostreams/filter/zlib.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
|
||||
std::string pick_file(wxWindow* parent, const std::string& title, const std::string& startdir);
|
||||
|
||||
namespace
|
||||
{
|
||||
class wxeditor_uploadtarget : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxeditor_uploadtarget(wxWindow* parent);
|
||||
wxeditor_uploadtarget(wxWindow* parent, upload_menu::upload_entry entry);
|
||||
upload_menu::upload_entry get_entry();
|
||||
void generate_dh25519(wxCommandEvent& e);
|
||||
void on_ok(wxCommandEvent& e);
|
||||
void on_cancel(wxCommandEvent& e);
|
||||
void on_auth_sel(wxCommandEvent& e);
|
||||
void revalidate(wxCommandEvent& e);
|
||||
private:
|
||||
void dh25519_fill_box();
|
||||
void ctor_common();
|
||||
wxButton* ok;
|
||||
wxButton* cancel;
|
||||
wxTextCtrl* name;
|
||||
wxTextCtrl* url;
|
||||
wxComboBox* auth;
|
||||
wxPanel* dh25519_p;
|
||||
wxTextCtrl* dh25519_k;
|
||||
wxButton* dh25519_g;
|
||||
};
|
||||
|
||||
wxeditor_uploadtarget::wxeditor_uploadtarget(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, towxstring("lsnes: New upload target"))
|
||||
{
|
||||
ctor_common();
|
||||
wxCommandEvent e;
|
||||
on_auth_sel(e);
|
||||
}
|
||||
|
||||
wxeditor_uploadtarget::wxeditor_uploadtarget(wxWindow* parent, upload_menu::upload_entry entry)
|
||||
: wxDialog(parent, wxID_ANY, towxstring("lsnes: Edit upload target: " + entry.name))
|
||||
{
|
||||
ctor_common();
|
||||
name->SetValue(towxstring(entry.name));
|
||||
url->SetValue(towxstring(entry.url));
|
||||
switch(entry.auth) {
|
||||
case upload_menu::upload_entry::AUTH_DH25519:
|
||||
auth->SetSelection(0);
|
||||
wxCommandEvent e;
|
||||
on_auth_sel(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::dh25519_fill_box()
|
||||
{
|
||||
try {
|
||||
uint8_t rbuf[32];
|
||||
get_dh25519_pubkey(rbuf);
|
||||
char out[65];
|
||||
out[64] = 0;
|
||||
for(unsigned i = 0; i < 32; i++)
|
||||
sprintf(out + 2 * i, "%02x", rbuf[i]);
|
||||
dh25519_k->SetValue(towxstring(out));
|
||||
dh25519_g->Disable();
|
||||
} catch(...) {
|
||||
dh25519_k->SetValue(towxstring("(Not available)"));
|
||||
dh25519_g->Enable();
|
||||
}
|
||||
wxCommandEvent e;
|
||||
revalidate(e);
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::ctor_common()
|
||||
{
|
||||
ok = NULL;
|
||||
std::vector<wxString> auth_choices;
|
||||
Center();
|
||||
wxBoxSizer* top_s = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(top_s);
|
||||
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, towxstring("Name")), 0, wxGROW);
|
||||
top_s->Add(name = new wxTextCtrl(this, wxID_ANY, towxstring(""), wxDefaultPosition, wxSize(550, -1)), 0,
|
||||
wxGROW);
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, towxstring("URL")), 0, wxGROW);
|
||||
top_s->Add(url = new wxTextCtrl(this, wxID_ANY, towxstring(""), wxDefaultPosition, wxSize(550, -1)), 0,
|
||||
wxGROW);
|
||||
name->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxeditor_uploadtarget::revalidate), NULL,
|
||||
this);
|
||||
url->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxeditor_uploadtarget::revalidate), NULL,
|
||||
this);
|
||||
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, towxstring("Authentication")), 0, wxGROW);
|
||||
auth_choices.push_back(towxstring("dh25519"));
|
||||
top_s->Add(auth = new wxComboBox(this, wxID_ANY, auth_choices[0], wxDefaultPosition, wxDefaultSize,
|
||||
auth_choices.size(), &auth_choices[0], wxCB_READONLY), 0, wxGROW);
|
||||
|
||||
dh25519_p = new wxPanel(this, wxID_ANY);
|
||||
wxBoxSizer* dh25519_s = new wxBoxSizer(wxVERTICAL);
|
||||
dh25519_p->SetSizer(dh25519_s);
|
||||
wxStaticBox* dh25519_b = new wxStaticBox(dh25519_p, wxID_ANY, towxstring("Authentication parameters"));
|
||||
wxStaticBoxSizer* dh25519_s2 = new wxStaticBoxSizer(dh25519_b, wxVERTICAL);
|
||||
top_s->Add(dh25519_p, 0, wxGROW);
|
||||
dh25519_s->Add(dh25519_s2, 0, wxGROW);
|
||||
dh25519_s2->Add(new wxStaticText(dh25519_p, wxID_ANY, towxstring("Key")), 0, wxGROW);
|
||||
dh25519_s2->Add(dh25519_k = new wxTextCtrl(dh25519_p, wxID_ANY, towxstring(""), wxDefaultPosition,
|
||||
wxSize(550, -1), wxTE_READONLY), 0, wxGROW);
|
||||
dh25519_s2->Add(dh25519_g = new wxButton(dh25519_p, wxID_ANY, towxstring("Generate")), 0, wxGROW);
|
||||
dh25519_s->SetSizeHints(dh25519_p);
|
||||
dh25519_fill_box();
|
||||
|
||||
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
|
||||
pbutton_s->AddStretchSpacer();
|
||||
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
|
||||
pbutton_s->Add(cancel = new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxGROW);
|
||||
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtarget::on_ok), NULL, this);
|
||||
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtarget::on_cancel), NULL, this);
|
||||
top_s->Add(pbutton_s, 0, wxGROW);
|
||||
|
||||
wxCommandEvent e;
|
||||
revalidate(e);
|
||||
|
||||
top_s->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::on_ok(wxCommandEvent& e)
|
||||
{
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::on_cancel(wxCommandEvent& e)
|
||||
{
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::generate_dh25519(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string entropy = pick_text(this, "Enter garbage", "Mash some garbage from keyboard to derive\n"
|
||||
"key from:", "", true);
|
||||
uint8_t rbuf[192];
|
||||
highrandom_256(rbuf + 0);
|
||||
highrandom_256(rbuf + 32);
|
||||
std::vector<char> x;
|
||||
x.resize(entropy.length());
|
||||
std::copy(entropy.begin(), entropy.end(), x.begin());
|
||||
skein_hash h(skein_hash::PIPE_1024, 1024);
|
||||
h.write((uint8_t*)&x[0], x.size());
|
||||
h.read((uint8_t*)rbuf + 64);
|
||||
{
|
||||
std::ofstream fp(get_config_path() + "/dh25519.key", std::ios::binary);
|
||||
if(!fp) throw std::runtime_error("Can't open keyfile");
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
chmod((get_config_path() + "/dh25519.key").c_str(), 0600);
|
||||
#endif
|
||||
fp.write((char*)rbuf, 192);
|
||||
if(!fp) throw std::runtime_error("Can't write keyfile");
|
||||
}
|
||||
dh25519_fill_box();
|
||||
} catch(canceled_exception& e) {
|
||||
return;
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Generate keys error", std::string("Error generating keys:") + e.what(),
|
||||
wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::on_auth_sel(wxCommandEvent& e)
|
||||
{
|
||||
dh25519_p->Show(false);
|
||||
switch(auth->GetSelection()) {
|
||||
case 0:
|
||||
dh25519_p->Show(true);
|
||||
break;
|
||||
}
|
||||
revalidate(e);
|
||||
Fit();
|
||||
}
|
||||
|
||||
upload_menu::upload_entry wxeditor_uploadtarget::get_entry()
|
||||
{
|
||||
upload_menu::upload_entry ent;
|
||||
ent.name = tostdstring(name->GetValue());
|
||||
ent.url = tostdstring(url->GetValue());
|
||||
ent.auth = upload_menu::upload_entry::AUTH_DH25519;
|
||||
switch(auth->GetSelection()) {
|
||||
case 0:
|
||||
ent.auth = upload_menu::upload_entry::AUTH_DH25519;
|
||||
break;
|
||||
}
|
||||
return ent;
|
||||
}
|
||||
|
||||
void wxeditor_uploadtarget::revalidate(wxCommandEvent& e)
|
||||
{
|
||||
bool valid = true;
|
||||
if(!name || (name->GetValue().Length() == 0)) valid = false;
|
||||
std::string URL = url ? tostdstring(url->GetValue()) : "";
|
||||
if(!regex_match("https?://(([!$&'()*+,;=:A-Za-z0-9._~-]|%[0-9A-Fa-f][0-9A-Fa-f])+|\\[v[0-9A-Fa-f]\\."
|
||||
"([!$&'()*+,;=:A-Za-z0-9._~-]|%[0-9A-Fa-f][0-9A-Fa-f])+\\]|\\[[0-9A-Fa-f:]+\\])"
|
||||
"(/([!$&'()*+,;=:A-Za-z0-9._~@-]|%[0-9A-Fa-f][0-9A-Fa-f])+)*", URL)) valid = false;
|
||||
if(!auth || (auth->GetSelection() == 0 && dh25519_g->IsEnabled())) valid = false;
|
||||
if(ok) ok->Enable(valid);
|
||||
}
|
||||
|
||||
class wxeditor_uploadtargets : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxeditor_uploadtargets(wxWindow* parent, upload_menu* menu);
|
||||
void on_ok(wxCommandEvent& e);
|
||||
void on_add(wxCommandEvent& e);
|
||||
void on_modify(wxCommandEvent& e);
|
||||
void on_remove(wxCommandEvent& e);
|
||||
void on_list_sel(wxCommandEvent& e);
|
||||
private:
|
||||
void refresh();
|
||||
upload_menu* umenu;
|
||||
std::map<int, unsigned> id_map;
|
||||
wxListBox* list;
|
||||
wxButton* ok;
|
||||
wxButton* add;
|
||||
wxButton* modify;
|
||||
wxButton* _delete;
|
||||
};
|
||||
|
||||
wxeditor_uploadtargets::wxeditor_uploadtargets(wxWindow* parent, upload_menu* menu)
|
||||
: wxDialog(parent, wxID_ANY, towxstring("lsnes: Configure upload targets"), wxDefaultPosition,
|
||||
wxSize(400, 500))
|
||||
{
|
||||
umenu = menu;
|
||||
Center();
|
||||
wxBoxSizer* top_s = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(top_s);
|
||||
|
||||
top_s->Add(list = new wxListBox(this, wxID_ANY), 1, wxGROW);
|
||||
list->Connect(wxEVT_COMMAND_LISTBOX_SELECTED,
|
||||
wxCommandEventHandler(wxeditor_uploadtargets::on_list_sel), NULL, this);
|
||||
|
||||
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
|
||||
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
|
||||
pbutton_s->AddStretchSpacer();
|
||||
pbutton_s->Add(add = new wxButton(this, wxID_ADD, wxT("Add")), 0, wxGROW);
|
||||
pbutton_s->Add(modify = new wxButton(this, wxID_EDIT, wxT("Modify")), 0, wxGROW);
|
||||
pbutton_s->Add(_delete = new wxButton(this, wxID_DELETE, wxT("Delete")), 0, wxGROW);
|
||||
modify->Enable(false);
|
||||
_delete->Enable(false);
|
||||
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtargets::on_ok), NULL, this);
|
||||
add->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtargets::on_add), NULL, this);
|
||||
modify->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtargets::on_modify), NULL, this);
|
||||
_delete->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploadtargets::on_remove), NULL, this);
|
||||
top_s->Add(pbutton_s, 0, wxGROW);
|
||||
|
||||
refresh();
|
||||
top_s->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::on_ok(wxCommandEvent& e)
|
||||
{
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::on_add(wxCommandEvent& e)
|
||||
{
|
||||
auto f = new wxeditor_uploadtarget(this);
|
||||
int r = f->ShowModal();
|
||||
if(r == wxID_OK) {
|
||||
unsigned ent = 0;
|
||||
auto used = umenu->entries();
|
||||
while(used.count(ent)) ent++;
|
||||
umenu->configure_entry(ent, f->get_entry());
|
||||
}
|
||||
f->Destroy();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::on_modify(wxCommandEvent& e)
|
||||
{
|
||||
auto s = list->GetSelection();
|
||||
if(s == wxNOT_FOUND) return;
|
||||
if(!id_map.count(s)) return;
|
||||
auto f = new wxeditor_uploadtarget(this, umenu->get_entry(id_map[s]));
|
||||
int r = f->ShowModal();
|
||||
if(r == wxID_OK)
|
||||
umenu->configure_entry(id_map[s], f->get_entry());
|
||||
f->Destroy();
|
||||
refresh();
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::on_remove(wxCommandEvent& e)
|
||||
{
|
||||
auto s = list->GetSelection();
|
||||
if(s == wxNOT_FOUND) return;
|
||||
if(!id_map.count(s)) return;
|
||||
unsigned id = id_map[s];
|
||||
umenu->delete_entry(id);
|
||||
refresh();
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::on_list_sel(wxCommandEvent& e)
|
||||
{
|
||||
auto s = list->GetSelection();
|
||||
modify->Enable(s != wxNOT_FOUND);
|
||||
_delete->Enable(s != wxNOT_FOUND);
|
||||
}
|
||||
|
||||
void wxeditor_uploadtargets::refresh()
|
||||
{
|
||||
auto ents = umenu->entries();
|
||||
auto sel = list->GetSelection();
|
||||
auto sel_id = id_map.count(sel) ? id_map[sel] : 0xFFFFFFFFU;
|
||||
|
||||
list->Clear();
|
||||
id_map.clear();
|
||||
int num = 0;
|
||||
for(auto i : ents) {
|
||||
auto ent = umenu->get_entry(i);
|
||||
list->Append(towxstring(ent.name));
|
||||
id_map[num++] = i;
|
||||
}
|
||||
|
||||
//Try to keep selection.
|
||||
if(sel_id != 0xFFFFFFFFU) {
|
||||
int x = wxNOT_FOUND;
|
||||
for(auto i : id_map)
|
||||
if(i.second == sel_id)
|
||||
x = i.first;
|
||||
if(x != wxNOT_FOUND)
|
||||
list->SetSelection(x);
|
||||
} else if(sel < list->GetCount())
|
||||
list->SetSelection(sel);
|
||||
}
|
||||
|
||||
class wxeditor_uploaddialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxeditor_uploaddialog(wxWindow* parent, upload_menu::upload_entry entry);
|
||||
void on_ok(wxCommandEvent& e);
|
||||
void on_cancel(wxCommandEvent& e);
|
||||
void on_source_sel(wxCommandEvent& e);
|
||||
void on_file_sel(wxCommandEvent& e);
|
||||
void timer_tick();
|
||||
private:
|
||||
struct _timer : public wxTimer
|
||||
{
|
||||
_timer(wxeditor_uploaddialog* _dialog) { dialog = _dialog; start(); }
|
||||
void start() { Start(500); }
|
||||
void stop() { Stop(); }
|
||||
void Notify()
|
||||
{
|
||||
dialog->timer_tick();
|
||||
}
|
||||
wxeditor_uploaddialog* dialog;
|
||||
}* timer;
|
||||
struct _games_output_handler : public http_request::output_handler {
|
||||
~_games_output_handler()
|
||||
{
|
||||
}
|
||||
void header(const std::string& name, const std::string& cotent)
|
||||
{
|
||||
//No-op.
|
||||
}
|
||||
void write(const char* source, size_t srcsize)
|
||||
{
|
||||
std::string x(source, srcsize);
|
||||
while(x.find_first_of("\n") < x.length()) {
|
||||
size_t split = x.find_first_of("\n");
|
||||
std::string line = x.substr(0, split);
|
||||
x = x.substr(split + 1);
|
||||
incomplete_line += line;
|
||||
while(incomplete_line.length() > 0 &&
|
||||
incomplete_line[incomplete_line.length() - 1] == '\r')
|
||||
incomplete_line = incomplete_line.substr(0, incomplete_line.length() - 1);
|
||||
choices.insert(incomplete_line);
|
||||
incomplete_line = "";
|
||||
}
|
||||
if(x != "") incomplete_line += x;
|
||||
|
||||
}
|
||||
void flush()
|
||||
{
|
||||
if(incomplete_line != "") choices.insert(incomplete_line);
|
||||
}
|
||||
std::string incomplete_line;
|
||||
std::set<std::string> choices;
|
||||
} games_output_handler;
|
||||
wxTextCtrl* status;
|
||||
wxTextCtrl* filename;
|
||||
wxTextCtrl* title;
|
||||
wxTextCtrl* description;
|
||||
wxComboBox* game;
|
||||
wxRadioButton* current;
|
||||
wxRadioButton* file;
|
||||
wxTextCtrl* ufilename;
|
||||
wxButton* file_select;
|
||||
wxGauge* progress;
|
||||
wxCheckBox* hidden;
|
||||
wxButton* ok;
|
||||
wxButton* cancel;
|
||||
file_upload* upload;
|
||||
http_async_request* games_req;
|
||||
upload_menu::upload_entry _entry;
|
||||
};
|
||||
|
||||
wxeditor_uploaddialog::wxeditor_uploaddialog(wxWindow* parent, upload_menu::upload_entry entry)
|
||||
: wxDialog(parent, wxID_ANY, towxstring("lsnes: Upload file: " + entry.name), wxDefaultPosition,
|
||||
wxSize(-1, -1))
|
||||
{
|
||||
_entry = entry;
|
||||
upload = NULL;
|
||||
Centre();
|
||||
wxBoxSizer* top_s = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(top_s);
|
||||
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Filename:")), 0, wxGROW);
|
||||
top_s->Add(filename = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(550, -1)), 0,
|
||||
wxGROW);
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Title:")), 0, wxGROW);
|
||||
top_s->Add(title = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(550, -1)), 0, wxGROW);
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Description:")), 0, wxGROW);
|
||||
top_s->Add(description = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(550, 300),
|
||||
wxTE_MULTILINE), 0, wxGROW);
|
||||
top_s->Add(new wxStaticText(this, wxID_ANY, wxT("Game:")), 0, wxGROW);
|
||||
top_s->Add(game = new wxComboBox(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL,
|
||||
wxCB_READONLY), 0, wxGROW);
|
||||
game->Append(towxstring("(default)"));
|
||||
game->SetSelection(0);
|
||||
top_s->Add(hidden = new wxCheckBox(this, wxID_ANY, wxT("Hidden")), 0, wxGROW);
|
||||
|
||||
top_s->Add(current = new wxRadioButton(this, wxID_ANY, wxT("Current movie"), wxDefaultPosition, wxDefaultSize,
|
||||
wxRB_GROUP), 0, wxGROW);
|
||||
top_s->Add(file = new wxRadioButton(this, wxID_ANY, wxT("Specified file:")), 0, wxGROW);
|
||||
current->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
|
||||
wxCommandEventHandler(wxeditor_uploaddialog::on_source_sel), NULL, this);
|
||||
file->Connect(wxEVT_COMMAND_RADIOBUTTON_SELECTED,
|
||||
wxCommandEventHandler(wxeditor_uploaddialog::on_source_sel), NULL, this);
|
||||
if(!our_rom.rtype || our_rom.rtype->isnull()) {
|
||||
current->Enable(false);
|
||||
file->SetValue(true);
|
||||
}
|
||||
|
||||
wxBoxSizer* file_s = new wxBoxSizer(wxHORIZONTAL);
|
||||
file_s->Add(ufilename = new wxTextCtrl(this, wxID_ANY, wxT("")), 1, wxGROW);
|
||||
file_s->Add(file_select = new wxButton(this, wxID_ANY, wxT("...")), 0, wxGROW);
|
||||
top_s->Add(file_s, 0, wxGROW);
|
||||
file_select->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploaddialog::on_file_sel), NULL, this);
|
||||
ufilename->Enable(file->GetValue());
|
||||
file_select->Enable(file->GetValue());
|
||||
|
||||
top_s->Add(status = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(550, 300),
|
||||
wxTE_READONLY | wxTE_MULTILINE), 0, wxGROW);
|
||||
top_s->Add(progress = new wxGauge(this, wxID_ANY, 1000000, wxDefaultPosition, wxSize(-1, 15),
|
||||
wxGA_HORIZONTAL), 0, wxGROW);
|
||||
|
||||
status->AppendText(wxT("Obtaining list of games...\n"));
|
||||
games_req = new http_async_request();
|
||||
games_req->verb = "GET";
|
||||
games_req->url = entry.url + "/games";
|
||||
games_req->ihandler = NULL;
|
||||
games_req->ohandler = &games_output_handler;
|
||||
games_req->lauch_async();
|
||||
|
||||
timer = new _timer(this);
|
||||
|
||||
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
|
||||
pbutton_s->AddStretchSpacer();
|
||||
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("Upload")), 0, wxGROW);
|
||||
ok->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploaddialog::on_ok), NULL, this);
|
||||
pbutton_s->Add(cancel = new wxButton(this, wxID_OK, wxT("Cancel")), 0, wxGROW);
|
||||
cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_uploaddialog::on_cancel), NULL, this);
|
||||
top_s->Add(pbutton_s, 0, wxGROW);
|
||||
top_s->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxeditor_uploaddialog::timer_tick()
|
||||
{
|
||||
if(upload) {
|
||||
for(auto i : upload->get_messages()) {
|
||||
status->AppendText(towxstring(i + "\n"));
|
||||
}
|
||||
if(upload->finished) {
|
||||
delete upload;
|
||||
upload = NULL;
|
||||
cancel->SetLabel(wxT("Close"));
|
||||
} else {
|
||||
auto prog = upload->get_progress_ppm();
|
||||
if(prog < 0)
|
||||
progress->Pulse();
|
||||
else {
|
||||
progress->SetRange(1000000);
|
||||
progress->SetValue(prog);
|
||||
}
|
||||
}
|
||||
} else if(games_req) {
|
||||
progress->Pulse();
|
||||
if(games_req->finished) {
|
||||
std::string msg;
|
||||
games_output_handler.flush();
|
||||
if(games_req->errormsg != "") {
|
||||
msg = (stringfmt() << "Error getting list of games: " << (games_req->errormsg)).str();
|
||||
} else if(games_req->http_code != 200) {
|
||||
msg = (stringfmt() << "Got unexpected HTTP status " << (games_req->http_code)).str();
|
||||
} else {
|
||||
for(auto i : games_output_handler.choices)
|
||||
game->Append(towxstring(i));
|
||||
msg = "Got list of games.";
|
||||
}
|
||||
status->AppendText(towxstring(msg + "\n"));
|
||||
delete games_req;
|
||||
games_req = NULL;
|
||||
wxCommandEvent e;
|
||||
on_source_sel(e);
|
||||
}
|
||||
} else {
|
||||
if(progress) {
|
||||
progress->SetRange(1000000);
|
||||
progress->SetValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxeditor_uploaddialog::on_ok(wxCommandEvent& e)
|
||||
{
|
||||
if(file->GetValue() && ufilename->GetValue().Length() == 0) return;
|
||||
std::string fn = filename->GetValue();
|
||||
std::vector<char> content;
|
||||
if(file->GetValue()) {
|
||||
if(fn == "")
|
||||
filename->SetValue(ufilename->GetValue());
|
||||
boost::iostreams::back_insert_device<std::vector<char>> rd(content);
|
||||
std::ifstream in(tostdstring(ufilename->GetValue()), std::ios::binary);
|
||||
if(!in) {
|
||||
status->AppendText("Can't open '" + tostdstring(ufilename->GetValue()) + "'\n");
|
||||
return;
|
||||
}
|
||||
boost::iostreams::copy(in, rd);
|
||||
} else {
|
||||
if(fn.length() < 6 || fn.substr(fn.length() - 5) != ".lsmv")
|
||||
filename->SetValue(fn + ".lsmv");
|
||||
our_movie.is_savestate = false;
|
||||
our_movie.input = movb.get_movie().save();
|
||||
auto prj = project_get();
|
||||
if(prj) {
|
||||
our_movie.gamename = prj->gamename;
|
||||
our_movie.authors = prj->authors;
|
||||
}
|
||||
our_movie.active_macros.clear();
|
||||
std::ostringstream stream;
|
||||
our_movie.save(stream);
|
||||
std::string _stream = stream.str();
|
||||
content = std::vector<char>(_stream.begin(), _stream.end());
|
||||
}
|
||||
ok->Enable(false);
|
||||
upload = new file_upload();
|
||||
upload->base_url = _entry.url;
|
||||
upload->content = content;
|
||||
upload->filename = tostdstring(filename->GetValue());
|
||||
upload->title = tostdstring(title->GetValue());
|
||||
upload->description = tostdstring(description->GetValue());
|
||||
upload->gamename = tostdstring(game->GetValue());
|
||||
upload->hidden = hidden->GetValue();
|
||||
upload->do_async();
|
||||
}
|
||||
|
||||
void wxeditor_uploaddialog::on_source_sel(wxCommandEvent& e)
|
||||
{
|
||||
ufilename->Enable(file->GetValue());
|
||||
file_select->Enable(file->GetValue());
|
||||
if(!games_req) {
|
||||
if(current->GetValue()) {
|
||||
std::string curgame;
|
||||
auto prj = project_get();
|
||||
if(prj)
|
||||
curgame = prj->gamename;
|
||||
else
|
||||
curgame = our_movie.gamename;
|
||||
|
||||
std::string plat = lookup_sysregion_mapping(our_movie.gametype->get_name()) + " ";
|
||||
size_t platlen = plat.length();
|
||||
std::string c = tostdstring(game->GetValue());
|
||||
game->Clear();
|
||||
game->Append("(default)");
|
||||
std::string c2;
|
||||
std::string c3;
|
||||
for(auto i : games_output_handler.choices) {
|
||||
std::string j = i;
|
||||
if(j.substr(0, platlen) == plat) {
|
||||
game->Append(towxstring(i));
|
||||
if(j == c)
|
||||
c2 = c;
|
||||
if(j.substr(platlen) == curgame)
|
||||
c3 = j;
|
||||
}
|
||||
}
|
||||
game->SetSelection(0);
|
||||
if(c3 != "")
|
||||
game->SetValue(towxstring(c3));
|
||||
else if(c2 != "")
|
||||
game->SetValue(towxstring(c2));
|
||||
} else {
|
||||
std::string c = tostdstring(game->GetValue());
|
||||
game->Clear();
|
||||
game->Append("(default)");
|
||||
for(auto i : games_output_handler.choices)
|
||||
game->Append(towxstring(i));
|
||||
game->SetValue(towxstring(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxeditor_uploaddialog::on_file_sel(wxCommandEvent& e)
|
||||
{
|
||||
std::string f;
|
||||
try {
|
||||
f = pick_file(this, "Pick file to send", ".");
|
||||
} catch(canceled_exception& e) {
|
||||
return;
|
||||
}
|
||||
ufilename->SetValue(towxstring(f));
|
||||
}
|
||||
|
||||
void wxeditor_uploaddialog::on_cancel(wxCommandEvent& e)
|
||||
{
|
||||
if(games_req) {
|
||||
games_req->cancel();
|
||||
while(!games_req->finished)
|
||||
usleep(100000);
|
||||
delete games_req;
|
||||
}
|
||||
if(upload) {
|
||||
upload->cancel();
|
||||
while(!upload->finished)
|
||||
usleep(100000);
|
||||
delete upload;
|
||||
}
|
||||
timer->stop();
|
||||
delete timer;
|
||||
EndModal(wxID_CANCEL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
upload_menu::upload_menu(wxWindow* win, int wxid_low, int wxid_high)
|
||||
{
|
||||
pwin = win;
|
||||
wxid_range_low = wxid_low;
|
||||
wxid_range_high = wxid_high;
|
||||
Append(wxid_range_high, towxstring("Configure..."));
|
||||
win->Connect(wxid_low, wxid_high, wxEVT_COMMAND_MENU_SELECTED,
|
||||
wxCommandEventHandler(upload_menu::on_select), NULL, this);
|
||||
{
|
||||
std::ifstream in(get_config_path() + "/upload.cfg");
|
||||
std::string line;
|
||||
unsigned num = 0;
|
||||
while(std::getline(in, line)) {
|
||||
upload_entry entry;
|
||||
try {
|
||||
JSON::node n(line);
|
||||
if(!n.field_exists("name") || n.type_of("name") != JSON::string)
|
||||
continue;
|
||||
if(!n.field_exists("url") || n.type_of("url") != JSON::string)
|
||||
continue;
|
||||
if(!n.field_exists("auth") || n.type_of("auth") != JSON::string)
|
||||
continue;
|
||||
entry.name = n["name"].as_string8();
|
||||
entry.url = n["url"].as_string8();
|
||||
std::string auth = n["auth"].as_string8();
|
||||
if(auth == "dh25519")
|
||||
entry.auth = upload_entry::AUTH_DH25519;
|
||||
else
|
||||
continue;
|
||||
} catch(...) {
|
||||
continue;
|
||||
}
|
||||
if(num == 0)
|
||||
PrependSeparator();
|
||||
entry.item = Prepend(wxid_range_low + num, towxstring(entry.name + "..."));
|
||||
destinations[wxid_range_low + num] = entry;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
upload_menu::~upload_menu()
|
||||
{
|
||||
}
|
||||
|
||||
void upload_menu::save()
|
||||
{
|
||||
std::string base = get_config_path() + "/upload.cfg";
|
||||
{
|
||||
std::ofstream out(base + ".tmp");
|
||||
if(!out)
|
||||
return;
|
||||
for(auto i : destinations) {
|
||||
upload_entry entry = i.second;
|
||||
JSON::node n(JSON::object);
|
||||
n["name"] = JSON::string(entry.name);
|
||||
n["url"] = JSON::string(entry.url);
|
||||
switch(entry.auth) {
|
||||
case upload_entry::AUTH_DH25519:
|
||||
n["auth"] = JSON::string("dh25519");
|
||||
break;
|
||||
}
|
||||
out << n.serialize() << std::endl;
|
||||
}
|
||||
if(!out)
|
||||
return;
|
||||
}
|
||||
rename_file_overwrite((base + ".tmp").c_str(), base.c_str());
|
||||
}
|
||||
|
||||
void upload_menu::configure_entry(unsigned num, struct upload_entry entry)
|
||||
{
|
||||
if(destinations.count(wxid_range_low + num)) {
|
||||
//Reconfigure.
|
||||
auto tmp = destinations[wxid_range_low + num].item;
|
||||
destinations[wxid_range_low + num] = entry;
|
||||
destinations[wxid_range_low + num].item = tmp;
|
||||
destinations[wxid_range_low + num].item->SetItemLabel(towxstring(entry.name + "..."));
|
||||
} else {
|
||||
//New entry.
|
||||
if(destinations.size() == 0)
|
||||
PrependSeparator();
|
||||
entry.item = Prepend(wxid_range_low + num, towxstring(entry.name + "..."));
|
||||
destinations[wxid_range_low + num] = entry;
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
std::set<unsigned> upload_menu::entries()
|
||||
{
|
||||
std::set<unsigned> r;
|
||||
for(auto i : destinations)
|
||||
r.insert(i.first - wxid_range_low);
|
||||
return r;
|
||||
}
|
||||
|
||||
upload_menu::upload_entry upload_menu::get_entry(unsigned num)
|
||||
{
|
||||
if(destinations.count(wxid_range_low + num))
|
||||
return destinations[wxid_range_low + num];
|
||||
else
|
||||
throw std::runtime_error("No such upload target");
|
||||
}
|
||||
|
||||
void upload_menu::delete_entry(unsigned num)
|
||||
{
|
||||
if(destinations.count(wxid_range_low + num)) {
|
||||
Delete(destinations[wxid_range_low + num].item);
|
||||
destinations.erase(wxid_range_low + num);
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
void upload_menu::on_select(wxCommandEvent& e)
|
||||
{
|
||||
int id = e.GetId();
|
||||
modal_pause_holder hld;
|
||||
try {
|
||||
wxDialog* f;
|
||||
if(id == wxid_range_high) {
|
||||
f = new wxeditor_uploadtargets(pwin, this);
|
||||
} else if(destinations.count(id)) {
|
||||
f = new wxeditor_uploaddialog(pwin, destinations[id]);
|
||||
} else
|
||||
return;
|
||||
f->ShowModal();
|
||||
f->Destroy();
|
||||
} catch(canceled_exception& e) {
|
||||
throw;
|
||||
} catch(...) {
|
||||
throw canceled_exception();
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue