2017-06-29 12:54:02 -06:00
|
|
|
type ProtocolString = "http:" | "https:";
|
|
|
|
let current: API | undefined;
|
|
|
|
/** Record of all the relevant stuff in a string URL, except without all the
|
|
|
|
* stringly typed nonsense. */
|
|
|
|
interface UrlInfo {
|
|
|
|
protocol: string;
|
|
|
|
hostname: string;
|
|
|
|
port: string;
|
|
|
|
pathname: string;
|
|
|
|
search: string;
|
|
|
|
hash: string;
|
|
|
|
host: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Store all API endpoints in one place for the sake of DRYness.
|
|
|
|
* API.current is probably the instance you want to use. */
|
|
|
|
export class API {
|
|
|
|
/** Guesses the most appropriate API port based on a number of environment
|
|
|
|
* factors such as hostname and protocol (HTTP vs. HTTPS). */
|
2018-06-18 15:12:00 -06:00
|
|
|
static inferPort(location = window.location): string {
|
2017-06-29 12:54:02 -06:00
|
|
|
|
2019-01-30 07:00:26 -07:00
|
|
|
// ATTEMPT 1: Most devs run a server on localhost with the API on port 3000.
|
2017-08-09 10:13:04 -06:00
|
|
|
if (location.port === "3808") { return "3000"; }
|
2017-06-29 12:54:02 -06:00
|
|
|
|
|
|
|
// ATTEMPT 2: If they provide an explicit port (as in ://localhost:3000)
|
|
|
|
// use that port.
|
|
|
|
if (location.port) { return location.port; }
|
|
|
|
|
|
|
|
// ATTEMPT 3: If that doesn't work, check for HTTPS:// and use the
|
|
|
|
// default of 443.
|
|
|
|
if (API.parseURL(location.origin).protocol === "https:") {
|
|
|
|
return "443";
|
|
|
|
}
|
|
|
|
|
|
|
|
// All others just use port 80.
|
|
|
|
return "80";
|
|
|
|
}
|
|
|
|
|
|
|
|
static fetchBrowserLocation() {
|
|
|
|
return `//${window.location.hostname}:${API.inferPort()}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
static fetchHostName() {
|
|
|
|
// Figured we could centralize this in case we change the method.
|
|
|
|
return window.location.hostname;
|
|
|
|
}
|
|
|
|
|
|
|
|
static parseURL(url: string): UrlInfo {
|
|
|
|
// Such an amazing hack!
|
2017-08-28 05:49:13 -06:00
|
|
|
const info = document.createElement("a");
|
2017-06-29 12:54:02 -06:00
|
|
|
info.href = url;
|
|
|
|
return info;
|
|
|
|
}
|
|
|
|
|
|
|
|
static setBaseUrl(base: string) {
|
|
|
|
current = new API(base);
|
|
|
|
}
|
2018-03-08 14:40:17 -07:00
|
|
|
|
2017-06-29 12:54:02 -06:00
|
|
|
/** The base URL can't be known until the user is logged in.
|
|
|
|
* API.current will give URLs is the base URL is known and throw an
|
|
|
|
* exception otherwise.
|
|
|
|
*/
|
|
|
|
static get current(): API {
|
|
|
|
if (current) {
|
|
|
|
return current;
|
|
|
|
} else {
|
|
|
|
throw new Error(`
|
|
|
|
Tried to access API before URL was resolved.
|
|
|
|
Call API.setBaseUrl() before using API.current .`);
|
|
|
|
}
|
2017-07-02 18:43:12 -06:00
|
|
|
}
|
2017-06-29 12:54:02 -06:00
|
|
|
|
|
|
|
/** "https:" or "http:". NO "//"! */
|
|
|
|
private readonly protocol: ProtocolString;
|
|
|
|
/** "example.com:3000" */
|
|
|
|
private readonly host: string;
|
|
|
|
|
|
|
|
constructor(input: string) {
|
2017-08-28 05:49:13 -06:00
|
|
|
const url = API.parseURL(input);
|
2017-06-29 12:54:02 -06:00
|
|
|
this.protocol = url.protocol as ProtocolString;
|
|
|
|
this.host = url.host;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** http://localhost:3000 */
|
2017-07-02 18:43:12 -06:00
|
|
|
get baseUrl() { return `${this.protocol}//${this.host}`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/tokens/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get tokensPath() { return `${this.baseUrl}/api/tokens/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/password_resets/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get passwordResetPath() { return `${this.baseUrl}/api/password_resets/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/device/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get devicePath() { return `${this.baseUrl}/api/device/`; }
|
2019-05-03 13:51:02 -06:00
|
|
|
/** /api/device/seed */
|
|
|
|
get accountSeedPath() { return `${this.devicePath}seed`; }
|
2019-05-02 19:37:10 -06:00
|
|
|
/** /api/device/reset */
|
|
|
|
get accountResetPath() { return `${this.devicePath}reset`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/users/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get usersPath() { return `${this.baseUrl}/api/users/`; }
|
2018-05-02 10:28:30 -06:00
|
|
|
/** /api/users/control_certificate */
|
|
|
|
get transferCertPath() {
|
|
|
|
return `${this.baseUrl}/api/users/control_certificate`;
|
|
|
|
}
|
2017-08-31 15:21:01 -06:00
|
|
|
/** /api/users/resend_verification */
|
2017-08-31 15:16:35 -06:00
|
|
|
get userResendConfirmationPath() {
|
|
|
|
return this.usersPath + "/resend_verification";
|
|
|
|
}
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/peripherals/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get peripheralsPath() { return `${this.baseUrl}/api/peripherals/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/farm_events/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get farmEventsPath() { return `${this.baseUrl}/api/farm_events/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/regimens/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get regimensPath() { return `${this.baseUrl}/api/regimens/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/sequences/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get sequencesPath() { return `${this.baseUrl}/api/sequences/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/tools/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get toolsPath() { return `${this.baseUrl}/api/tools/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/images/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get imagesPath() { return `${this.baseUrl}/api/images/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/points/ */
|
2017-07-02 18:43:12 -06:00
|
|
|
get pointsPath() { return `${this.baseUrl}/api/points/`; }
|
2019-08-05 15:45:19 -06:00
|
|
|
/** /api/point_groups/ */
|
|
|
|
get pointGroupsPath() { return `${this.baseUrl}/api/point_groups/`; }
|
2018-09-20 13:59:13 -06:00
|
|
|
/** /api/points/?filter=all */
|
|
|
|
get allPointsPath() { return `${this.pointsPath}?filter=all`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
/** /api/points/search */
|
2018-06-18 15:12:00 -06:00
|
|
|
get pointSearchPath() { return `${this.pointsPath}search`; }
|
2018-04-03 15:49:21 -06:00
|
|
|
/** Rather than returning ALL logs, returns a filtered subset.
|
|
|
|
* /api/logs/search */
|
2018-04-03 15:55:53 -06:00
|
|
|
get filteredLogsPath() { return `${this.baseUrl}/api/logs/search`; }
|
2019-08-26 12:20:46 -06:00
|
|
|
/** /api/logs/ */
|
|
|
|
get logsPath() { return `${this.baseUrl}/api/logs/`; }
|
2017-08-21 07:32:24 -06:00
|
|
|
/** /api/webcam_feed */
|
2017-09-19 08:45:18 -06:00
|
|
|
get webcamFeedPath() { return `${this.baseUrl}/api/webcam_feeds/`; }
|
2018-01-27 02:29:13 -07:00
|
|
|
/** /api/web_app_config */
|
2018-01-10 15:28:22 -07:00
|
|
|
get webAppConfigPath() { return `${this.baseUrl}/api/web_app_config/`; }
|
2018-01-27 02:29:13 -07:00
|
|
|
/** /api/fbos_config */
|
|
|
|
get fbosConfigPath() { return `${this.baseUrl}/api/fbos_config/`; }
|
2018-03-08 21:03:02 -07:00
|
|
|
/** /api/firmware_config */
|
|
|
|
get firmwareConfigPath() { return `${this.baseUrl}/api/firmware_config/`; }
|
2018-02-15 15:11:27 -07:00
|
|
|
/** /api/sensor_readings */
|
|
|
|
get sensorReadingPath() { return `${this.baseUrl}/api/sensor_readings`; }
|
2018-03-10 00:17:53 -07:00
|
|
|
/** /api/sensors/ */
|
|
|
|
get sensorPath() { return `${this.baseUrl}/api/sensors/`; }
|
2018-08-15 12:44:04 -06:00
|
|
|
/** /api/farmware_envs/:id */
|
2018-11-01 11:17:18 -06:00
|
|
|
get farmwareEnvPath() { return `${this.baseUrl}/api/farmware_envs/`; }
|
2018-02-28 10:51:26 -07:00
|
|
|
/** /api/pin_bindings/:id */
|
2018-03-13 18:34:30 -06:00
|
|
|
get pinBindingPath() { return `${this.baseUrl}/api/pin_bindings/`; }
|
2018-04-19 13:02:11 -06:00
|
|
|
/** /api/saved_gardens/:id */
|
2018-08-01 18:13:44 -06:00
|
|
|
get savedGardensPath() { return `${this.baseUrl}/api/saved_gardens/`; }
|
2018-04-20 10:26:18 -06:00
|
|
|
/** /api/saved_gardens/snapshot */
|
2018-04-20 09:53:13 -06:00
|
|
|
get snapshotPath() { return this.savedGardensPath + "/snapshot"; }
|
2018-04-20 10:26:18 -06:00
|
|
|
/** /api/saved_gardens/:id/apply */
|
|
|
|
applyGardenPath =
|
|
|
|
(gardenId: number) => `${this.savedGardensPath}/${gardenId}/apply`;
|
2018-04-30 09:06:59 -06:00
|
|
|
get exportDataPath() { return `${this.baseUrl}/api/export_data`; }
|
2018-04-19 13:02:11 -06:00
|
|
|
/** /api/plant_templates/:id */
|
2018-09-13 16:00:14 -06:00
|
|
|
get plantTemplatePath() { return `${this.baseUrl}/api/plant_templates/`; }
|
2018-02-26 10:53:41 -07:00
|
|
|
/** /api/farmware_installations/:id */
|
|
|
|
get farmwareInstallationPath() {
|
2018-11-05 18:37:09 -07:00
|
|
|
return `${this.baseUrl}/api/farmware_installations/`;
|
2018-02-26 10:53:41 -07:00
|
|
|
}
|
2020-02-15 11:30:23 -07:00
|
|
|
/** /api/first_party_farmwares */
|
|
|
|
get firstPartyFarmwarePath() {
|
|
|
|
return `${this.baseUrl}/api/first_party_farmwares`;
|
|
|
|
}
|
2019-04-19 16:04:25 -06:00
|
|
|
/** /api/alerts/:id */
|
|
|
|
get alertPath() { return `${this.baseUrl}/api/alerts/`; }
|
2019-04-23 12:44:10 -06:00
|
|
|
/** /api/global_bulletins/:id */
|
2019-04-19 16:48:43 -06:00
|
|
|
get globalBulletinPath() { return `${this.baseUrl}/api/global_bulletins/`; }
|
2019-12-04 08:12:34 -07:00
|
|
|
/** /api/folders */
|
|
|
|
get foldersPath() { return `${this.baseUrl}/api/folders/`; }
|
2019-07-29 09:46:43 -06:00
|
|
|
// get syncPath() { return `${this.baseUrl}/api/device/sync/`; }
|
2017-06-29 12:54:02 -06:00
|
|
|
}
|