UNPKG

edge-core-js

Version:

Edge account & wallet management library

147 lines (111 loc) 3.04 kB
import { asObject, asString } from 'cleaners' import { bridgifyObject, close, update, watchMethod } from 'yaob' import { asBase64 } from '../../types/server-cleaners' import { makeAccount } from '../account/account-init' import { makeLobby } from './lobby' import { searchTree, syncLogin } from './login' import { getStashById } from './login-selectors' import { asLoginStash, saveStash } from './login-stash' export const asLobbyLoginPayload = asObject({ appId: asString, loginKey: asBase64, loginStash: asLoginStash }) /** * Turns a reply into a logged-in account. */ async function unpackAccount( ai, payload, appId, opts ) { const { now = new Date() } = opts const { loginKey, loginStash: stashTree } = payload // For crash errors: ai.props.log.breadcrumb('unpackAccount', {}) // Find the appropriate child: const child = searchTree(stashTree, stash => stash.appId === appId) if (child == null) { throw new Error(`Cannot find requested appId: "${appId}"`) } // Rescue any existing vouchers: try { const old = getStashById(ai, child.loginId) child.voucherId = old.stash.voucherId child.voucherAuth = old.stash.voucherAuth } catch (error) {} stashTree.lastLogin = now await saveStash(ai, stashTree) // This is almost guaranteed to blow up spectacularly: const sessionKey = { loginId: child.loginId, loginKey } await syncLogin(ai, sessionKey) return await makeAccount(ai, sessionKey, 'edgeLogin', opts) } /** * Creates a new account request lobby on the server. */ export async function requestEdgeLogin( ai, appId, opts = {} ) { function handleSoftError(error) { out.error = error update(out) } function handleError(error) { // Stop the long-polling: for (const cleanup of cleanups) cleanup() // Update the API: out.state = 'error' out.error = error update(out) close(out) } async function handleReply(reply) { // Stop the long-polling: for (const cleanup of cleanups) cleanup() // Decode the reply: const payload = asLobbyLoginPayload(reply) const { username } = payload.loginStash out.state = 'started' out.username = username update(out) // Log in: const account = await unpackAccount(ai, payload, appId, opts) out.state = 'done' out.account = account update(out) close(out) } async function cancelRequest() { // Stop the long-polling: for (const cleanup of cleanups) cleanup() // Update the API: out.state = 'closed' update(out) close(out) } const lobby = await makeLobby(ai, { loginRequest: { appId } }) const cleanups = [ lobby.close, lobby.on('error', handleSoftError), lobby.on('reply', reply => { handleReply(reply).catch(handleError) }) ] const out = { id: lobby.lobbyId, cancelRequest, watch: watchMethod, state: 'pending', account: undefined, error: undefined, username: undefined } return bridgifyObject(out) }