package ionet import ( "encoding/json" "fmt" "strings" "github.com/samber/lo" ) // GetAvailableReplicas retrieves available replicas per location for specified hardware func (c *Client) GetAvailableReplicas(hardwareID int, gpuCount int) (*AvailableReplicasResponse, error) { if hardwareID <= 0 { return nil, fmt.Errorf("hardware_id must be greater than 0") } if gpuCount < 1 { return nil, fmt.Errorf("gpu_count must be at least 1") } params := map[string]interface{}{ "hardware_id": hardwareID, "hardware_qty": gpuCount, } endpoint := "/available-replicas" + buildQueryParams(params) resp, err := c.makeRequest("GET", endpoint, nil) if err != nil { return nil, fmt.Errorf("failed to get available replicas: %w", err) } type availableReplicaPayload struct { ID int `json:"id"` ISO2 string `json:"iso2"` Name string `json:"name"` AvailableReplicas int `json:"available_replicas"` } var payload []availableReplicaPayload if err := decodeData(resp.Body, &payload); err != nil { return nil, fmt.Errorf("failed to parse available replicas response: %w", err) } replicas := lo.Map(payload, func(item availableReplicaPayload, _ int) AvailableReplica { return AvailableReplica{ LocationID: item.ID, LocationName: item.Name, HardwareID: hardwareID, HardwareName: "", AvailableCount: item.AvailableReplicas, MaxGPUs: gpuCount, } }) return &AvailableReplicasResponse{Replicas: replicas}, nil } // GetMaxGPUsPerContainer retrieves the maximum number of GPUs available per hardware type func (c *Client) GetMaxGPUsPerContainer() (*MaxGPUResponse, error) { resp, err := c.makeRequest("GET", "/hardware/max-gpus-per-container", nil) if err != nil { return nil, fmt.Errorf("failed to get max GPUs per container: %w", err) } var maxGPUResp MaxGPUResponse if err := decodeData(resp.Body, &maxGPUResp); err != nil { return nil, fmt.Errorf("failed to parse max GPU response: %w", err) } return &maxGPUResp, nil } // ListHardwareTypes retrieves available hardware types using the max GPUs endpoint func (c *Client) ListHardwareTypes() ([]HardwareType, int, error) { maxGPUResp, err := c.GetMaxGPUsPerContainer() if err != nil { return nil, 0, fmt.Errorf("failed to list hardware types: %w", err) } mapped := lo.Map(maxGPUResp.Hardware, func(hw MaxGPUInfo, _ int) HardwareType { name := strings.TrimSpace(hw.HardwareName) if name == "" { name = fmt.Sprintf("Hardware %d", hw.HardwareID) } return HardwareType{ ID: hw.HardwareID, Name: name, GPUType: "", GPUMemory: 0, MaxGPUs: hw.MaxGPUsPerContainer, CPU: "", Memory: 0, Storage: 0, HourlyRate: 0, Available: hw.Available > 0, BrandName: strings.TrimSpace(hw.BrandName), AvailableCount: hw.Available, } }) totalAvailable := maxGPUResp.Total if totalAvailable == 0 { totalAvailable = lo.SumBy(maxGPUResp.Hardware, func(hw MaxGPUInfo) int { return hw.Available }) } return mapped, totalAvailable, nil } // ListLocations retrieves available deployment locations (if supported by the API) func (c *Client) ListLocations() (*LocationsResponse, error) { resp, err := c.makeRequest("GET", "/locations", nil) if err != nil { return nil, fmt.Errorf("failed to list locations: %w", err) } var locations LocationsResponse if err := decodeData(resp.Body, &locations); err != nil { return nil, fmt.Errorf("failed to parse locations response: %w", err) } locations.Locations = lo.Map(locations.Locations, func(location Location, _ int) Location { location.ISO2 = strings.ToUpper(strings.TrimSpace(location.ISO2)) return location }) if locations.Total == 0 { locations.Total = lo.SumBy(locations.Locations, func(location Location) int { return location.Available }) } return &locations, nil } // GetHardwareType retrieves details about a specific hardware type func (c *Client) GetHardwareType(hardwareID int) (*HardwareType, error) { if hardwareID <= 0 { return nil, fmt.Errorf("hardware ID must be greater than 0") } endpoint := fmt.Sprintf("/hardware/types/%d", hardwareID) resp, err := c.makeRequest("GET", endpoint, nil) if err != nil { return nil, fmt.Errorf("failed to get hardware type: %w", err) } // API response format not documented, assuming direct format var hardwareType HardwareType if err := json.Unmarshal(resp.Body, &hardwareType); err != nil { return nil, fmt.Errorf("failed to parse hardware type: %w", err) } return &hardwareType, nil } // GetLocation retrieves details about a specific location func (c *Client) GetLocation(locationID int) (*Location, error) { if locationID <= 0 { return nil, fmt.Errorf("location ID must be greater than 0") } endpoint := fmt.Sprintf("/locations/%d", locationID) resp, err := c.makeRequest("GET", endpoint, nil) if err != nil { return nil, fmt.Errorf("failed to get location: %w", err) } // API response format not documented, assuming direct format var location Location if err := json.Unmarshal(resp.Body, &location); err != nil { return nil, fmt.Errorf("failed to parse location: %w", err) } return &location, nil } // GetLocationAvailability retrieves real-time availability for a specific location func (c *Client) GetLocationAvailability(locationID int) (*LocationAvailability, error) { if locationID <= 0 { return nil, fmt.Errorf("location ID must be greater than 0") } endpoint := fmt.Sprintf("/locations/%d/availability", locationID) resp, err := c.makeRequest("GET", endpoint, nil) if err != nil { return nil, fmt.Errorf("failed to get location availability: %w", err) } // API response format not documented, assuming direct format var availability LocationAvailability if err := json.Unmarshal(resp.Body, &availability); err != nil { return nil, fmt.Errorf("failed to parse location availability: %w", err) } return &availability, nil }