path string
issuer string
http *http.Client
- clock func() time.Time
}
// tokenFile is the content of the token file.
}
// login runs "onechat login": the device code login into the token file of the
-// data directory.
-func login(ctx context.Context, out io.Writer) error {
+// data directory. It holds the lock of the token file, so it does not run while
+// the daemon runs.
+func login(ctx context.Context, out io.Writer) (err error) {
dir, err := dataDir()
if err != nil {
return err
}
+ tokens, err := lockTokens(dir)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ err = errors.Join(err, tokens.Close())
+ }()
+
return newChatGPTAuth(filepath.Join(dir, tokenFileName), authIssuer).Login(ctx, out)
}
path: path,
issuer: issuer,
http: &http.Client{},
- clock: time.Now,
}
}
}
expiry, found := tokenExpiry(tokens.AccessToken)
- if !found || !a.clock().Before(expiry.Add(-refreshMargin)) {
+ if !found || !time.Now().Before(expiry.Add(-refreshMargin)) {
tokens, err = a.refresh(ctx, tokens)
if err != nil {
return err