Skip to content

Commit 7e5c6dd

Browse files
committed
feat: add call for retrieving rate limit
1 parent 059f964 commit 7e5c6dd

2 files changed

Lines changed: 70 additions & 1 deletion

File tree

src/base.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
MobileDeviceSettings,
2525
PushNotificationRegistration,
2626
PushNotificationRegistrationData,
27+
RateLimit,
2728
RunningTimeAggregation,
2829
RunningTimes,
2930
RunningTimesSummaryOnly,
@@ -35,7 +36,7 @@ import type {
3536
} from "./types";
3637

3738
import { Agent } from "https";
38-
import axios, { Method } from "axios";
39+
import axios, { AxiosHeaders, Method } from "axios";
3940
import { Semaphore } from "./semaphore";
4041
import { AuthTimeout, InvalidRefreshToken, NotAuthenticated, TadoError } from "./types";
4142

@@ -49,6 +50,7 @@ export class BaseTado {
4950
#token?: Token | undefined;
5051
#tokenCallback?: (token: Token) => void;
5152
#semaphore: Semaphore;
53+
#ratelimit: RateLimit | undefined = undefined;
5254

5355
constructor() {
5456
this.#httpsAgent = new Agent({ keepAlive: true });
@@ -165,6 +167,15 @@ export class BaseTado {
165167
this.#tokenCallback = cb;
166168
}
167169

170+
/**
171+
* Get the Tado API rate limit information
172+
*
173+
* @returns `RateLimit` if an API call has occured
174+
*/
175+
get ratelimit(): RateLimit | undefined {
176+
return this.#ratelimit;
177+
}
178+
168179
/**
169180
* Authenticate with the Oauth server. A refresh token may be supplied to bypass the device auth
170181
* flow if it is still valid, otherwise the device flow is initiaited.
@@ -248,6 +259,52 @@ export class BaseTado {
248259
request.data = data;
249260
}
250261
const response = await axios<R>(request);
262+
263+
const headers = response.headers;
264+
if (headers instanceof AxiosHeaders) {
265+
let ratelimit: RateLimit = {
266+
policy: {
267+
quota: 0,
268+
window: 0,
269+
},
270+
current: {
271+
remaining: 0,
272+
resetsIn: undefined,
273+
},
274+
};
275+
276+
headers
277+
.get("ratelimit-policy")
278+
?.toString()
279+
.split(";")
280+
.forEach((v) => {
281+
if (v.includes("=")) {
282+
const parts = v.split("=");
283+
if (parts[0] == "q") {
284+
ratelimit.policy.quota = Number.parseInt(parts[1]);
285+
} else if (parts[0] == "w") {
286+
ratelimit.policy.window = Number.parseInt(parts[1]);
287+
}
288+
}
289+
});
290+
headers
291+
.get("ratelimit")
292+
?.toString()
293+
.split(";")
294+
.forEach((v) => {
295+
if (v.includes("=")) {
296+
const parts = v.split("=");
297+
if (parts[0] == "r") {
298+
ratelimit.current.remaining = Number.parseInt(parts[1]);
299+
} else if (parts[0] == "t") {
300+
ratelimit.current.resetsIn = Number.parseInt(parts[1]);
301+
}
302+
}
303+
});
304+
305+
this.#ratelimit = ratelimit;
306+
}
307+
251308
return response.data;
252309
}
253310

src/types/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,18 @@ export type DeepPartial<T> = T extends object
5353
type Nullable<T> = T | null;
5454

5555
// tado
56+
57+
export interface RateLimit {
58+
policy: {
59+
quota: number;
60+
window: number;
61+
};
62+
current: {
63+
remaining: number;
64+
resetsIn?: number;
65+
};
66+
}
67+
5668
/** Example: `'en'` */
5769
export type Locale = string;
5870

0 commit comments

Comments
 (0)