-
-
Notifications
You must be signed in to change notification settings - Fork 41
Expand file tree
/
Copy pathSirvClient.ts
More file actions
116 lines (103 loc) · 2.86 KB
/
SirvClient.ts
File metadata and controls
116 lines (103 loc) · 2.86 KB
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
import axios from 'axios'
import { CircuitBreaker, retryWithBackoff } from '../../../../utils/CircuitBreaker'
const SIRV_CONFIG = {
clientId: process.env.SIRV_CLIENT_ID_RO ?? null,
clientSecret: process.env.SIRV_CLIENT_SECRET_RO ?? null
}
const client = axios.create({
baseURL: 'https://api.sirv.com/v2',
headers: {
'content-type': 'application/json'
},
timeout: 30000 // 30 second timeout
})
// Add axios interceptors for better error handling
client.interceptors.response.use(
response => response,
async error => {
console.error('Sirv API error:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
config: {
method: error.config?.method,
url: error.config?.url
}
})
return await Promise.reject(error)
}
)
const headers = {
'content-type': 'application/json'
}
interface TokenParamsType {
clientId: string | null
clientSecret: string | null
}
// Circuit breaker for Sirv API calls
const sirvCircuitBreaker = new CircuitBreaker({
failureThreshold: 3,
resetTimeout: 60000, // 1 minute
monitoringPeriod: 10000 // 10 seconds
})
const getToken = async (): Promise<string | null> => {
const params: TokenParamsType = {
clientId: SIRV_CONFIG.clientId,
clientSecret: SIRV_CONFIG.clientSecret
}
try {
const res = await sirvCircuitBreaker.execute(async () => {
return await retryWithBackoff(async () => {
return await client.post('/token', params)
}, 3, 1000, 5000)
})
if (res.status === 200) {
return res.data.token
}
} catch (e) {
console.error('Failed to get Sirv token after retries:', e)
// Don't exit process - let the app continue without Sirv functionality
return null
}
return null
}
const token = await getToken() ?? ''
interface FileMetadaata {
mtime: Date
btime: Date
}
/**
* When downloading photos from Sirv using rclone or on the UI,
* the image file's upload time is lost. This function gets
* the original upload timestamp.
* @param filename
* @returns
*/
export const getFileInfo = async (filename: string): Promise<FileMetadaata> => {
try {
const res = await sirvCircuitBreaker.execute(async () => {
return await retryWithBackoff(async () => {
return await client.get(
'/files/stat?filename=' + encodeURIComponent(filename),
{
headers: {
...headers,
Authorization: `bearer ${token}`
}
}
)
}, 3, 1000, 5000)
})
if (res.status === 200) {
const { ctime, mtime } = res.data
return ({
btime: new Date(ctime),
mtime: new Date(mtime)
})
}
throw new Error('Sirv API.getFileInfo() error: ' + String(res.statusText))
} catch (e) {
console.error('Failed to get file info after retries:', e)
throw e
}
}