github.com/micro/go-micro/examples@v0.0.0-20210105173217-bf4ab679e18b/tunnel/echo/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  
     9  	"github.com/google/uuid"
    10  	"github.com/micro/go-micro/v2/transport"
    11  	"github.com/micro/go-micro/v2/tunnel"
    12  )
    13  
    14  var (
    15  	address = flag.String("address", ":10001", "tunnel address")
    16  	nodes   = flag.String("nodes", "", "tunnel nodes")
    17  	channel = flag.String("channel", "default", "the channel")
    18  )
    19  
    20  func readLoop(c tunnel.Session, readChan chan *transport.Message) {
    21  	for {
    22  		m := new(transport.Message)
    23  		if err := c.Recv(m); err != nil {
    24  			return
    25  		}
    26  
    27  		// fire them into the channel
    28  		select {
    29  		case readChan <- m:
    30  		default:
    31  		}
    32  	}
    33  }
    34  
    35  func writeLoop(c tunnel.Session, sendChan chan *transport.Message) {
    36  	for {
    37  		m := <-sendChan
    38  
    39  		// don't relay back to sender
    40  		if c.Id() == m.Header["Session"] {
    41  			continue
    42  		}
    43  
    44  		// send messages
    45  		if err := c.Send(m); err != nil {
    46  			return
    47  		}
    48  	}
    49  }
    50  
    51  func serverAccept(l tunnel.Listener, sendChan chan *transport.Message) {
    52  	connCh := make(chan chan *transport.Message)
    53  
    54  	go func() {
    55  		conns := make(map[string]chan *transport.Message)
    56  
    57  		for {
    58  			// send all things we're writing to all connections
    59  			select {
    60  			case b := <-sendChan:
    61  				for _, c := range conns {
    62  					select {
    63  					case c <- b:
    64  					default:
    65  					}
    66  				}
    67  			// append new connections
    68  			case c := <-connCh:
    69  				conns[uuid.New().String()] = c
    70  			}
    71  		}
    72  	}()
    73  
    74  	for {
    75  		c, err := l.Accept()
    76  		if err != nil {
    77  			return
    78  		}
    79  
    80  		fmt.Println("Accepting new connection")
    81  
    82  		// pass to reader
    83  		rch := make(chan *transport.Message)
    84  		connCh <- rch
    85  
    86  		// send anything we receive
    87  		go readLoop(c, sendChan)
    88  
    89  		// write our messages to conn
    90  		go writeLoop(c, rch)
    91  	}
    92  }
    93  
    94  func main() {
    95  	flag.Parse()
    96  
    97  	// create a tunnel
    98  	tun := tunnel.NewTunnel(
    99  		tunnel.Address(*address),
   100  		tunnel.Nodes(*nodes),
   101  	)
   102  	if err := tun.Connect(); err != nil {
   103  		fmt.Println(err)
   104  		return
   105  	}
   106  	defer tun.Close()
   107  
   108  	// listen for inbound messages on the channel
   109  	l, err := tun.Listen(*channel)
   110  	if err != nil {
   111  		fmt.Println(err)
   112  		return
   113  	}
   114  	defer l.Close()
   115  
   116  	sendChan := make(chan *transport.Message)
   117  	printChan := make(chan *transport.Message)
   118  
   119  	// accept the messages on the channel
   120  	go serverAccept(l, sendChan)
   121  
   122  	// client code
   123  
   124  	// dial an outbound connection for the channel
   125  	c, err := tun.Dial(*channel)
   126  	if err != nil {
   127  		fmt.Println(err)
   128  		return
   129  	}
   130  	defer c.Close()
   131  
   132  	// write the things we get back
   133  	go func() {
   134  		for m := range printChan {
   135  			if m.Header["Session"] == c.Id() {
   136  				continue
   137  			}
   138  			fmt.Println(string(m.Body))
   139  		}
   140  	}()
   141  
   142  	// read and print what we get back on the dialled conn
   143  	go readLoop(c, printChan)
   144  
   145  	// read input and send over the tunnel
   146  	scanner := bufio.NewScanner(os.Stdin)
   147  
   148  	for scanner.Scan() {
   149  		m := &transport.Message{
   150  			Header: map[string]string{
   151  				"Session": c.Id(),
   152  			},
   153  			Body: scanner.Bytes(),
   154  		}
   155  
   156  		// send to all listeners
   157  		sendChan <- m
   158  
   159  		// send it also
   160  		c.Send(m)
   161  	}
   162  }