Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for data root before loading filesystem #42

Merged
merged 3 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@
"dependencies": {
"clipboard-copy": "^4.0.1",
"qrcode-svg": "^1.1.0",
"webnative": "0.34.0"
"webnative": "0.34.1"
}
}
76 changes: 49 additions & 27 deletions src/components/auth/link/LinkDevice.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import { goto } from '$app/navigation'
import { page } from '$app/stores'

import { appName } from '$lib/app-name'
import { createAccountLinkingConsumer } from '$lib/auth/linking'
import { loadAccount } from '$lib/common/webnative'

let loadingFilesystem = false

let displayPin: string = ''
let url = $page.url
const username = url.searchParams.get('username')
Expand All @@ -23,6 +24,8 @@

accountLinkingConsumer.on('link', async ({ approved, username }) => {
if (approved) {
loadingFilesystem = true

await loadAccount(username)
goto('/')
// Send up a toast on '/'
Expand All @@ -34,35 +37,54 @@
</script>

<input type="checkbox" id="my-modal-5" checked class="modal-toggle" />
<div class="modal">
<div
class="modal-box w-80 relative text-center dark:border-slate-600 dark:border"
>
<div class="grid grid-flow-row auto-rows-max gap-7">
<h3 class="text-xl font-serif">Connection Requested</h3>
<div class="grid grid-flow-row auto-rows-max gap-4 justify-items-center">
{#if displayPin}
<span
class="btn btn-info btn-lg rounded-full text-2xl tracking-widest w-3/4 cursor-default"
>
{displayPin}
</span>
{/if}
<span class="text-md">Enter this code on your connected device.</span>
{#if loadingFilesystem}
<div class="modal">
<div
class="modal-box rounded-lg shadow-sm bg-slate-100 w-80 relative text-center dark:bg-slate-900 dark:border-slate-600 dark:border "
>
<p class="text-slate-500 dark:text-slate-50">
<span
class="rounded-lg border-t-2 border-l-2 border-slate-500 dark:border-slate-50 w-4 h-4 inline-block animate-spin mr-1"
/>
Loading file system...
</p>
</div>
</div>
{:else}
<div class="modal">
<div
class="modal-box w-80 relative text-center dark:border-slate-600 dark:border"
>
<div class="grid grid-flow-row auto-rows-max gap-7">
<h3 class="text-xl font-serif">Connection Requested</h3>
<div
class="grid grid-flow-col auto-cols-max gap-4 justify-center items-center text-slate-500"
class="grid grid-flow-row auto-rows-max gap-4 justify-items-center"
>
<span
class="rounded-lg border-t-2 border-l-2 border-slate-600 dark:border-slate-50 w-4 h-4 block animate-spin"
/>
Waiting for a response...
{#if displayPin}
<span
class="btn btn-info btn-lg rounded-full text-2xl tracking-widest w-3/4 cursor-default"
>
{displayPin}
</span>
{/if}
<span class="text-md">Enter this code on your connected device.</span>
<div
class="grid grid-flow-col auto-cols-max gap-4 justify-center items-center text-slate-500"
>
<span
class="rounded-lg border-t-2 border-l-2 border-slate-600 dark:border-slate-50 w-4 h-4 block animate-spin"
/>
Waiting for a response...
</div>
</div>
<div>
<button
class="btn btn-primary btn-outline text-base font-normal mt-4"
>
Cancel Request
</button>
</div>
</div>
<div>
<button class="btn btn-primary btn-outline text-base font-normal mt-4">
Cancel Request
</button>
</div>
</div>
</div>
</div>
{/if}
27 changes: 27 additions & 0 deletions src/lib/common/webnative.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ export const register = async (username: string): Promise<boolean> => {
}

export const loadAccount = async (username: string): Promise<void> => {
await checkDataRoot(username)

const fs = await webnative.loadRootFileSystem()
filesystemStore.set(fs)

Expand All @@ -115,3 +117,28 @@ export const loadAccount = async (username: string): Promise<void> => {
authed: true
}))
}

const checkDataRoot = async (username: string): Promise<void> => {
let dataRoot = await webnative.dataRoot.lookup(username)

if (dataRoot) return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guard clause! 💪


return new Promise((resolve) => {
const maxRetries = 20
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bgins Not familiar with TypeScript module best practices, but feels weird to define this constant here. The name is quite clear! I wondering if it should be moved to the top level of webnative.ts and commented? 🤔

Maybe we wait until we need a retry construct somewhere else?

Now that I'm thinking about it, should this retry behavior be handled by the WebNative library, perhaps with an exponential backoff? (future improvement, not for this PR)

let attempt = 0

const dataRootInterval = setInterval(async () => {
console.warn('Could not fetch filesystem data root. Retrying.')

dataRoot = await webnative.dataRoot.lookup(username)

if (!dataRoot && attempt < maxRetries) {
attempt++
return
}

clearInterval(dataRootInterval)
resolve()
}, 500)
})
}