From e27f0ed05b3a30a55bd9f5ad73d72d4705e86219 Mon Sep 17 00:00:00 2001 From: "Theodor S. Midtlien" Date: Tue, 2 Jun 2026 14:41:41 +0200 Subject: [PATCH] Clean up --- .../internal/profilemanager/profilemanager.go | 8 ++---- client/internal/profilemanager/service.go | 26 +++++++------------ client/proto/daemon.pb.go | 23 +++++++--------- client/proto/daemon.proto | 7 +---- client/server/server.go | 6 +---- 5 files changed, 23 insertions(+), 47 deletions(-) diff --git a/client/internal/profilemanager/profilemanager.go b/client/internal/profilemanager/profilemanager.go index 3c6c76c5a..b72348ca0 100644 --- a/client/internal/profilemanager/profilemanager.go +++ b/client/internal/profilemanager/profilemanager.go @@ -83,9 +83,7 @@ func NewProfileManager() *ProfileManager { } // GetActiveProfile returns the active profile as recorded in the local -// user state file. Only ID is populated; the display Name is not known -// at this layer — callers that need it should query the daemon's -// ListProfiles RPC. +// user state file. Only ID is populated. func (pm *ProfileManager) GetActiveProfile() (*Profile, error) { pm.mu.Lock() defer pm.mu.Unlock() @@ -95,9 +93,7 @@ func (pm *ProfileManager) GetActiveProfile() (*Profile, error) { } // SwitchProfile records the given profile ID as active in the local user -// state file. The CLI calls this after the daemon has resolved the user- -// supplied handle to a concrete ID, so the value written here is always a -// valid profile filename stem. +// state file. func (pm *ProfileManager) SwitchProfile(id string) error { if id != defaultProfileName && !IsValidProfileFilenameStem(id) { return fmt.Errorf("invalid profile ID: %q", id) diff --git a/client/internal/profilemanager/service.go b/client/internal/profilemanager/service.go index f0aeecc78..d7da191cf 100644 --- a/client/internal/profilemanager/service.go +++ b/client/internal/profilemanager/service.go @@ -46,9 +46,8 @@ const ( AmbiguityKindName ) -// profileMeta is the minimal slice of a profile JSON we need for the list. -// Using a private struct here avoids running the full Config.apply() -// pipeline (which can rewrite the file) on every list operation. +// profileMeta is the minimal slice of a profile JSON we need, so we avoid +// reading all fields type profileMeta struct { Name string } @@ -87,11 +86,11 @@ func init() { } type ActiveProfileState struct { - // ID is the on-disk filename stem of the active profile. The JSON - // tag stays as "name" for backwards compatibility with active state - // files written before the ID-keyed layout. Legacy values were - // profile names, which were also the legacy filename stems, so they - // still resolve to the correct file on disk. + // ID is the on-disk filename stem of the active profile. The JSON tag stays + // as "name" for backwards compatibility with active state files written + // before the ID-based config files. Legacy values were profile names, which + // were also the legacy filename stems, so they still resolve to the correct + // file on disk. ID string `json:"name"` Username string `json:"username"` } @@ -373,8 +372,6 @@ func (s *ServiceManager) RemoveProfile(id, username string) error { return fmt.Errorf("failed to remove profile config: %w", err) } - // Best-effort state file cleanup. Missing is fine — state files are - // only created on demand. stateFile := filepath.Join(filepath.Dir(target.Path), id+".state.json") if err := os.Remove(stateFile); err != nil && !os.IsNotExist(err) { log.Warnf("failed to remove profile state file %s: %v", stateFile, err) @@ -436,8 +433,8 @@ func (s *ServiceManager) getConfigDir(username string) (string, error) { // by ID for a stable display order. // // Each Profile is fully populated: ID is the filename stem, Name comes -// from the JSON's "name" field (falling back to the ID when absent), and -// Path is built from a basename read off disk (path-traversal safe). +// from the JSON's "name" field (falling back to the filename stem when absent) +// and Path is built from a basename read off disk. func (s *ServiceManager) loadAllProfiles(username string) ([]Profile, error) { activeID, activeIsDefault := s.activeProfileID() @@ -545,15 +542,13 @@ func (s *ServiceManager) ResolveProfile(handle, username string) (*Profile, erro return nil, err } - // Exact ID match wins outright — covers the default profile and any - // legacy profile whose ID is its name. for i := range profiles { if profiles[i].ID == handle { return &profiles[i], nil } } - // ID prefix match. Skip the default profile so a `select d` does not + // ID prefix match. Skip the default profile so `select d` does not // accidentally pick it via prefix. var prefixMatches []Profile for i := range profiles { @@ -575,7 +570,6 @@ func (s *ServiceManager) ResolveProfile(handle, username string) (*Profile, erro } } - // Exact name match. var nameMatches []Profile for i := range profiles { if profiles[i].Name == handle { diff --git a/client/proto/daemon.pb.go b/client/proto/daemon.pb.go index a8dc7ad60..9a6e60500 100644 --- a/client/proto/daemon.pb.go +++ b/client/proto/daemon.pb.go @@ -4427,7 +4427,7 @@ func (x *AddProfileRequest) GetProfileName() string { type AddProfileResponse struct { state protoimpl.MessageState `protogen:"open.v1"` // id is the generated on-disk ID of the new profile. CLI clients - // display a truncated form; UI clients can ignore it. + // display a truncated form, UI clients can ignore it. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -4659,12 +4659,10 @@ func (x *ListProfilesResponse) GetProfiles() []*Profile { } type Profile struct { - state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - IsActive bool `protobuf:"varint,2,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` - // id is the on-disk filename stem of the profile. Always set by the - // server; older clients that ignore it continue to work via name. - Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + IsActive bool `protobuf:"varint,2,opt,name=is_active,json=isActive,proto3" json:"is_active,omitempty"` + Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4757,13 +4755,10 @@ func (*GetActiveProfileRequest) Descriptor() ([]byte, []int) { } type GetActiveProfileResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - // profileName carries the display name for backwards compatibility - // with UI clients. New callers should prefer id, which is unique. - ProfileName string `protobuf:"bytes,1,opt,name=profileName,proto3" json:"profileName,omitempty"` - Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` - // id is the on-disk filename stem of the active profile. - Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + ProfileName string `protobuf:"bytes,1,opt,name=profileName,proto3" json:"profileName,omitempty"` + Username string `protobuf:"bytes,2,opt,name=username,proto3" json:"username,omitempty"` + Id string `protobuf:"bytes,3,opt,name=id,proto3" json:"id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } diff --git a/client/proto/daemon.proto b/client/proto/daemon.proto index fc3c63a4a..c1cd57d39 100644 --- a/client/proto/daemon.proto +++ b/client/proto/daemon.proto @@ -698,7 +698,7 @@ message AddProfileRequest { message AddProfileResponse { // id is the generated on-disk ID of the new profile. CLI clients - // display a truncated form; UI clients can ignore it. + // display a truncated form, UI clients can ignore it. string id = 1; } @@ -726,19 +726,14 @@ message ListProfilesResponse { message Profile { string name = 1; bool is_active = 2; - // id is the on-disk filename stem of the profile. Always set by the - // server; older clients that ignore it continue to work via name. string id = 3; } message GetActiveProfileRequest {} message GetActiveProfileResponse { - // profileName carries the display name for backwards compatibility - // with UI clients. New callers should prefer id, which is unique. string profileName = 1; string username = 2; - // id is the on-disk filename stem of the active profile. string id = 3; } diff --git a/client/server/server.go b/client/server/server.go index e7a44a9d2..0675e8449 100644 --- a/client/server/server.go +++ b/client/server/server.go @@ -1011,8 +1011,6 @@ func (s *Server) canRemoveProfile(id string) error { return nil } -// validateProfileOperation runs the common preconditions for add/remove/ -// logout flows. `id` is the resolved profile ID (never user input). func (s *Server) validateProfileOperation(id string, allowActiveProfile bool) error { if s.checkProfilesDisabled() { return gstatus.Errorf(codes.Unavailable, errProfilesDisabled) @@ -1031,8 +1029,6 @@ func (s *Server) validateProfileOperation(id string, allowActiveProfile bool) er return nil } -// logoutFromProfile logs out from a specific (already-resolved) profile -// by loading its config and sending a logout request. func (s *Server) logoutFromProfile(ctx context.Context, profile *profilemanager.Profile) error { activeProf, err := s.profileManager.GetActiveProfileState() if err == nil && activeProf.ID == profile.ID && s.connectClient != nil { @@ -1639,7 +1635,7 @@ func (s *Server) ListProfiles(ctx context.Context, msg *proto.ListProfilesReques // GetActiveProfile returns the active profile in the daemon. The // ProfileName field carries the display name for backwards compatibility -// with UI clients; new callers should prefer Id. +// with UI clients, new callers should prefer Id. func (s *Server) GetActiveProfile(ctx context.Context, msg *proto.GetActiveProfileRequest) (*proto.GetActiveProfileResponse, error) { s.mutex.Lock() defer s.mutex.Unlock()