fix: simplify nats handlers

This commit is contained in:
Julian Sommer
2026-02-09 10:42:47 +10:00
parent 88f07a9f3a
commit e15c077d3a
5 changed files with 49 additions and 311 deletions
+2 -29
View File
@@ -1,7 +1,6 @@
package handlers_ec2_image
import (
"encoding/json"
"fmt"
"time"
@@ -20,37 +19,11 @@ func NewNATSImageService(conn *nats.Conn) ImageService {
return &NATSImageService{natsConn: conn}
}
// DescribeImages sends a request via NATS and waits for response
func (s *NATSImageService) DescribeImages(input *ec2.DescribeImagesInput) (*ec2.DescribeImagesOutput, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send NATS request with 30 second timeout
msg, err := s.natsConn.Request("ec2.DescribeImages", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Validate error response
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, fmt.Errorf("daemon returned error: %s", *responseError.Code)
}
// Unmarshal successful response
var output ec2.DescribeImagesOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DescribeImagesOutput](s.natsConn, "ec2.DescribeImages", input, 30*time.Second)
}
// Stub implementations for other ImageService methods
// Stub implementations for unimplemented ImageService methods
func (s *NATSImageService) CreateImage(input *ec2.CreateImageInput) (*ec2.CreateImageOutput, error) {
return nil, fmt.Errorf("CreateImage not yet implemented")
}
+1 -36
View File
@@ -1,10 +1,6 @@
package handlers_ec2_instance
import (
"encoding/json"
"errors"
"fmt"
"log/slog"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
@@ -22,37 +18,6 @@ func NewNATSInstanceService(conn *nats.Conn) InstanceService {
return &NATSInstanceService{natsConn: conn}
}
// RunInstances sends a RunInstances request to the daemon via NATS
func (s *NATSInstanceService) RunInstances(input *ec2.RunInstancesInput) (*ec2.Reservation, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
slog.Error("NATSInstanceService: Failed to marshal RunInstancesInput", "err", err)
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send request to daemon via NATS with 5 minute timeout
msg, err := s.natsConn.Request("ec2.RunInstances", jsonData, 5*time.Minute)
if err != nil {
slog.Error("NATSInstanceService: Failed to send NATS request", "err", err)
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Check if the response is an error
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
// Response is an error payload - return just the error code for gateway lookup
slog.Error("NATSInstanceService: Received error response from daemon", "code", responseError.Code)
return nil, errors.New(*responseError.Code)
}
// Unmarshal successful response
var reservation ec2.Reservation
err = json.Unmarshal(msg.Data, &reservation)
if err != nil {
slog.Error("NATSInstanceService: Failed to unmarshal reservation", "err", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &reservation, nil
return utils.NATSRequest[ec2.Reservation](s.natsConn, "ec2.RunInstances", input, 5*time.Minute)
}
+4 -128
View File
@@ -1,9 +1,6 @@
package handlers_ec2_key
import (
"encoding/json"
"fmt"
"log/slog"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
@@ -21,139 +18,18 @@ func NewNATSKeyService(conn *nats.Conn) KeyService {
return &NATSKeyService{natsConn: conn}
}
// CreateKeyPair sends a CreateKeyPair request to the daemon via NATS
func (s *NATSKeyService) CreateKeyPair(input *ec2.CreateKeyPairInput) (*ec2.CreateKeyPairOutput, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
slog.Error("NATSKeyService: Failed to marshal CreateKeyPairInput", "err", err)
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send request to daemon via NATS with 30 second timeout
msg, err := s.natsConn.Request("ec2.CreateKeyPair", jsonData, 30*time.Second)
if err != nil {
slog.Error("NATSKeyService: Failed to send NATS request", "err", err)
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Check if the response is an error
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
// Response is an error payload
slog.Error("NATSKeyService: Received error response from daemon", "code", responseError.Code)
return nil, fmt.Errorf("daemon returned error: %s", *responseError.Code)
}
// Unmarshal successful response
var output ec2.CreateKeyPairOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
slog.Error("NATSKeyService: Failed to unmarshal output", "err", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.CreateKeyPairOutput](s.natsConn, "ec2.CreateKeyPair", input, 30*time.Second)
}
func (s *NATSKeyService) DeleteKeyPair(input *ec2.DeleteKeyPairInput) (*ec2.DeleteKeyPairOutput, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
slog.Error("NATSKeyService: Failed to marshal DeleteKeyPairInput", "err", err)
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send request to daemon via NATS with 30 second timeout
msg, err := s.natsConn.Request("ec2.DeleteKeyPair", jsonData, 30*time.Second)
if err != nil {
slog.Error("NATSKeyService: Failed to send NATS request", "err", err)
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Check if the response is an error
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
// Response is an error payload
slog.Error("NATSKeyService: Received error response from daemon", "code", responseError.Code)
return nil, fmt.Errorf("daemon returned error: %s", *responseError.Code)
}
// Unmarshal successful response
var output ec2.DeleteKeyPairOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
slog.Error("NATSKeyService: Failed to unmarshal output", "err", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DeleteKeyPairOutput](s.natsConn, "ec2.DeleteKeyPair", input, 30*time.Second)
}
func (s *NATSKeyService) DescribeKeyPairs(input *ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
slog.Error("NATSKeyService: Failed to marshal DescribeKeyPairsInput", "err", err)
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send request to daemon via NATS with 30 second timeout
msg, err := s.natsConn.Request("ec2.DescribeKeyPairs", jsonData, 30*time.Second)
if err != nil {
slog.Error("NATSKeyService: Failed to send NATS request", "err", err)
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Check if the response is an error
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
// Response is an error payload
slog.Error("NATSKeyService: Received error response from daemon", "code", responseError.Code)
return nil, fmt.Errorf("daemon returned error: %s", *responseError.Code)
}
// Unmarshal successful response
var output ec2.DescribeKeyPairsOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
slog.Error("NATSKeyService: Failed to unmarshal output", "err", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DescribeKeyPairsOutput](s.natsConn, "ec2.DescribeKeyPairs", input, 30*time.Second)
}
func (s *NATSKeyService) ImportKeyPair(input *ec2.ImportKeyPairInput) (*ec2.ImportKeyPairOutput, error) {
// Marshal input to JSON
jsonData, err := json.Marshal(input)
if err != nil {
slog.Error("NATSKeyService: Failed to marshal ImportKeyPairInput", "err", err)
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
// Send request to daemon via NATS with 30 second timeout
msg, err := s.natsConn.Request("ec2.ImportKeyPair", jsonData, 30*time.Second)
if err != nil {
slog.Error("NATSKeyService: Failed to send NATS request", "err", err)
return nil, fmt.Errorf("NATS request failed: %w", err)
}
// Check if the response is an error
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
// Response is an error payload
slog.Error("NATSKeyService: Received error response from daemon", "code", responseError.Code)
return nil, fmt.Errorf("daemon returned error: %s", *responseError.Code)
}
// Unmarshal successful response
var output ec2.ImportKeyPairOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
slog.Error("NATSKeyService: Failed to unmarshal output", "err", err)
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.ImportKeyPairOutput](s.natsConn, "ec2.ImportKeyPair", input, 30*time.Second)
}
+5 -118
View File
@@ -1,9 +1,6 @@
package handlers_ec2_volume
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
@@ -21,132 +18,22 @@ func NewNATSVolumeService(conn *nats.Conn) VolumeService {
return &NATSVolumeService{natsConn: conn}
}
// CreateVolume sends a CreateVolume request via NATS and waits for response
func (s *NATSVolumeService) CreateVolume(input *ec2.CreateVolumeInput) (*ec2.Volume, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := s.natsConn.Request("ec2.CreateVolume", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output ec2.Volume
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.Volume](s.natsConn, "ec2.CreateVolume", input, 30*time.Second)
}
// DescribeVolumes sends a DescribeVolumes request via NATS and waits for response
func (s *NATSVolumeService) DescribeVolumes(input *ec2.DescribeVolumesInput) (*ec2.DescribeVolumesOutput, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := s.natsConn.Request("ec2.DescribeVolumes", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output ec2.DescribeVolumesOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DescribeVolumesOutput](s.natsConn, "ec2.DescribeVolumes", input, 30*time.Second)
}
// ModifyVolume sends a ModifyVolume request via NATS and waits for response
func (s *NATSVolumeService) ModifyVolume(input *ec2.ModifyVolumeInput) (*ec2.ModifyVolumeOutput, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := s.natsConn.Request("ec2.ModifyVolume", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output ec2.ModifyVolumeOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.ModifyVolumeOutput](s.natsConn, "ec2.ModifyVolume", input, 30*time.Second)
}
// DescribeVolumeStatus sends a DescribeVolumeStatus request via NATS and waits for response
func (s *NATSVolumeService) DescribeVolumeStatus(input *ec2.DescribeVolumeStatusInput) (*ec2.DescribeVolumeStatusOutput, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := s.natsConn.Request("ec2.DescribeVolumeStatus", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output ec2.DescribeVolumeStatusOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DescribeVolumeStatusOutput](s.natsConn, "ec2.DescribeVolumeStatus", input, 30*time.Second)
}
// DeleteVolume sends a DeleteVolume request via NATS and waits for response
func (s *NATSVolumeService) DeleteVolume(input *ec2.DeleteVolumeInput) (*ec2.DeleteVolumeOutput, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := s.natsConn.Request("ec2.DeleteVolume", jsonData, 30*time.Second)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := utils.ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output ec2.DeleteVolumeOutput
err = json.Unmarshal(msg.Data, &output)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
return utils.NATSRequest[ec2.DeleteVolumeOutput](s.natsConn, "ec2.DeleteVolume", input, 30*time.Second)
}
+37
View File
@@ -0,0 +1,37 @@
package utils
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/nats-io/nats.go"
)
// NATSRequest performs a NATS request-response with JSON marshaling.
// It marshals the input, sends to the given subject, validates the response
// for error payloads, and unmarshals the successful response into Out.
func NATSRequest[Out any](conn *nats.Conn, subject string, input any, timeout time.Duration) (*Out, error) {
jsonData, err := json.Marshal(input)
if err != nil {
return nil, fmt.Errorf("failed to marshal input: %w", err)
}
msg, err := conn.Request(subject, jsonData, timeout)
if err != nil {
return nil, fmt.Errorf("NATS request failed: %w", err)
}
responseError, err := ValidateErrorPayload(msg.Data)
if err != nil {
return nil, errors.New(*responseError.Code)
}
var output Out
if err := json.Unmarshal(msg.Data, &output); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &output, nil
}