Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ require (
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1
github.com/otiai10/copy v1.14.1
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc
github.com/sirupsen/logrus v1.9.3
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.9.1
Expand Down Expand Up @@ -193,7 +192,6 @@ require (
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
5 changes: 0 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc h1:zAsgcP8MhzAbhMnB1QQ2O7ZhWYVGYSR2iVcjzQuPV+o=
github.com/r3labs/sse v0.0.0-20210224172625-26fe804710bc/go.mod h1:S8xSOnV3CgpNrWd0GQ/OoQfMtlg2uPRSuTzcSGrzwK8=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
Expand Down Expand Up @@ -561,7 +559,6 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
Expand Down Expand Up @@ -637,8 +634,6 @@ google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwl
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=
gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI=
gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
gopkg.in/cenkalti/backoff.v2 v2.2.1/go.mod h1:S0QdOvT2AlerfSBkp0O+dk+bbIMaNbEmVk876gPCthU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
209 changes: 0 additions & 209 deletions internal/desktop/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@
package desktop

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net"
Expand All @@ -29,7 +27,6 @@ import (

"github.com/docker/compose/v2/internal"
"github.com/docker/compose/v2/internal/memnet"
"github.com/r3labs/sse"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
)

Expand Down Expand Up @@ -130,212 +127,6 @@ func (c *Client) FeatureFlags(ctx context.Context) (FeatureFlagResponse, error)
return ret, nil
}

type GetFileSharesConfigResponse struct {
Active bool `json:"active"`
Compose struct {
ManageBindMounts bool `json:"manageBindMounts"`
}
}

func (c *Client) GetFileSharesConfig(ctx context.Context) (*GetFileSharesConfigResponse, error) {
req, err := c.newRequest(ctx, http.MethodGet, "/mutagen/file-shares/config", http.NoBody)
if err != nil {
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode != http.StatusOK {
return nil, newHTTPStatusCodeError(resp)
}

var ret GetFileSharesConfigResponse
if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

type CreateFileShareRequest struct {
HostPath string `json:"hostPath"`
Labels map[string]string `json:"labels,omitempty"`
}

type CreateFileShareResponse struct {
FileShareID string `json:"fileShareID"`
}

func (c *Client) CreateFileShare(ctx context.Context, r CreateFileShareRequest) (*CreateFileShareResponse, error) {
rawBody, err := json.Marshal(r)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}

req, err := c.newRequest(ctx, http.MethodPost, "/mutagen/file-shares", bytes.NewReader(rawBody))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")

resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode != http.StatusOK {
errBody, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(errBody))
}

var ret CreateFileShareResponse
if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
return nil, err
}
return &ret, nil
}

type FileShareReceiverState struct {
TotalReceivedSize uint64 `json:"totalReceivedSize"`
}

type FileShareEndpoint struct {
Path string `json:"path"`
TotalFileSize uint64 `json:"totalFileSize,omitempty"`
StagingProgress *FileShareReceiverState `json:"stagingProgress"`
}

type FileShareSession struct {
SessionID string `json:"identifier"`
Alpha FileShareEndpoint `json:"alpha"`
Beta FileShareEndpoint `json:"beta"`
Labels map[string]string `json:"labels"`
Status string `json:"status"`
}

func (c *Client) ListFileShares(ctx context.Context) ([]FileShareSession, error) {
req, err := c.newRequest(ctx, http.MethodGet, "/mutagen/file-shares", http.NoBody)
if err != nil {
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode != http.StatusOK {
return nil, newHTTPStatusCodeError(resp)
}

var ret []FileShareSession
if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
return nil, err
}
return ret, nil
}

func (c *Client) DeleteFileShare(ctx context.Context, id string) error {
req, err := c.newRequest(ctx, http.MethodDelete, "/mutagen/file-shares/"+id, http.NoBody)
if err != nil {
return err
}

resp, err := c.client.Do(req)
if err != nil {
return err
}
defer func() {
_ = resp.Body.Close()
}()

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return newHTTPStatusCodeError(resp)
}
return nil
}

type EventMessage[T any] struct {
Value T
Error error
}

func newHTTPStatusCodeError(resp *http.Response) error {
r := io.LimitReader(resp.Body, 2048)
body, err := io.ReadAll(r)
if err != nil {
return fmt.Errorf("http status code %d", resp.StatusCode)
}
return fmt.Errorf("http status code %d: %s", resp.StatusCode, string(body))
}

func (c *Client) StreamFileShares(ctx context.Context) (<-chan EventMessage[[]FileShareSession], error) {
req, err := c.newRequest(ctx, http.MethodGet, "/mutagen/file-shares/stream", http.NoBody)
if err != nil {
return nil, err
}

resp, err := c.client.Do(req)
if err != nil {
return nil, err
}

if resp.StatusCode < 200 || resp.StatusCode >= 300 {
_ = resp.Body.Close()
return nil, newHTTPStatusCodeError(resp)
}

events := make(chan EventMessage[[]FileShareSession])
go func(ctx context.Context) {
defer func() {
_ = resp.Body.Close()
close(events)
}()
if err := readEvents(ctx, resp.Body, events); err != nil {
select {
case <-ctx.Done():
case events <- EventMessage[[]FileShareSession]{Error: err}:
}
}
}(ctx)
return events, nil
}

func readEvents[T any](ctx context.Context, r io.Reader, events chan<- EventMessage[T]) error {
eventReader := sse.NewEventStreamReader(r)
for {
msg, err := eventReader.ReadEvent()
if errors.Is(err, io.EOF) {
return nil
} else if err != nil {
return fmt.Errorf("reading events: %w", err)
}
msg = bytes.TrimPrefix(msg, []byte("data: "))

var event T
if err := json.Unmarshal(msg, &event); err != nil {
return err
}
select {
case <-ctx.Done():
return context.Cause(ctx)
case events <- EventMessage[T]{Value: event}:
// event was sent to channel, read next
}
}
}

func (c *Client) newRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequestWithContext(ctx, method, backendURL(path), body)
if err != nil {
Expand Down
Loading