-
Notifications
You must be signed in to change notification settings - Fork 0
/
useDownloadState.ts
146 lines (128 loc) · 4.85 KB
/
useDownloadState.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { DownloadState } from '@janhq/core'
import { atom } from 'jotai'
import { toaster } from '@/containers/Toast'
import {
configuredModelsAtom,
downloadedModelsAtom,
removeDownloadingModelAtom,
} from '@/helpers/atoms/Model.atom'
// download states
export const modelDownloadStateAtom = atom<Record<string, DownloadState>>({})
/**
* Used to set the download state for a particular model.
*/
export const setDownloadStateAtom = atom(
null,
(get, set, state: DownloadState) => {
try {
const currentState = { ...get(modelDownloadStateAtom) }
if (state.downloadState === 'end') {
const modelDownloadState = currentState[state.modelId]
const updatedChildren: DownloadState[] = (
modelDownloadState.children ?? []
).filter((m) => m.fileName !== state.fileName)
updatedChildren.push(state)
modelDownloadState.children = updatedChildren
currentState[state.modelId] = modelDownloadState
const isAllChildrenDownloadEnd = modelDownloadState.children?.every(
(m) => m.downloadState === 'end'
)
if (isAllChildrenDownloadEnd) {
// download successfully
delete currentState[state.modelId]
set(removeDownloadingModelAtom, state.modelId)
const model = get(configuredModelsAtom).find(
(e) => e.id === state.modelId
)
if (model) set(downloadedModelsAtom, (prev) => [...prev, model])
toaster({
title: 'Download Completed',
description: `Download ${state.modelId} completed`,
type: 'success',
})
}
} else if (state.downloadState === 'error') {
// download error
delete currentState[state.modelId]
set(removeDownloadingModelAtom, state.modelId)
if (state.error === 'aborted') {
toaster({
title: 'Cancel Download',
description: `Model ${state.modelId} download cancelled`,
type: 'warning',
})
} else {
let error = state.error
if (
typeof error?.includes === 'function' &&
state.error?.includes('certificate')
) {
error +=
'. To fix enable "Ignore SSL Certificates" in Advanced settings.'
}
toaster({
title: 'Download Failed',
description: `Model ${state.modelId} download failed: ${error}`,
type: 'error',
})
}
} else {
// download in progress
if (state.size.total === 0) {
// this is initial state, just set the state
currentState[state.modelId] = state
set(modelDownloadStateAtom, currentState)
return
}
const modelDownloadState = currentState[state.modelId]
if (!modelDownloadState) {
console.debug('setDownloadStateAtom: modelDownloadState not found')
return
}
// delete the children if the filename is matched and replace the new state
const updatedChildren: DownloadState[] = (
modelDownloadState.children ?? []
).filter((m) => m.fileName !== state.fileName)
updatedChildren.push(state)
// re-calculate the overall progress if we have all the children download data
const isAnyChildDownloadNotReady = updatedChildren.some(
(m) =>
m.size.total === 0 &&
!modelDownloadState.children?.some(
(e) => e.fileName === m.fileName && e.downloadState === 'end'
) &&
modelDownloadState.children?.some((e) => e.fileName === m.fileName)
)
modelDownloadState.children = updatedChildren
if (isAnyChildDownloadNotReady) {
// just update the children
currentState[state.modelId] = modelDownloadState
set(modelDownloadStateAtom, currentState)
return
}
const parentTotalSize = modelDownloadState.size.total
if (parentTotalSize === 0) {
// calculate the total size of the parent by sum all children total size
const totalSize = updatedChildren.reduce(
(acc, m) => acc + m.size.total,
0
)
modelDownloadState.size.total = totalSize
}
// calculate the total transferred size by sum all children transferred size
const transferredSize = updatedChildren.reduce(
(acc, m) => acc + m.size.transferred,
0
)
modelDownloadState.size.transferred = transferredSize
modelDownloadState.percent =
parentTotalSize === 0 ? 0 : transferredSize / parentTotalSize
currentState[state.modelId] = modelDownloadState
}
set(modelDownloadStateAtom, currentState)
} catch (e) {
console.debug('setDownloadStateAtom: state', state)
console.debug('setDownloadStateAtom: error', e)
}
}
)