simplify contract for state polling

This commit is contained in:
Jose Garcia 2021-08-27 17:34:06 -04:00
parent e5f45d4bfa
commit 368e8c6110
2 changed files with 58 additions and 76 deletions

View file

@ -106,64 +106,55 @@ func create(opts *createOptions) error {
}
func showStatus(ctx context.Context, log *output.Logger, apiClient *api.API, user *api.User, codespace *api.Codespace) error {
states, err := codespaces.PollPostCreateStates(ctx, log, apiClient, user, codespace)
if err != nil {
return fmt.Errorf("failed to subscribe to state changes from codespace: %v", err)
}
var lastState codespaces.PostCreateState
finishedStates := make(map[string]bool)
var breakNextState bool
PollStates:
for {
select {
case <-ctx.Done():
return nil
finishedStates := make(map[string]bool)
ctx, stopPolling := context.WithCancel(ctx)
case stateUpdate := <-states:
if stateUpdate.Err != nil {
return fmt.Errorf("receive state update: %v", err)
poller := func(states []codespaces.PostCreateState) {
var inProgress bool
for _, state := range states {
if _, found := finishedStates[state.Name]; found {
continue // skip this state as we've processed it already
}
var inProgress bool
for _, state := range stateUpdate.PostCreateStates {
if _, found := finishedStates[state.Name]; found {
continue // skip this state as we've processed it already
if state.Name != lastState.Name {
log.Print(state.Name)
if state.Status == codespaces.PostCreateStateRunning {
inProgress = true
lastState = state
log.Print("...")
break
}
if state.Name != lastState.Name {
log.Print(state.Name)
if state.Status == codespaces.PostCreateStateRunning {
inProgress = true
lastState = state
log.Print("...")
break
}
finishedStates[state.Name] = true
log.Println("..." + state.Status)
} else {
if state.Status == codespaces.PostCreateStateRunning {
inProgress = true
log.Print(".")
break
}
finishedStates[state.Name] = true
log.Println(state.Status)
lastState = codespaces.PostCreateState{} // reset the value
finishedStates[state.Name] = true
log.Println("..." + state.Status)
} else {
if state.Status == codespaces.PostCreateStateRunning {
inProgress = true
log.Print(".")
break
}
}
if !inProgress {
if breakNextState {
break PollStates
}
breakNextState = true
finishedStates[state.Name] = true
log.Println(state.Status)
lastState = codespaces.PostCreateState{} // reset the value
}
}
if !inProgress {
if breakNextState {
stopPolling()
return
}
breakNextState = true
}
}
if err := codespaces.PollPostCreateStates(ctx, log, apiClient, user, codespace, poller); err != nil {
return fmt.Errorf("failed to poll state changes from codespace: %v", err)
}
return nil

View file

@ -33,50 +33,40 @@ type PostCreateState struct {
Status PostCreateStateStatus `json:"status"`
}
func PollPostCreateStates(ctx context.Context, log logger, apiClient *api.API, user *api.User, codespace *api.Codespace) (<-chan PostCreateStatesResult, error) {
pollch := make(chan PostCreateStatesResult)
func PollPostCreateStates(ctx context.Context, log logger, apiClient *api.API, user *api.User, codespace *api.Codespace, poller func([]PostCreateState)) error {
token, err := apiClient.GetCodespaceToken(ctx, user.Login, codespace.Name)
if err != nil {
return nil, fmt.Errorf("getting codespace token: %v", err)
return fmt.Errorf("getting codespace token: %v", err)
}
lsclient, err := ConnectToLiveshare(ctx, log, apiClient, user.Login, token, codespace)
if err != nil {
return nil, fmt.Errorf("connect to liveshare: %v", err)
return fmt.Errorf("connect to liveshare: %v", err)
}
tunnelPort, connClosed, err := MakeSSHTunnel(ctx, lsclient, 0)
if err != nil {
return nil, fmt.Errorf("make ssh tunnel: %v", err)
return fmt.Errorf("make ssh tunnel: %v", err)
}
go func() {
t := time.NewTicker(1 * time.Second)
for {
select {
case <-ctx.Done():
return
case err := <-connClosed:
if err != nil {
pollch <- PostCreateStatesResult{Err: fmt.Errorf("connection closed: %v", err)}
return
}
case <-t.C:
states, err := getPostCreateOutput(ctx, tunnelPort, codespace)
if err != nil {
pollch <- PostCreateStatesResult{Err: fmt.Errorf("get post create output: %v", err)}
return
}
pollch <- PostCreateStatesResult{
PostCreateStates: states,
}
t := time.NewTicker(1 * time.Second)
for {
select {
case <-ctx.Done():
return nil
case err := <-connClosed:
return fmt.Errorf("connection closed: %v", err)
case <-t.C:
states, err := getPostCreateOutput(ctx, tunnelPort, codespace)
if err != nil {
return fmt.Errorf("get post create output: %v", err)
}
}
}()
return pollch, nil
poller(states)
}
}
return nil
}
func getPostCreateOutput(ctx context.Context, tunnelPort int, codespace *api.Codespace) ([]PostCreateState, error) {
@ -87,6 +77,7 @@ func getPostCreateOutput(ctx context.Context, tunnelPort int, codespace *api.Cod
if err != nil {
return nil, fmt.Errorf("run command: %v", err)
}
defer stdout.Close()
b, err := ioutil.ReadAll(stdout)
if err != nil {