feat: support in-memory authentication
This commit is contained in:
@@ -24,7 +24,10 @@ const (
|
||||
availabilityTTL = 60 * time.Second
|
||||
)
|
||||
|
||||
type Option func(*Client) error
|
||||
type ClientOption func(*Client) error
|
||||
|
||||
// Option is kept as an alias for compatibility with existing callers.
|
||||
type Option = ClientOption
|
||||
|
||||
// WithHTTPClient configures the HTTP transport used by the client.
|
||||
func WithHTTPClient(httpClient *http.Client) Option {
|
||||
@@ -58,6 +61,7 @@ func WithQRWriter(writer io.Writer) Option {
|
||||
|
||||
type Client struct {
|
||||
authPath string
|
||||
authDataChanged func(AuthData) error
|
||||
authMu sync.RWMutex
|
||||
authData AuthData
|
||||
loginMu sync.Mutex
|
||||
@@ -80,8 +84,34 @@ func NewClient(authPath string, options ...Option) (*Client, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := newClient(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.authPath = resolvedPath
|
||||
if err := client.loadAuthData(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.ensureIdentity()
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// NewClientWithAuthData creates a client whose authentication state is kept in memory.
|
||||
// Zero AuthData is accepted for QR login; non-zero AuthData must be complete.
|
||||
func NewClientWithAuthData(authData AuthData, options ...ClientOption) (*Client, error) {
|
||||
if !authData.zero() && !authData.complete() {
|
||||
return nil, fmt.Errorf("incomplete auth data")
|
||||
}
|
||||
client, err := newClient(options...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.setAuthData(authData)
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func newClient(options ...ClientOption) (*Client, error) {
|
||||
client := &Client{
|
||||
authPath: resolvedPath,
|
||||
httpClient: http.DefaultClient,
|
||||
baseURL: defaultBaseURL,
|
||||
loginURL: defaultLoginURL,
|
||||
@@ -97,14 +127,22 @@ func NewClient(authPath string, options ...Option) (*Client, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := client.loadAuthData(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.ensureIdentity()
|
||||
client.initSession()
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// WithAuthDataChanged configures serialized persistence for in-memory auth updates.
|
||||
// The callback runs under login serialization, but never while the auth data lock is held.
|
||||
func WithAuthDataChanged(callback func(AuthData) error) ClientOption {
|
||||
return func(client *Client) error {
|
||||
if callback == nil {
|
||||
return fmt.Errorf("auth data changed callback must not be nil")
|
||||
}
|
||||
client.authDataChanged = callback
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func resolveAuthPath(authPath string) (string, error) {
|
||||
if authPath == "" {
|
||||
home, err := os.UserHomeDir()
|
||||
|
||||
Reference in New Issue
Block a user