@@ -10,7 +10,7 @@ using namespace geode::prelude;
1010using namespace horrible ::prelude;
1111
1212$on_game(Loaded) {
13- if (auto as = AuthState::get ()) as->startAuth ([](Result<> res) {if (res.isErr ()) log::error (" Argon authorization failed: {}" , std::move (res).unwrapErr ()); });
13+ if (auto as = AuthState::get ()) as->startAuth ([](Result<> res) { if (res.isErr ()) log::error (" Argon authorization failed: {}" , std::move (res).unwrapErr ()); });
1414};
1515
1616static constexpr auto g_suggestWait = 60 ;
@@ -19,6 +19,26 @@ MenuSuggest* MenuSuggest::s_inst = nullptr;
1919
2020asp::Instant MenuSuggest::s_lastSuggest = asp::Instant();
2121
22+ Result<DiscordLink> json::Serialize<DiscordLink>::fromJson(json::Value const & value) {
23+ if (!value.isObject ()) return Err (" Expected an object" );
24+
25+ GEODE_UNWRAP_INTO (std::string id, value[" id" ].asString ());
26+ GEODE_UNWRAP_INTO (std::string username, value[" username" ].asString ());
27+ GEODE_UNWRAP_INTO (std::string avatar, value[" avatar" ].asString ());
28+
29+ return Ok (DiscordLink{std::move (id), std::move (username), std::move (avatar)});
30+ };
31+
32+ json::Value json::Serialize<DiscordLink>::toJson(DiscordLink const & value) {
33+ auto obj = json::Value ();
34+
35+ obj[" id" ] = value.id ;
36+ obj[" username" ] = value.username ;
37+ obj[" avatar" ] = value.avatar ;
38+
39+ return obj;
40+ };
41+
2242bool MenuSuggest::init (ZStringView theme) {
2343 auto btns = themes::getCircleBaseColor (theme);
2444
@@ -175,7 +195,7 @@ void MenuSuggest::processSuggestion(Button* sender) {
175195 if (auto s = self.lock ()) toggleBack (s);
176196 };
177197
178- if (! res.ok ()) return fallback (fmt::format (" Request failed ({}: {})" , res.code (), res.errorMessage ()));
198+ if (res.error ()) return fallback (fmt::format (" Request failed ({}: {})" , res.code (), res.errorMessage ()));
179199
180200 s_lastSuggest = asp::Instant::now ();
181201
@@ -221,6 +241,12 @@ void AuthState::setAuthInfo(int accountID, int userID, std::string username, std
221241 m_authorized = !m_token.empty ();
222242};
223243
244+ void AuthState::setDiscordLinkInfo (DiscordLink discord) {
245+ m_discord = std::move (discord);
246+
247+ m_discordLinked = !m_discord.id .empty ();
248+ };
249+
224250bool AuthState::isAuthorized () const noexcept {
225251 return m_authorized;
226252};
@@ -245,23 +271,56 @@ ZStringView AuthState::getToken() const noexcept {
245271 return m_token;
246272};
247273
274+ Result<DiscordLink> AuthState::getDiscord () const {
275+ if (!m_discordLinked) return Err (" Discord account not linked" );
276+ return Ok (m_discord);
277+ };
278+
248279void AuthState::startAuth (CopyableFunction<void (Result<>)>&& callback) {
249280 if (!argon::signedIn ()) return callback (Err (" Player is logged out" ));
250281
251- if (auto as = AuthState::get ()) {
252- if (as->isAuthValid ()) return callback (Ok ());
282+ if (isAuthValid ()) return callback (Ok ());
283+
284+ async::spawn (
285+ argon::startAuth (),
286+ [this , cb = std::move (callback)](Result<std::string> res) {
287+ if (res.isErr ()) return cb (res.asErr ());
288+
289+ auto const acc = argon::getGameAccountData ();
290+
291+ setAuthInfo (acc.accountId , acc.userId , acc.username , std::move (res).unwrap ());
292+ log::info (" Authorized {} ({}) with Argon" , acc.username , acc.accountId );
293+
294+ return cb (Ok ());
295+ });
296+
297+ if (auto gjam = GJAccountManager::sharedState ()) {
298+ auto req = web::WebRequest ()
299+ .param (" id" , gjam->m_accountID );
253300
254301 async::spawn (
255- argon::startAuth (),
256- [cb = std::move (callback), as](Result<std::string> res) {
257- if (res.isErr ()) return cb (res.asErr ());
302+ req.get (" https://api.cubicstudios.xyz/breakeode/v1/discord" ),
303+ [this ](web::WebResponse res) {
304+ auto const fallback = [](std::string_view err = " " ) {
305+ log::error (" Discord link web request failed ({})" , err);
306+ };
307+
308+ if (res.error ()) return fallback (res.errorMessage ());
309+
310+ auto jsonRes = res.json ();
311+ if (jsonRes.isErr ()) return fallback (std::move (jsonRes).unwrapErr ());
312+
313+ auto json = std::move (jsonRes).unwrap ();
314+
315+ auto discordRes = json.as <DiscordLink>();
316+ if (discordRes.isErr ()) return fallback (std::move (discordRes).unwrapErr ());
258317
259- auto const acc = argon::getGameAccountData ( );
318+ setDiscordLinkInfo ( std::move (discordRes). unwrap () );
260319
261- as-> setAuthInfo (acc. accountId , acc. userId , acc. username , std::move (res). unwrap () );
262- log::info ( " Authorized {} ({}) with Argon " , acc. username , acc. accountId );
320+ auto discordLinkRes = getDiscord ( );
321+ if (discordLinkRes. isErr ()) return fallback ( std::move (discordLinkRes). unwrapErr () );
263322
264- return cb ( Ok () );
323+ log::info ( " Authorized as Discord user {} " , std::move (discordLinkRes). unwrap (). username );
265324 });
266325 };
267326};
@@ -279,6 +338,24 @@ bool MenuDiscord::init(ZStringView theme) {
279338
280339 popup::closeBtnID (m_closeBtn);
281340
341+ if (auto as = AuthState::get ()) {
342+ auto discordRes = as->getDiscord ();
343+ if (discordRes.isOk ()) { // testing, will replace with actual ui later..!
344+ auto const discord = std::move (discordRes).unwrap ();
345+
346+ auto label = Label::createRich (fmt::format (" Authorized as <cg>@{}</c>" , discord.username ), " chatFont.fnt" );
347+
348+ m_mainLayer->addChildAtPosition (label, Anchor::Center);
349+ } else {
350+ log::error (" {}" , std::move (discordRes).unwrapErr ());
351+
352+ m_state = utils::random::generateUUID ();
353+ web::openLinkInBrowser (fmt::format (" https://api.cubicstudios.xyz/breakeode/v1/discord/link/auth?state={}" , m_state));
354+
355+ scheduleOnce (schedule_selector (MenuDiscord::checkDiscordStatus), 1 .25f );
356+ };
357+ };
358+
282359 auto infoBtn = Button::createWithSpriteFrameName (
283360 " GJ_infoIcon_001.png" ,
284361 [](auto ) {
@@ -298,8 +375,62 @@ bool MenuDiscord::init(ZStringView theme) {
298375 return true ;
299376};
300377
378+ void MenuDiscord::checkDiscordStatus (float ) {
379+ if (auto as = AuthState::get ()) {
380+ if (!as->isAuthValid ()) return unschedule (schedule_selector (MenuDiscord::checkDiscordStatus));
381+
382+ auto reqJson = json::Value ();
383+ reqJson[" account_id" ] = as->getAccountID ();
384+ reqJson[" user_id" ] = as->getUserID ();
385+ reqJson[" username" ] = as->getUsername ();
386+ reqJson[" authtoken" ] = as->getToken ();
387+ reqJson[" state" ] = m_state;
388+
389+ auto req = web::WebRequest ()
390+ .bodyJSON (reqJson);
391+
392+ log::debug (" Checking endpoint for Discord link status..." );
393+
394+ m_listener.spawn (
395+ req.post (" https://api.cubicstudios.xyz/breakeode/v1/discord/link/check" ),
396+ [self = WeakRef (this )](web::WebResponse res) {
397+ if (auto s = self.lock ()) {
398+ auto const fallback = [&s](std::string_view err = " " ) {
399+ log::error (" Discord link web request failed ({}), trying again in 1.25s" , err);
400+ s->scheduleOnce (schedule_selector (MenuDiscord::checkDiscordStatus), 1 .25f );
401+ };
402+
403+ if (res.error ()) return fallback (res.errorMessage ());
404+
405+ auto jsonRes = res.json ();
406+ if (jsonRes.isErr ()) return fallback (std::move (jsonRes).unwrapErr ());
407+
408+ auto json = std::move (jsonRes).unwrap ();
409+
410+ auto discordRes = json.as <DiscordLink>();
411+ if (discordRes.isErr ()) return fallback (std::move (discordRes).unwrapErr ());
412+
413+ auto discord = std::move (discordRes).unwrap ();
414+
415+ log::info (" Successfully authorized as {}" , discord.username );
416+ if (auto as = AuthState::get ()) as->setDiscordLinkInfo (std::move (discord));
417+
418+ s->unschedule (schedule_selector (MenuDiscord::checkDiscordStatus));
419+ s->m_listener .cancel ();
420+ };
421+ });
422+ } else {
423+ unschedule (schedule_selector (MenuDiscord::checkDiscordStatus));
424+ };
425+ };
426+
301427void MenuDiscord::onExit () {
302428 s_inst = nullptr ;
429+
430+ if (m_listener.isPending ()) log::trace (" Cancelling Discord link tasks" );
431+ unschedule (schedule_selector (MenuDiscord::checkDiscordStatus));
432+ m_listener.cancel ();
433+
303434 Popup::onExit ();
304435};
305436
0 commit comments