-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathwnsm-api.js
92 lines (79 loc) · 2.2 KB
/
wnsm-api.js
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
const { default: axios } = require('axios')
const qs = require('node:querystring')
const config = {
tokenUrl: 'https://log.wien/auth/realms/logwien/protocol/openid-connect/token',
baseUrl: 'https://api.wstw.at/gateway/WN_SMART_METER_API/1.0',
}
module.exports = class Wnsm {
config
http
token
tokenExpiresAt
constructor(authConfig) {
if (!authConfig.clientId || !authConfig.clientSecret || !authConfig.apiKey) {
throw new Error('Authentication configuration must have properties "clientId", "clientSecret" and "apiKey"')
}
this.config = {
...config,
...authConfig
}
this.http = axios.create({
timeout: 60 * 1000,
validateStatus: status => status < 400
})
}
async #getToken() {
let res
try {
res = await this.http.post(
this.config.tokenUrl,
qs.stringify({
'client_id': this.config.clientId,
'client_secret': this.config.clientSecret,
'grant_type': 'client_credentials'
})
)
} catch (err) {
throw new Error(`Failed to authenticate: ${err.response.status} ${err.response.statusText}`)
}
if (res.data?.access_token && res.data?.expires_in) {
this.token = res.data.access_token
this.tokenExpiresAt = this.#getEpoch() + res.data.expires_in - 10
} else {
throw new Error(`Failed to parse authentication response: ${res.data}`)
}
}
#getEpoch() {
return Math.floor(Date.now() / 1000)
}
async #call2(endpoint, params) {
return await this.http.get(
this.config.baseUrl + endpoint,
{
headers: {
'x-Gateway-APIKey': this.config.apiKey,
'Authorization': `Bearer ${this.token}`,
},
params
}
)
}
async call(endpoint, params) {
if (!this.token || this.#getEpoch() >= this.tokenExpiresAt) {
await this.#getToken()
}
let res
try {
res = await this.#call2(endpoint, params)
} catch (err) {
// If call fails with status 401, try again with new token
if (err.response.status === 401) {
await this.#getToken()
res = await this.#call2(endpoint, params)
} else {
throw err
}
}
return res.data
}
}