github.com/sleungcy/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 }