github.com/sld880311/docker@v0.0.0-20200524143708-d5593973a475/cli/command/container/tty.go (about)

     1  package container
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	gosignal "os/signal"
     7  	"runtime"
     8  	"time"
     9  
    10  	"github.com/Sirupsen/logrus"
    11  	"github.com/docker/docker/api/types"
    12  	"github.com/docker/docker/cli/command"
    13  	"github.com/docker/docker/client"
    14  	"github.com/docker/docker/pkg/signal"
    15  	"golang.org/x/net/context"
    16  )
    17  
    18  // resizeTtyTo resizes tty to specific height and width
    19  func resizeTtyTo(ctx context.Context, client client.ContainerAPIClient, id string, height, width uint, isExec bool) {
    20  	if height == 0 && width == 0 {
    21  		return
    22  	}
    23  
    24  	options := types.ResizeOptions{
    25  		Height: height,
    26  		Width:  width,
    27  	}
    28  
    29  	var err error
    30  	if isExec {
    31  		err = client.ContainerExecResize(ctx, id, options)
    32  	} else {
    33  		err = client.ContainerResize(ctx, id, options)
    34  	}
    35  
    36  	if err != nil {
    37  		logrus.Debugf("Error resize: %s", err)
    38  	}
    39  }
    40  
    41  // MonitorTtySize updates the container tty size when the terminal tty changes size
    42  func MonitorTtySize(ctx context.Context, cli *command.DockerCli, id string, isExec bool) error {
    43  	resizeTty := func() {
    44  		height, width := cli.Out().GetTtySize()
    45  		resizeTtyTo(ctx, cli.Client(), id, height, width, isExec)
    46  	}
    47  
    48  	resizeTty()
    49  
    50  	if runtime.GOOS == "windows" {
    51  		go func() {
    52  			prevH, prevW := cli.Out().GetTtySize()
    53  			for {
    54  				time.Sleep(time.Millisecond * 250)
    55  				h, w := cli.Out().GetTtySize()
    56  
    57  				if prevW != w || prevH != h {
    58  					resizeTty()
    59  				}
    60  				prevH = h
    61  				prevW = w
    62  			}
    63  		}()
    64  	} else {
    65  		sigchan := make(chan os.Signal, 1)
    66  		gosignal.Notify(sigchan, signal.SIGWINCH)
    67  		go func() {
    68  			for range sigchan {
    69  				resizeTty()
    70  			}
    71  		}()
    72  	}
    73  	return nil
    74  }
    75  
    76  // ForwardAllSignals forwards signals to the container
    77  func ForwardAllSignals(ctx context.Context, cli *command.DockerCli, cid string) chan os.Signal {
    78  	sigc := make(chan os.Signal, 128)
    79  	signal.CatchAll(sigc)
    80  	go func() {
    81  		for s := range sigc {
    82  			if s == signal.SIGCHLD || s == signal.SIGPIPE {
    83  				continue
    84  			}
    85  			var sig string
    86  			for sigStr, sigN := range signal.SignalMap {
    87  				if sigN == s {
    88  					sig = sigStr
    89  					break
    90  				}
    91  			}
    92  			if sig == "" {
    93  				fmt.Fprintf(cli.Err(), "Unsupported signal: %v. Discarding.\n", s)
    94  				continue
    95  			}
    96  
    97  			if err := cli.Client().ContainerKill(ctx, cid, sig); err != nil {
    98  				logrus.Debugf("Error sending signal: %s", err)
    99  			}
   100  		}
   101  	}()
   102  	return sigc
   103  }