Skip to content

Commit c5d8c5b

Browse files
authored
REFACTOR: Implement Fetch over $.ajax (#4564)
* REFACTOR: Implement Fetch over $.ajax Move to using the async capable fetch for Build API calls * Updates following review * Additional error handling * Additional error handling (firmware flasher) * Removing superfluous cached data check * Simplified the load hex - noting will need binary for uf2 support
1 parent e542d3d commit c5d8c5b

File tree

7 files changed

+321
-312
lines changed

7 files changed

+321
-312
lines changed

src/js/BuildApi.js

Lines changed: 128 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,184 +1,190 @@
11
import { gui_log } from "./gui_log";
22
import { i18n } from "./localization";
33
import { get as getStorage, set as setStorage } from "./SessionStorage";
4-
import $ from "jquery";
4+
import CONFIGURATOR from "./data_storage.js";
55

66
export default class BuildApi {
77
constructor() {
88
this._url = "https://build.betaflight.com";
99
this._cacheExpirationPeriod = 3600 * 1000;
1010
}
1111

12-
load(url, onSuccess, onFailure) {
12+
isSuccessCode(code) {
13+
return code === 200 || code === 201 || code === 202;
14+
}
15+
16+
async fetchText(url) {
17+
const response = await fetch(url, {
18+
method: "GET",
19+
headers: {
20+
"User-Agent": navigator.userAgent,
21+
"X-CFG-VER": `${CONFIGURATOR.version}`,
22+
},
23+
});
24+
25+
if (this.isSuccessCode(response.status)) {
26+
return await response.text();
27+
}
28+
29+
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${response.status}`]));
30+
return null;
31+
}
32+
33+
async fetchJson(url) {
34+
const response = await fetch(url, {
35+
method: "GET",
36+
headers: {
37+
"User-Agent": navigator.userAgent,
38+
"X-CFG-VER": `${CONFIGURATOR.version}`,
39+
},
40+
});
41+
42+
if (this.isSuccessCode(response.status)) {
43+
return await response.json();
44+
}
45+
46+
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${response.status}`]));
47+
return null;
48+
}
49+
50+
async fetchCachedJson(url) {
1351
const dataTag = `${url}_Data`;
1452
const cacheLastUpdateTag = `${url}_LastUpdate`;
1553

16-
const result = getStorage([cacheLastUpdateTag, dataTag]);
17-
const dataTimestamp = $.now();
18-
const cachedData = result[dataTag];
19-
const cachedLastUpdate = result[cacheLastUpdateTag];
20-
21-
const cachedCallback = () => {
22-
if (cachedData) {
23-
gui_log(i18n.getMessage("buildServerUsingCached", [url]));
24-
}
25-
26-
onSuccess(cachedData);
27-
};
28-
29-
if (!cachedData || !cachedLastUpdate || dataTimestamp - cachedLastUpdate > this._cacheExpirationPeriod) {
30-
$.get(url, function (info) {
31-
// cache loaded info
32-
const object = {};
33-
object[dataTag] = info;
34-
object[cacheLastUpdateTag] = $.now();
35-
setStorage(object);
36-
onSuccess(info);
37-
}).fail((xhr) => {
38-
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${xhr.status}`]));
39-
if (onFailure !== undefined) {
40-
onFailure();
41-
} else {
42-
cachedCallback();
43-
}
44-
});
45-
} else {
46-
cachedCallback();
54+
const storageResult = getStorage([cacheLastUpdateTag, dataTag]);
55+
const dataTimestamp = Date.now();
56+
const cachedData = storageResult[dataTag];
57+
const cachedLastUpdate = storageResult[cacheLastUpdateTag];
58+
59+
if (cachedData && cachedLastUpdate && dataTimestamp - cachedLastUpdate < this._cacheExpirationPeriod) {
60+
gui_log(i18n.getMessage("buildServerUsingCached", [url]));
61+
return cachedData;
4762
}
63+
64+
const response = await fetch(url, {
65+
method: "GET",
66+
headers: {
67+
"User-Agent": navigator.userAgent,
68+
"X-CFG-VER": `${CONFIGURATOR.version}`,
69+
},
70+
});
71+
72+
if (response.status === 500) {
73+
throw new Error(await response.text());
74+
}
75+
76+
if (response.status === 404) {
77+
return null;
78+
}
79+
80+
const result = await response.json();
81+
82+
const object = {};
83+
object[dataTag] = result;
84+
object[cacheLastUpdateTag] = Date.now();
85+
setStorage(object);
86+
return result;
4887
}
4988

50-
loadTargets(callback) {
89+
async loadTargets() {
5190
const url = `${this._url}/api/targets`;
52-
this.load(url, callback);
91+
return await this.fetchCachedJson(url);
5392
}
5493

55-
loadTargetReleases(target, callback) {
94+
async loadTargetReleases(target) {
5695
const url = `${this._url}/api/targets/${target}`;
57-
this.load(url, callback);
96+
return await this.fetchCachedJson(url);
5897
}
5998

60-
loadTarget(target, release, onSuccess, onFailure) {
99+
async loadTarget(target, release) {
61100
const url = `${this._url}/api/builds/${release}/${target}`;
62-
this.load(url, onSuccess, onFailure);
101+
return await this.fetchCachedJson(url);
63102
}
64103

65-
loadTargetHex(path, onSuccess, onFailure) {
104+
async loadTargetHex(path) {
66105
const url = `${this._url}${path}`;
67-
$.get(url, function (data) {
68-
gui_log(i18n.getMessage("buildServerSuccess", [path]));
69-
onSuccess(data);
70-
}).fail((xhr) => {
71-
gui_log(i18n.getMessage("buildServerFailure", [path, `HTTP ${xhr.status}`]));
72-
if (onFailure !== undefined) {
73-
onFailure();
74-
}
75-
});
106+
return await this.fetchText(url);
76107
}
77108

78-
getSupportCommands(onSuccess, onFailure) {
109+
async getSupportCommands() {
79110
const url = `${this._url}/api/support/commands`;
80-
$.get(url, function (data) {
81-
onSuccess(data);
82-
}).fail((xhr) => {
83-
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${xhr.status}`]));
84-
if (onFailure !== undefined) {
85-
onFailure();
86-
}
87-
});
111+
return await this.fetchJson(url);
88112
}
89113

90-
submitSupportData(data, onSuccess, onFailure) {
114+
async submitSupportData(data) {
91115
const url = `${this._url}/api/support`;
92-
$.ajax({
93-
url: url,
94-
type: "POST",
95-
data: data,
96-
contentType: "text/plain",
97-
dataType: "text",
98-
99-
success: function (response) {
100-
onSuccess(response);
116+
117+
const response = await fetch(url, {
118+
method: "POST",
119+
headers: {
120+
"Content-Type": "text/plain",
121+
"User-Agent": navigator.userAgent,
122+
"X-CFG-VER": `${CONFIGURATOR.version}`,
101123
},
102-
}).fail((xhr) => {
103-
gui_log(i18n.getMessage("buildServerFailure", [`HTTP ${xhr.status}`]));
104-
if (onFailure !== undefined) {
105-
onFailure();
106-
}
124+
body: data,
107125
});
126+
127+
if (response.status === 200) {
128+
return await response.text();
129+
}
130+
131+
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${response.status}`]));
132+
return null;
108133
}
109134

110-
requestBuild(request, onSuccess, onFailure) {
135+
async requestBuild(request) {
111136
const url = `${this._url}/api/builds`;
112-
$.ajax({
113-
url: url,
114-
type: "POST",
115-
data: JSON.stringify(request),
116-
contentType: "application/json",
117-
dataType: "json",
118-
119-
success: function (response) {
120-
onSuccess(response);
137+
138+
const response = await fetch(url, {
139+
method: "POST",
140+
headers: {
141+
"Content-Type": "application/json",
142+
"User-Agent": navigator.userAgent,
143+
"X-CFG-VER": `${CONFIGURATOR.version}`,
121144
},
122-
}).fail((xhr) => {
123-
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${xhr.status}`]));
124-
if (onFailure !== undefined) {
125-
onFailure();
126-
}
145+
body: JSON.stringify(request),
127146
});
147+
148+
if (this.isSuccessCode(response.status)) {
149+
return await response.json();
150+
}
151+
152+
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${response.status}`]));
153+
return null;
128154
}
129155

130-
requestBuildStatus(key, onSuccess, onFailure) {
156+
async requestBuildStatus(key) {
131157
const url = `${this._url}/api/builds/${key}/status`;
132-
$.get(url, function (data) {
133-
gui_log(i18n.getMessage("buildServerSuccess", [url]));
134-
onSuccess(data);
135-
}).fail((xhr) => {
136-
gui_log(i18n.getMessage("buildServerFailure", [url, `HTTP ${xhr.status}`]));
137-
if (onFailure !== undefined) {
138-
onFailure();
139-
}
140-
});
158+
return await this.fetchJson(url);
141159
}
142160

143-
requestBuildOptions(key, onSuccess, onFailure) {
161+
async requestBuildOptions(key) {
144162
const url = `${this._url}/api/builds/${key}/json`;
145-
$.get(url, function (data) {
146-
onSuccess(data);
147-
}).fail((xhr) => {
148-
if (onFailure !== undefined) {
149-
onFailure();
150-
}
151-
});
163+
return await this.fetchJson(url);
152164
}
153165

154-
loadOptions(release, onSuccess, onFailure) {
166+
async loadOptions(release) {
155167
const url = `${this._url}/api/options/${release}`;
156-
this.load(url, onSuccess, onFailure);
168+
return await this.fetchJson(url);
157169
}
158170

159-
loadOptionsByBuildKey(release, key, onSuccess, onFailure) {
171+
async loadOptionsByBuildKey(release, key) {
160172
const url = `${this._url}/api/options/${release}/${key}`;
161-
this.load(url, onSuccess, onFailure);
173+
return await this.fetchJson(url);
162174
}
163175

164-
loadCommits(release, onSuccess, onFailure) {
176+
async loadCommits(release) {
165177
const url = `${this._url}/api/releases/${release}/commits`;
166-
this.load(url, onSuccess, onFailure);
178+
return await this.fetchJson(url);
167179
}
168180

169-
loadConfiguratorRelease(type, onSuccess, onFailure) {
181+
async loadConfiguratorRelease(type) {
170182
const url = `${this._url}/api/configurator/releases/${type}`;
171-
this.load(url, onSuccess, onFailure);
183+
return await this.fetchJson(url);
172184
}
173185

174-
loadSponsorTile(mode, page, onSuccess, onFailure) {
186+
async loadSponsorTile(mode, page) {
175187
const url = `${this._url}/api/configurator/sponsors/${mode}/${page}`;
176-
$.get(url, function (data) {
177-
onSuccess(data);
178-
}).fail((xhr) => {
179-
if (onFailure !== undefined) {
180-
onFailure();
181-
}
182-
});
188+
return await this.fetchText(url);
183189
}
184190
}

src/js/Sponsor.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export default class Sponsor {
88
this._api = new BuildApi();
99
}
1010

11-
Refresh() {
11+
async Refresh() {
1212
if (!ispConnected()) {
1313
return;
1414
}
@@ -17,27 +17,30 @@ export default class Sponsor {
1717
return;
1818
}
1919

20-
this._api.loadSponsorTile(DarkTheme.enabled ? "dark" : "light", this._name, (content) => {
20+
try {
21+
let content = await this._api.loadSponsorTile(DarkTheme.enabled ? "dark" : "light", this._name);
2122
if (content) {
2223
this._div.fadeOut(500, () => {
2324
this._div.html(content);
2425
this._div.fadeIn(500);
2526
});
2627
this._div.show();
27-
} else {
28-
this._div.hide();
28+
return;
2929
}
30-
});
30+
} catch (error) {
31+
console.error("Failed to load sponsor tile: ", error);
32+
}
33+
this._div.hide();
3134
}
3235

33-
loadSponsorTile(name, div) {
36+
async loadSponsorTile(name, div) {
3437
this._name = name;
3538
this._div = div;
3639

3740
GUI.interval_add(
3841
"sponsor",
39-
() => {
40-
this.Refresh();
42+
async () => {
43+
await this.Refresh();
4144
},
4245
15000,
4346
true,

src/js/main.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ function appReady() {
6464
cleanupLocalStorage();
6565

6666
i18n.init(function () {
67-
// pass the configurator version as a custom header for every AJAX request.
68-
$.ajaxSetup({
69-
headers: {
70-
"X-CFG-VER": `${CONFIGURATOR.version}`,
71-
},
72-
});
73-
7467
startProcess();
7568

7669
checkSetupAnalytics(function (analyticsService) {

0 commit comments

Comments
 (0)