From ecb04c6b7fbf5d06c2fdce5128e83575cac2bd21 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Fri, 23 May 2025 17:06:02 +0200 Subject: Web version (work in progress) --- web/adapter.cpp | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 11 deletions(-) (limited to 'web/adapter.cpp') diff --git a/web/adapter.cpp b/web/adapter.cpp index 1774187..3613730 100644 --- a/web/adapter.cpp +++ b/web/adapter.cpp @@ -1,11 +1,15 @@ #include "../cpp/nissy.h" +#include "storage.h" +#include #include #include #include #include #include +EM_ASYNC_JS(void, fake_async, (), {}); + extern "C" { extern int addCallbackFunction(/* args intentionally unspecified */); extern void callFunction(int, const char *); @@ -47,26 +51,43 @@ const std::set available_solvers std::map loaded_solvers; // TODO: this should ask the user if they want to download or generate. -// TODO: this should also save the data to a file (IDBFS / NODEFS) bool init_solver(const std::string& name) { auto se = nissy::solver::get(name); nissy::solver solver = std::get(se); - log("Generating data for solver " + solver.name + "\n"); - auto err = solver.generate_data(); - if (!err.ok()) { - log("Error generating the data!\n"); - return false; + + solver.data.resize(solver.size); + if (storage::read(solver.id, solver.size, + reinterpret_cast(solver.data.data()))) { + log("Data for solver " + solver.name + " read from storage\n"); + } else { + log("Could not read data for solver " + solver.name + + " from storage, generating it\n"); + auto err = solver.generate_data(); + + if (!err.ok()) { + log("Error generating the data!\n"); + return false; + } } + log("Checking data integrity " "(this is done only once per session per solver)...\n"); if (!solver.check_data().ok()) { - log("Error generating the data!\n"); + log("Error! Data is corrupted!\n"); return false; } loaded_solvers.insert({name, solver}); - log("Data generated successfully, but not saved " - "(feature not yet available)\n"); + + if (storage::write(solver.id, solver.size, + reinterpret_cast(solver.data.data()))) { + log("Data for solver " + solver.name + " stored\n"); + } else { + log("Error storing the data (the solver is usable, " + "but the data will have to be re-generated next " + "time you want to use it)"); + } + return true; } @@ -87,17 +108,31 @@ bool solver_valid(const std::string& name) int poll_status(void *arg) { + return nissy::status::RUN.value; +/* +TODO: reintroduce poll status int id = *(int *)arg; if (id == -1) return nissy::status::RUN.value; return callFunctionInt(id); +*/ } +#if 0 + nissy::solver::solve_result solve(std::string name, nissy::cube cube, nissy::nissflag nissflag, unsigned minmoves, unsigned maxmoves, unsigned maxsols, unsigned optimal, unsigned threads, int poll_status_id) { + // Here we use a dirty trick to make this function always return the + // same kind of JavaScript object. If we did not do this, the returned + // object would be a Promise on the first run of the solver for each + // session (because when loading the table some async JS code is + // called), and a regular object otherwise. + // TODO figure out if there is a better way to do this. + fake_async(); + if (!solver_valid(name)) return nissy::solver::solve_result {.err = nissy::error::INVALID_SOLVER}; @@ -106,6 +141,35 @@ nissy::solver::solve_result solve(std::string name, maxmoves, maxsols, optimal, threads, NULL, &poll_status_id); } +#else + +std::string solve(std::string name, + nissy::cube cube, nissy::nissflag nissflag, unsigned minmoves, + unsigned maxmoves, unsigned maxsols, unsigned optimal, unsigned threads, + int poll_status_id) +{ + // Here we use a dirty trick to make this function always return the + // same kind of JavaScript object. If we did not do this, the returned + // object would be a Promise on the first run of the solver for each + // session (because when loading the table some async JS code is + // called), and a regular object otherwise. + // TODO figure out if there is a better way to do this. + fake_async(); + + if (!solver_valid(name)) + return ""; +/* + return nissy::solver::solve_result + {.err = nissy::error::INVALID_SOLVER}; +*/ + + return loaded_solvers.at(name).solve(cube, nissflag, minmoves, + maxmoves, maxsols, optimal, threads, NULL, &poll_status_id) + .solutions[0]; +} + +#endif + EMSCRIPTEN_BINDINGS(Nissy) { emscripten::class_("NissFlag") @@ -134,13 +198,11 @@ EMSCRIPTEN_BINDINGS(Nissy) emscripten::constant("statusRUN", nissy::status::RUN.value); emscripten::constant("statusSTOP", nissy::status::STOP.value); emscripten::constant("statusPAUSE", nissy::status::PAUSE.value); - /* emscripten::class_("Status") .class_property("run", &nissy::status::RUN) .class_property("stop", &nissy::status::STOP) .class_property("pause", &nissy::status::PAUSE) ; - */ emscripten::class_("Cube") .constructor<>() @@ -150,10 +212,17 @@ EMSCRIPTEN_BINDINGS(Nissy) .function("toString", &nissy::cube::to_string) ; + emscripten::register_vector("StringVector"); + emscripten::value_array("SolveResult") + .element(&nissy::solver::solve_result::err) + .element(&nissy::solver::solve_result::solutions) + ; +/* emscripten::class_("SolveResult") .property("err", &nissy::solver::solve_result::err) .property("solutions", &nissy::solver::solve_result::solutions) ; +*/ emscripten::function("countMoves", &nissy::count_moves); emscripten::function("solve", &solve, -- cgit v1.3