Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/frontend/compute/api.ts
Views: 687
import api from "@cocalc/frontend/client/api";1("");2import type {3Action,4ComputeServerTemplate,5Configuration,6Cloud,7Images,8GoogleCloudImages,9} from "@cocalc/util/db-schema/compute-servers";10import type { GoogleCloudData } from "@cocalc/util/compute/cloud/google-cloud/compute-cost";11import type { HyperstackPriceData } from "@cocalc/util/compute/cloud/hyperstack/pricing";12import type {13ConfigurationTemplate,14ConfigurationTemplates,15} from "@cocalc/util/compute/templates";16import { reuseInFlight } from "@cocalc/util/reuse-in-flight";17import TTL from "@isaacs/ttlcache";1819export async function createServer(opts: {20project_id: string;21title?: string;22color?: string;23idle_timeout?: number;24autorestart?: boolean;25cloud?: Cloud;26configuration?: Configuration;27notes?: string;28}): Promise<number> {29return await api("compute/create-server", opts);30}3132export async function computeServerAction(opts: {33id: number;34action: Action;35}) {36await api("compute/compute-server-action", opts);37}3839export async function getServers(opts: { id?: number; project_id: string }) {40return await api("compute/get-servers", opts);41}4243export async function getServerState(id: number) {44return await api("compute/get-server-state", { id });45}4647export async function getSerialPortOutput(id: number) {48return await api("compute/get-serial-port-output", { id });49}5051export async function deleteServer(id: number) {52await api("compute/delete-server", { id });53}5455export async function undeleteServer(id: number) {56await api("compute/undelete-server", { id });57}5859// only owner can change properties of a compute server.6061export async function setServerColor(opts: { id: number; color: string }) {62return await api("compute/set-server-color", opts);63}6465export async function setServerTitle(opts: { id: number; title: string }) {66return await api("compute/set-server-title", opts);67}6869export async function setServerConfiguration(opts: {70id: number;71configuration;72}) {73return await api("compute/set-server-configuration", opts);74}7576// only for admins!77export async function setTemplate(opts: {78id: number;79template: ComputeServerTemplate;80}) {81return await api("compute/set-template", opts);82}8384// 5-minute client side ttl cache of all and specific template, since85// templates change rarely.8687const templatesCache = new TTL({ ttl: 60 * 1000 * 5 });8889export async function getTemplate(id: number): Promise<ConfigurationTemplate> {90if (templatesCache.has(id)) {91return templatesCache.get(id)!;92}93const x = await api("compute/get-template", { id });94templatesCache.set(id, x);95return x;96}9798export async function getTemplates(): Promise<ConfigurationTemplates> {99if (templatesCache.has("templates")) {100return templatesCache.get("templates")!;101}102const x = await api("compute/get-templates");103templatesCache.set("templates", x);104return x;105}106107export async function setServerCloud(opts: { id: number; cloud: string }) {108return await api("compute/set-server-cloud", opts);109}110111// Cache for 12 hours112let googleCloudPriceData: GoogleCloudData | null = null;113let googleCloudPriceDataExpire: number = 0;114export const getGoogleCloudPriceData = reuseInFlight(115async (): Promise<GoogleCloudData> => {116if (117googleCloudPriceData == null ||118Date.now() >= googleCloudPriceDataExpire119) {120googleCloudPriceData = await api("compute/google-cloud/get-pricing-data");121googleCloudPriceDataExpire = Date.now() + 1000 * 60 * 60 * 12; // 12 hour cache122}123if (googleCloudPriceData == null) {124throw Error("bug");125}126return googleCloudPriceData;127},128);129130import { useState, useEffect } from "react";131export function useGoogleCloudPriceData() {132const [priceData, setPriceData] = useState<null | GoogleCloudData>(null);133const [error, setError] = useState<string>("");134useEffect(() => {135(async () => {136try {137setError("");138setPriceData(await getGoogleCloudPriceData());139} catch (err) {140setError(`${err}`);141}142})();143}, []);144return [priceData, error];145}146147// Cache for 5 minutes -- cache less since this includes realtime148// information about GPU availability.149let hyperstackPriceData: HyperstackPriceData | null = null;150let hyperstackPriceDataExpire: number = 0;151export const getHyperstackPriceData = reuseInFlight(152async (): Promise<HyperstackPriceData> => {153if (154hyperstackPriceData == null ||155Date.now() >= hyperstackPriceDataExpire156) {157hyperstackPriceData = await api("compute/get-hyperstack-pricing-data");158hyperstackPriceDataExpire = Date.now() + 1000 * 60 * 5; // 5 minute cache159}160if (hyperstackPriceData == null) {161throw Error("bug");162}163return hyperstackPriceData;164},165);166167// Returns network usage during the given interval. Returns168// amount in GiB and cost at our current rate.169export async function getNetworkUsage(opts: {170id: number;171start: Date;172end: Date;173}): Promise<{ amount: number; cost: number }> {174return await api("compute/get-network-usage", opts);175}176177// Get the current api key for a specific (on prem) server.178// We only need this for on prem, so we are restricting to that right now.179// If no key is allocated, one will be created.180export async function getApiKey(opts: { id }): Promise<string> {181return await api("compute/get-api-key", opts);182}183export async function deleteApiKey(opts: { id }): Promise<string> {184return await api("compute/delete-api-key", opts);185}186187// Get the project log entries directly for just one compute server188export async function getLog(opts: { id }) {189return await api("compute/get-log", opts);190}191192export const getTitle = reuseInFlight(193async (opts: {194id: number;195}): Promise<{196title: string;197color: string;198project_specific_id: number;199}> => {200return await api("compute/get-server-title", opts);201},202);203204// Setting a detailed state component for a compute server205export async function setDetailedState(opts: {206project_id: string;207id: number;208name: string;209state?: string;210extra?: string;211timeout?: number;212progress?: number;213}) {214return await api("compute/set-detailed-state", opts);215}216217// We cache images for 5 minutes.218const IMAGES_TTL = 5 * 60 * 1000;219220const imagesCache: {221[cloud: string]: { timestamp: number; images: Images | null };222} = {};223224function cacheHas(cloud: string) {225const x = imagesCache[cloud];226if (x == null) {227return false;228}229if (Math.abs(x.timestamp - Date.now()) <= IMAGES_TTL) {230return true;231}232return false;233}234235function cacheGet(cloud) {236return imagesCache[cloud]?.images;237}238239function cacheSet(cloud, images) {240imagesCache[cloud] = { images, timestamp: Date.now() };241}242243async function getImagesFor({244cloud,245endpoint,246reload,247}: {248cloud: string;249endpoint: string;250reload?: boolean;251}): Promise<any> {252if (!reload && cacheHas(cloud)) {253return cacheGet(cloud);254}255256try {257const images = await api(258endpoint,259// admin reload forces fetch data from github and/or google cloud - normal users just have their cache ignored above260reload ? { noCache: true } : undefined,261);262cacheSet(cloud, images);263return images;264} catch (err) {265const images = cacheGet(cloud);266if (images != null) {267console.warn(268"ERROR getting updated compute server images -- using cached data",269err,270);271return images;272}273throw err;274}275}276277export async function getImages(reload?: boolean): Promise<Images> {278return await getImagesFor({279cloud: "",280endpoint: "compute/get-images",281reload,282});283}284285export async function getGoogleCloudImages(286reload?: boolean,287): Promise<GoogleCloudImages> {288return await getImagesFor({289cloud: "google",290endpoint: "compute/get-images-google",291reload,292});293}294295export async function setImageTested(opts: {296id: number; // server id297tested: boolean;298}) {299return await api("compute/set-image-tested", opts);300}301302303