initialize session+client if needed, return: * the initialized client * a cleanup func to run when the call is done nolint:gocyclo // session/client initialization is an intentionally linear state machine.
( ctx context.Context, opts *ClientInitOpts, )
| 811 | // |
| 812 | //nolint:gocyclo // session/client initialization is an intentionally linear state machine. |
| 813 | func (srv *Server) getOrInitClient( |
| 814 | ctx context.Context, |
| 815 | opts *ClientInitOpts, |
| 816 | ) (_ *daggerClient, _ func() error, rerr error) { |
| 817 | if srv.isShuttingDown() { |
| 818 | return nil, nil, errServerShuttingDown |
| 819 | } |
| 820 | |
| 821 | sessionID := opts.SessionID |
| 822 | if sessionID == "" { |
| 823 | return nil, nil, fmt.Errorf("session ID is required") |
| 824 | } |
| 825 | clientID := opts.ClientID |
| 826 | if clientID == "" { |
| 827 | return nil, nil, fmt.Errorf("client ID is required") |
| 828 | } |
| 829 | token := opts.ClientSecretToken |
| 830 | if token == "" { |
| 831 | return nil, nil, fmt.Errorf("client secret token is required") |
| 832 | } |
| 833 | |
| 834 | // cleanup to do if this method fails |
| 835 | failureCleanups := &cleanups.Cleanups{} |
| 836 | defer func() { |
| 837 | if rerr != nil { |
| 838 | rerr = errors.Join(rerr, failureCleanups.Run()) |
| 839 | } |
| 840 | }() |
| 841 | |
| 842 | // get or initialize the session as a whole |
| 843 | |
| 844 | srv.daggerSessionsMu.Lock() |
| 845 | if srv.isShuttingDown() { |
| 846 | srv.daggerSessionsMu.Unlock() |
| 847 | return nil, nil, errServerShuttingDown |
| 848 | } |
| 849 | sess, sessionExists := srv.daggerSessions[sessionID] |
| 850 | stateMuLocked := false |
| 851 | if !sessionExists { |
| 852 | sess = &daggerSession{ |
| 853 | state: sessionStateUninitialized, |
| 854 | } |
| 855 | // Lock stateMu before publishing the session below so a concurrent |
| 856 | // clientFromIDs that looks it up blocks until initialization finishes |
| 857 | // instead of observing uninitialized fields. The session is still |
| 858 | // unreachable by other goroutines here, so this never blocks and can't |
| 859 | // invert removeDaggerSession's stateMu->daggerSessionsMu order even |
| 860 | // though we currently hold daggerSessionsMu. |
| 861 | sess.stateMu.Lock() |
| 862 | stateMuLocked = true |
| 863 | srv.daggerSessions[sessionID] = sess |
| 864 | |
| 865 | failureCleanups.Add("delete session ID", func() error { |
| 866 | srv.daggerSessionsMu.Lock() |
| 867 | delete(srv.daggerSessions, sessionID) |
| 868 | srv.daggerSessionsMu.Unlock() |
| 869 | return nil |
| 870 | }) |
no test coverage detected