gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/tunnel/listener.go (about)

     1  package tunnel
     2  
     3  import (
     4  	"io"
     5  	"time"
     6  
     7  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/log"
     8  )
     9  
    10  type tunListener struct {
    11  	// address of the listener
    12  	channel string
    13  	// token is the tunnel token
    14  	token string
    15  	// the accept channel
    16  	accept chan *session
    17  	// the channel to close
    18  	closed chan bool
    19  	// the tunnel closed channel
    20  	tunClosed chan bool
    21  	// the listener session
    22  	session *session
    23  	// del func to kill listener
    24  	delFunc func()
    25  }
    26  
    27  // periodically announce self the channel being listened on
    28  func (t *tunListener) announce() {
    29  	tick := time.NewTicker(time.Second * 30)
    30  	defer tick.Stop()
    31  
    32  	// first announcement
    33  	t.session.Announce()
    34  
    35  	for {
    36  		select {
    37  		case <-tick.C:
    38  			t.session.Announce()
    39  		case <-t.closed:
    40  			return
    41  		}
    42  	}
    43  }
    44  
    45  func (t *tunListener) process() {
    46  	// our connection map for session
    47  	conns := make(map[string]*session)
    48  
    49  	defer func() {
    50  		// close the sessions
    51  		for id, conn := range conns {
    52  			conn.Close()
    53  			delete(conns, id)
    54  		}
    55  		// unassign
    56  		conns = nil
    57  	}()
    58  
    59  	for {
    60  		select {
    61  		case <-t.closed:
    62  			return
    63  		case <-t.tunClosed:
    64  			t.Close()
    65  			return
    66  		// receive a new message
    67  		case m := <-t.session.recv:
    68  			var sessionId string
    69  			var linkId string
    70  
    71  			switch m.mode {
    72  			case Multicast:
    73  				sessionId = "multicast"
    74  				linkId = "multicast"
    75  			case Broadcast:
    76  				sessionId = "broadcast"
    77  				linkId = "broadcast"
    78  			default:
    79  				sessionId = m.session
    80  				linkId = m.link
    81  			}
    82  
    83  			// get a session
    84  			sess, ok := conns[sessionId]
    85  			log.Tracef("Tunnel listener received channel %s session %s type %s exists: %t", m.channel, m.session, m.typ, ok)
    86  			if !ok {
    87  				// we only process open and session types
    88  				switch m.typ {
    89  				case "open", "session":
    90  				default:
    91  					continue
    92  				}
    93  
    94  				// create a new session session
    95  				sess = &session{
    96  					// the id of the remote side
    97  					tunnel: m.tunnel,
    98  					// the channel
    99  					channel: m.channel,
   100  					// the session id
   101  					session: sessionId,
   102  					// tunnel token
   103  					token: t.token,
   104  					// is loopback conn
   105  					loopback: m.loopback,
   106  					// the link the message was received on
   107  					link: linkId,
   108  					// set the connection mode
   109  					mode: m.mode,
   110  					// close chan
   111  					closed: make(chan bool),
   112  					// recv called by the acceptor
   113  					recv: make(chan *message, 128),
   114  					// use the internal send buffer
   115  					send: t.session.send,
   116  					// error channel
   117  					errChan: make(chan error, 1),
   118  					// set the read timeout
   119  					readTimeout: t.session.readTimeout,
   120  				}
   121  
   122  				// save the session
   123  				conns[sessionId] = sess
   124  
   125  				select {
   126  				case <-t.closed:
   127  					return
   128  				// send to accept chan
   129  				case t.accept <- sess:
   130  				}
   131  			}
   132  
   133  			// an existing session was found
   134  
   135  			switch m.typ {
   136  			case "close":
   137  				// received a close message
   138  				select {
   139  				// check if the session is closed
   140  				case <-sess.closed:
   141  					// no op
   142  					delete(conns, sessionId)
   143  				default:
   144  					// only close if unicast session
   145  					// close and delete session
   146  					close(sess.closed)
   147  					delete(conns, sessionId)
   148  				}
   149  
   150  				// continue
   151  				continue
   152  			case "session":
   153  				// operate on this
   154  			default:
   155  				// non operational type
   156  				continue
   157  			}
   158  
   159  			// send this to the accept chan
   160  			select {
   161  			case <-sess.closed:
   162  				delete(conns, sessionId)
   163  			case sess.recv <- m:
   164  				log.Tracef("Tunnel listener sent to recv chan channel %s session %s type %s", m.channel, sessionId, m.typ)
   165  			}
   166  		}
   167  	}
   168  }
   169  
   170  func (t *tunListener) Channel() string {
   171  	return t.channel
   172  }
   173  
   174  // Close closes tunnel listener
   175  func (t *tunListener) Close() error {
   176  	select {
   177  	case <-t.closed:
   178  		return nil
   179  	default:
   180  		// close and delete
   181  		t.delFunc()
   182  		t.session.Close()
   183  		close(t.closed)
   184  	}
   185  	return nil
   186  }
   187  
   188  // Everytime accept is called we essentially block till we get a new connection
   189  func (t *tunListener) Accept() (Session, error) {
   190  	select {
   191  	// if the session is closed return
   192  	case <-t.closed:
   193  		return nil, io.EOF
   194  	case <-t.tunClosed:
   195  		// close the listener when the tunnel closes
   196  		return nil, io.EOF
   197  	// wait for a new connection
   198  	case c, ok := <-t.accept:
   199  		// check if the accept chan is closed
   200  		if !ok {
   201  			return nil, io.EOF
   202  		}
   203  		// return without accept
   204  		if c.mode != Unicast {
   205  			return c, nil
   206  		}
   207  		// send back the accept
   208  		if err := c.Accept(); err != nil {
   209  			return nil, err
   210  		}
   211  		return c, nil
   212  	}
   213  }