github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/service/prompting/stream.go (about)

     1  package prompting
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  )
     7  
     8  // streamPrompter implements Prompter on top of a Prompting_HostServer stream.
     9  type streamPrompter struct {
    10  	// allowPrompts indicates whether or not the client allows prompts.
    11  	allowPrompts bool
    12  	// stream is the underlying Prompting_HostServer stream.
    13  	stream Prompting_HostServer
    14  	// errored indicates whether or not the stream has encountered an error.
    15  	errored bool
    16  }
    17  
    18  // sendReceive performs a send/receive cycle by sending a HostResponse and
    19  // receiving a HostRequest.
    20  func (p *streamPrompter) sendReceive(response *HostResponse) (*HostRequest, error) {
    21  	// Send the request.
    22  	if err := p.stream.Send(response); err != nil {
    23  		return nil, fmt.Errorf("unable to send response: %w", err)
    24  	}
    25  
    26  	// Determine the expected request mode.
    27  	mode := hostRequestModeMessageResponse
    28  	if response.IsPrompt {
    29  		mode = hostRequestModePromptResponse
    30  	}
    31  
    32  	// Receive the response.
    33  	if request, err := p.stream.Recv(); err != nil {
    34  		return nil, fmt.Errorf("unable to receive request: %w", err)
    35  	} else if err = request.ensureValid(mode); err != nil {
    36  		return nil, fmt.Errorf("invalid request received: %w", err)
    37  	} else {
    38  		return request, nil
    39  	}
    40  }
    41  
    42  // Message implements the Message method of Prompter.
    43  func (p *streamPrompter) Message(message string) error {
    44  	// Check if a previous transmission error has occurred.
    45  	if p.errored {
    46  		return errors.New("prompter encountered previous error")
    47  	}
    48  
    49  	// Otherwise perform the messaging operation.
    50  	if _, err := p.sendReceive(&HostResponse{Message: message}); err != nil {
    51  		p.errored = true
    52  		return err
    53  	}
    54  
    55  	// Success.
    56  	return nil
    57  }
    58  
    59  // Prompt implements the Prompt method of Prompter.
    60  func (p *streamPrompter) Prompt(prompt string) (string, error) {
    61  	// Check if a previous transmission error has occurred.
    62  	if p.errored {
    63  		return "", errors.New("prompter encountered previous error")
    64  	}
    65  
    66  	// Check whether or not prompts are supported by this client.
    67  	if !p.allowPrompts {
    68  		return "", errors.New("prompter only supports messaging")
    69  	}
    70  
    71  	// Perform the exchange.
    72  	response, err := p.sendReceive(&HostResponse{IsPrompt: true, Message: prompt})
    73  	if err != nil {
    74  		p.errored = true
    75  		return "", err
    76  	}
    77  
    78  	// Success.
    79  	return response.Response, nil
    80  }