code.cloudfoundry.org/cli@v7.1.0+incompatible/actor/v2action/logging.go (about)

     1  package v2action
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/SermoDigital/jose/jws"
    10  
    11  	"code.cloudfoundry.org/cli/actor/sharedaction"
    12  )
    13  
    14  func (actor Actor) GetStreamingLogs(appGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc) {
    15  	return sharedaction.GetStreamingLogs(appGUID, client)
    16  }
    17  
    18  func (actor Actor) GetRecentLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client sharedaction.LogCacheClient) ([]sharedaction.LogMessage, Warnings, error) {
    19  	app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
    20  	if err != nil {
    21  		return nil, allWarnings, err
    22  	}
    23  
    24  	logCacheMessages, err := sharedaction.GetRecentLogs(app.GUID, client)
    25  	if err != nil {
    26  		return nil, allWarnings, err
    27  	}
    28  
    29  	var logMessages []sharedaction.LogMessage
    30  
    31  	for _, message := range logCacheMessages {
    32  		logMessages = append(logMessages, *sharedaction.NewLogMessage(
    33  			message.Message(),
    34  			message.Type(),
    35  			message.Timestamp(),
    36  			message.SourceType(),
    37  			message.SourceInstance(),
    38  		))
    39  	}
    40  
    41  	return logMessages, allWarnings, nil
    42  }
    43  
    44  func (actor Actor) GetStreamingLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, Warnings, error) {
    45  	app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
    46  	if err != nil {
    47  		return nil, nil, func() {}, allWarnings, err
    48  	}
    49  
    50  	messages, logErrs, stopStreaming := actor.GetStreamingLogs(app.GUID, client)
    51  
    52  	return messages, logErrs, stopStreaming, allWarnings, err
    53  }
    54  
    55  func (actor Actor) ScheduleTokenRefresh(
    56  	after func(time.Duration) <-chan time.Time,
    57  	stop chan struct{},
    58  	stoppedRefreshingToken chan struct{}) (<-chan error, error) {
    59  
    60  	timeToRefresh, err := actor.refreshAccessTokenIfNecessary()
    61  	if err != nil {
    62  		close(stoppedRefreshingToken)
    63  		return nil, err
    64  	}
    65  
    66  	refreshErrs := make(chan error)
    67  
    68  	go func() {
    69  		defer close(stoppedRefreshingToken)
    70  		for {
    71  			select {
    72  			case <-after(*timeToRefresh):
    73  				d, err := actor.refreshAccessTokenIfNecessary()
    74  				if err == nil {
    75  					timeToRefresh = d
    76  				} else {
    77  					refreshErrs <- err
    78  				}
    79  			case <-stop:
    80  				return
    81  			}
    82  		}
    83  	}()
    84  
    85  	return refreshErrs, nil
    86  }
    87  
    88  func (actor Actor) tokenExpiryTime(accessToken string) (*time.Duration, error) {
    89  	var expiresIn time.Duration
    90  
    91  	accessTokenString := strings.TrimPrefix(accessToken, "bearer ")
    92  	token, err := jws.ParseJWT([]byte(accessTokenString))
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	expiration, ok := token.Claims().Expiration()
    98  	if ok {
    99  		expiresIn = time.Until(expiration)
   100  	}
   101  	return &expiresIn, nil
   102  }
   103  
   104  func (actor Actor) refreshAccessTokenIfNecessary() (*time.Duration, error) {
   105  	accessToken := actor.Config.AccessToken()
   106  
   107  	duration, err := actor.tokenExpiryTime(accessToken)
   108  	if err != nil || *duration < time.Minute {
   109  		accessToken, err = actor.RefreshAccessToken(actor.Config.RefreshToken())
   110  		if err != nil {
   111  			return nil, err
   112  		}
   113  	}
   114  
   115  	accessToken = strings.TrimPrefix(accessToken, "bearer ")
   116  	token, err := jws.ParseJWT([]byte(accessToken))
   117  	if err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	var timeToRefresh time.Duration
   122  	expiration, ok := token.Claims().Expiration()
   123  	if !ok {
   124  		return nil, errors.New("Failed to get an expiry time from the current access token")
   125  	}
   126  	expiresIn := time.Until(expiration)
   127  	if expiresIn >= 2*time.Minute {
   128  		timeToRefresh = expiresIn - time.Minute
   129  	} else {
   130  		timeToRefresh = expiresIn * 9 / 10
   131  	}
   132  	return &timeToRefresh, nil
   133  }