Skip to content

Commit f5c86fc

Browse files
register and verify working
1 parent 7a84c72 commit f5c86fc

10 files changed

Lines changed: 176 additions & 96 deletions

File tree

backend/docs/swagger/swagger.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,7 @@ paths:
20742074
summary: Get account ID by twin ID
20752075
tags:
20762076
- twins
2077-
/user:
2077+
/user/:
20782078
get:
20792079
description: Retrieves all data of the user
20802080
operationId: get-user
Lines changed: 77 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import axios from "axios"
1+
import { Lock as MutexLock } from "async-await-mutex-lock"
2+
import axios, { AxiosError } from "axios"
23
import {
34
AdminApi,
45
DeploymentsApi,
@@ -11,110 +12,71 @@ import {
1112
} from "../generated/api"
1213

1314
export const useApi = createGlobalState(() => {
14-
const config = useRuntimeConfig()
15-
const { apiBasePath } = config.public
16-
17-
const accessToken = useLocalStorage<string>("accessToken", "", { writeDefaults: false })
18-
// const refreshToken = useLocalStorage<string>("refreshToken", "", { writeDefaults: false })
15+
const mu = new MutexLock()
16+
async function awaitLock() {
17+
if (mu.isAcquired()) {
18+
await mu.acquire()
19+
mu.release()
20+
}
21+
}
1922

2023
const instance = axios.create({
21-
baseURL: apiBasePath,
24+
baseURL: useRuntimeConfig().public.apiBasePath,
2225
})
2326

24-
instance.interceptors.request.use((config) => {
27+
const admin = new AdminApi(undefined, undefined, instance)
28+
const deployments = new DeploymentsApi(undefined, undefined, instance)
29+
const invoices = new InvoicesApi(undefined, undefined, instance)
30+
const nodes = new NodesApi(undefined, undefined, instance)
31+
const notifications = new NotificationsApi(undefined, undefined, instance)
32+
const twins = new TwinsApi(undefined, undefined, instance)
33+
const users = new UsersApi(undefined, undefined, instance)
34+
const workflow = new WorkflowApi(undefined, undefined, instance)
35+
36+
const accessToken = useLocalStorage<string>("accessToken", "", { writeDefaults: false })
37+
const refreshToken = useLocalStorage<string>("refreshToken", "", { writeDefaults: false })
38+
39+
instance.interceptors.request.use(async (config) => {
2540
if (config.unauthenticated) {
2641
return config
2742
}
2843

2944
// await lock to get access to accessToken
45+
await awaitLock()
3046
config.headers.Authorization = `Bearer ${accessToken.value}`
3147

3248
return config
3349
})
3450

35-
class ApiHelpers {
36-
constructor(
37-
private readonly admin: AdminApi,
38-
private readonly deployments: DeploymentsApi,
39-
private readonly invoices: InvoicesApi,
40-
private readonly nodes: NodesApi,
41-
private readonly notifications: NotificationsApi,
42-
private readonly twins: TwinsApi,
43-
private readonly users: UsersApi,
44-
private readonly workflow: WorkflowApi
45-
) {}
46-
47-
public async awaitWorkflowCompletion(workflowId: string): Promise<boolean> {
48-
const { data } = await this.workflow.getWorkflowStatus(workflowId, {
49-
unauthenticated: true,
50-
})
51-
52-
if (data.data === "failed") {
53-
return false
54-
}
55-
56-
if (data.data === "completed") {
57-
return true
58-
}
59-
60-
await new Promise((res) => setTimeout(res, 2_000))
61-
return this.awaitWorkflowCompletion(workflowId)
62-
}
63-
}
64-
65-
/*
6651
instance.interceptors.response.use(
6752
(response) => response,
68-
(error: AxiosError) => {
69-
if (error.response?.status === 401) {
70-
// local access token expired, clear it
71-
// request new access token
72-
// update tokens
73-
// unlock access to accessToken
74-
// retry request
53+
async (error) => {
54+
if (
55+
error instanceof AxiosError &&
56+
error.response &&
57+
error.response.status === 401 &&
58+
error.config &&
59+
"Authorization" in error.config.headers
60+
) {
61+
if (!mu.isAcquired()) {
62+
await mu.acquire()
63+
const { data } = await users.refreshToken(
64+
{ refresh_token: refreshToken.value },
65+
{ unauthenticated: true }
66+
)
67+
68+
accessToken.value = data.data?.access_token ?? ""
69+
mu.release()
70+
} else {
71+
await awaitLock()
72+
}
73+
74+
return instance(error.config)
7575
}
7676

77-
// if (error.response?.status === 401) {
78-
// // await lock to get access to refreshToken
79-
// const newAccessToken = await refreshToken.value
80-
// if (newAccessToken) {
81-
// accessToken.value = newAccessToken
82-
// }
83-
// }
84-
8577
return Promise.reject(error)
8678
}
87-
) */
88-
89-
// instance.interceptors.request.use((config) => {
90-
// console.log("[request] _internalFlags", config._internalFlags)
91-
// return config
92-
// })
93-
94-
// instance.interceptors.response.use(
95-
// (response) => {
96-
// console.log("[response] _internalFlags", response.config._internalFlags)
97-
// return response
98-
// },
99-
// (error: AxiosError) => {
100-
// console.log(error.config?._internalFlags)
101-
// console.log("[response] error", error)
102-
// return Promise.reject(error)
103-
// }
104-
// )
105-
106-
// const config = new Configuration({
107-
// basePath: "https://staging.myceliumcloud.tf/api/v1",
108-
// })
109-
110-
const admin = new AdminApi(undefined, undefined, instance)
111-
const deployments = new DeploymentsApi(undefined, undefined, instance)
112-
const invoices = new InvoicesApi(undefined, undefined, instance)
113-
const nodes = new NodesApi(undefined, undefined, instance)
114-
const notifications = new NotificationsApi(undefined, undefined, instance)
115-
const twins = new TwinsApi(undefined, undefined, instance)
116-
const users = new UsersApi(undefined, undefined, instance)
117-
const workflow = new WorkflowApi(undefined, undefined, instance)
79+
)
11880

11981
return {
12082
admin,
@@ -137,3 +99,33 @@ export const useApi = createGlobalState(() => {
13799
),
138100
}
139101
})
102+
103+
class ApiHelpers {
104+
constructor(
105+
private readonly admin: AdminApi,
106+
private readonly deployments: DeploymentsApi,
107+
private readonly invoices: InvoicesApi,
108+
private readonly nodes: NodesApi,
109+
private readonly notifications: NotificationsApi,
110+
private readonly twins: TwinsApi,
111+
private readonly users: UsersApi,
112+
private readonly workflow: WorkflowApi
113+
) {}
114+
115+
public async awaitWorkflowCompletion(workflowId: string): Promise<boolean> {
116+
const { data } = await this.workflow.getWorkflowStatus(workflowId, {
117+
unauthenticated: true,
118+
})
119+
120+
if (data.data === "failed") {
121+
return false
122+
}
123+
124+
if (data.data === "completed") {
125+
return true
126+
}
127+
128+
await new Promise((res) => setTimeout(res, 2_000))
129+
return this.awaitWorkflowCompletion(workflowId)
130+
}
131+
}

frontend/kubecloud-v2/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"dependencies": {
2020
"@mdi/font": "^7.4.47",
2121
"@vueuse/nuxt": "14.1.0",
22+
"async-await-mutex-lock": "^1.0.12",
2223
"axios": "^1.13.2",
2324
"nuxt": "^4.2.2",
2425
"vue": "^3.5.25",
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
<template>
2-
<div>Dashboard Clusters</div>
2+
<div>
3+
<h1>Dashboard Clusters {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
10+
11+
<script setup lang="ts">
12+
const api = useApi()
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.deployments.deploymentsGet()
16+
return data
17+
}, null)
18+
</script>
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
<template>
2-
<div>Dashboard Overview</div>
2+
<div>
3+
<h1>Dashboard Overview {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
410

511
<script setup lang="ts">
612
const api = useApi()
7-
onMounted(async () => {
8-
const { data } = await api.users.getUser()
9-
console.log(data)
10-
})
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.users.getUserBalance()
16+
return data
17+
}, null)
1118
</script>
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
<template>
2-
<div>Dashboard Nodes</div>
2+
<div>
3+
<h1>Dashboard Nodes {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
10+
11+
<script setup lang="ts">
12+
const api = useApi()
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.nodes.listReservedNodes()
16+
return data
17+
}, null)
18+
</script>
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
<template>
2-
<div>Dashboard Payments</div>
2+
<div>
3+
<h1>Dashboard Payments {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
10+
11+
<script setup lang="ts">
12+
const api = useApi()
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.users.listUserPendingRecords()
16+
return data
17+
}, null)
18+
</script>
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
<template>
2-
<div>Dashboard Profile</div>
2+
<div>
3+
<h1>Dashboard Profile {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
10+
11+
<script setup lang="ts">
12+
const api = useApi()
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.users.getUser()
16+
return data
17+
}, null)
18+
</script>
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
11
<template>
2-
<div>Dashboard SSH</div>
2+
<div>
3+
<h1>Dashboard SSH {{ isLoading }}</h1>
4+
5+
<pre>
6+
{{ state }}
7+
</pre>
8+
</div>
39
</template>
10+
11+
<script setup lang="ts">
12+
const api = useApi()
13+
14+
const { state, isLoading } = useAsyncState(async () => {
15+
const { data } = await api.users.listSshKeys()
16+
return data
17+
}, null)
18+
</script>

frontend/kubecloud-v2/yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,11 @@ ast-walker-scope@^0.8.3:
25092509
"@babel/parser" "^7.28.4"
25102510
ast-kit "^2.1.3"
25112511

2512+
async-await-mutex-lock@^1.0.12:
2513+
version "1.0.12"
2514+
resolved "https://registry.yarnpkg.com/async-await-mutex-lock/-/async-await-mutex-lock-1.0.12.tgz#30b4ad10c96f8b251a9ccb6a3fbaf696d6a6e818"
2515+
integrity sha512-zFq1Cxvk0OeU+dbrOFCLleOTNjG7g/PHKkQxzi6SfPR1vO1J3SC0rDoKf99TPb+nC5ezPirsZAff7qZVb+u8sA==
2516+
25122517
async-sema@^3.1.1:
25132518
version "3.1.1"
25142519
resolved "https://registry.yarnpkg.com/async-sema/-/async-sema-3.1.1.tgz#e527c08758a0f8f6f9f15f799a173ff3c40ea808"

0 commit comments

Comments
 (0)