github.com/godevsig/adaptiveservice@v0.9.23/registry.go (about)

     1  package adaptiveservice
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"os"
     9  	"reflect"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/niubaoshu/gotiny"
    15  )
    16  
    17  var (
    18  	udsRegistry  = "@adaptiveservice/"
    19  	chanRegistry = struct {
    20  		sync.RWMutex
    21  		table map[string]*chanTransport
    22  	}{table: make(map[string]*chanTransport)}
    23  )
    24  
    25  func regServiceChan(publisherName, serviceName string, ct *chanTransport) {
    26  	name := publisherName + "_" + serviceName
    27  	chanRegistry.Lock()
    28  	defer chanRegistry.Unlock()
    29  	if _, has := chanRegistry.table[name]; has {
    30  		panic("registering duplicated channel for " + name)
    31  	}
    32  	chanRegistry.table[name] = ct
    33  }
    34  
    35  func delServiceChan(publisherName, serviceName string) {
    36  	name := publisherName + "_" + serviceName
    37  	chanRegistry.Lock()
    38  	delete(chanRegistry.table, name)
    39  	chanRegistry.Unlock()
    40  }
    41  
    42  func serviceNamesInProcess(publisherName, serviceName string) (names []string) {
    43  	name := publisherName + "_" + serviceName
    44  	if strings.Contains(name, "*") {
    45  		chanRegistry.RLock()
    46  		for ctname := range chanRegistry.table {
    47  			chanRegistry.RUnlock()
    48  			if wildcardMatch(name, ctname) {
    49  				names = append(names, ctname)
    50  			}
    51  			chanRegistry.RLock()
    52  		}
    53  		chanRegistry.RUnlock()
    54  	} else {
    55  		chanRegistry.RLock()
    56  		ct := chanRegistry.table[name]
    57  		chanRegistry.RUnlock()
    58  		if ct != nil {
    59  			names = append(names, name)
    60  		}
    61  	}
    62  	return
    63  }
    64  
    65  // support wildcard
    66  func queryServiceProcess(publisherName, serviceName string) (serviceInfos []*ServiceInfo) {
    67  	names := serviceNamesInProcess(publisherName, serviceName)
    68  	for _, name := range names {
    69  		strs := strings.Split(name, "_")
    70  		sInfo := &ServiceInfo{strs[0], strs[1], "self", "internal"}
    71  		serviceInfos = append(serviceInfos, sInfo)
    72  	}
    73  	return
    74  }
    75  
    76  // support wildcard
    77  func (c *Client) lookupServiceChan(publisherName, serviceName string) (ccts []*clientChanTransport) {
    78  	names := serviceNamesInProcess(publisherName, serviceName)
    79  	for _, name := range names {
    80  		chanRegistry.RLock()
    81  		ct := chanRegistry.table[name]
    82  		chanRegistry.RUnlock()
    83  		if ct != nil {
    84  			ccts = append(ccts, &clientChanTransport{c, ct})
    85  		}
    86  	}
    87  	return
    88  }
    89  
    90  func toUDSAddr(publisherName, serviceName string) (addr string) {
    91  	return udsRegistry + publisherName + "_" + serviceName + ".sock"
    92  }
    93  
    94  func serviceNamesInOS(publisherName, serviceName string) (names []string) {
    95  	f, err := os.Open("/proc/net/unix")
    96  	if err != nil {
    97  		return nil
    98  	}
    99  	defer f.Close()
   100  
   101  	var b bytes.Buffer
   102  	_, err = b.ReadFrom(f)
   103  	if err != nil {
   104  		return nil
   105  	}
   106  
   107  	distinctEntires := make(map[string]struct{})
   108  	tName := publisherName + "_" + serviceName
   109  	//skip first line
   110  	b.ReadString('\n')
   111  	for {
   112  		line, err := b.ReadString('\n')
   113  		if err != nil {
   114  			break
   115  		}
   116  		//0000000000000000: 00000002 00000000 00010000 0001 01 10156659 @adaptiveservice/publisherName_serviceName.sock
   117  		fs := strings.Fields(line)
   118  		if len(fs) == 8 {
   119  			addr := fs[7]
   120  			if strings.Contains(addr, udsRegistry) {
   121  				name := strings.TrimSuffix(strings.TrimPrefix(addr, udsRegistry), ".sock")
   122  				// there can be multiple entires with the same name
   123  				if _, has := distinctEntires[name]; has {
   124  					continue
   125  				}
   126  				distinctEntires[name] = struct{}{}
   127  				if wildcardMatch(tName, name) {
   128  					names = append(names, name)
   129  				}
   130  			}
   131  		}
   132  	}
   133  
   134  	return
   135  }
   136  
   137  // support wildcard
   138  func queryServiceOS(publisherName, serviceName string) (serviceInfos []*ServiceInfo) {
   139  	names := serviceNamesInOS(publisherName, serviceName)
   140  	for _, name := range names {
   141  		strs := strings.Split(name, "_")
   142  		sInfo := &ServiceInfo{strs[0], strs[1], "self", udsRegistry + name + ".sock"}
   143  		serviceInfos = append(serviceInfos, sInfo)
   144  	}
   145  	return
   146  }
   147  
   148  // support wildcard
   149  func lookupServiceUDS(publisherName, serviceName string) (addrs []string) {
   150  	names := serviceNamesInOS(publisherName, serviceName)
   151  	for _, name := range names {
   152  		addrs = append(addrs, udsRegistry+name+".sock")
   153  	}
   154  	return
   155  }
   156  
   157  func (svc *service) regServiceLAN(port string) error {
   158  	c := NewClient(WithScope(ScopeProcess|ScopeOS), WithLogger(svc.s.lg)).SetDiscoverTimeout(0)
   159  	conn := <-c.Discover(BuiltinPublisher, SrvLANRegistry)
   160  	if conn == nil {
   161  		return errors.New("LANRegistry not found")
   162  	}
   163  	defer conn.Close()
   164  	return conn.SendRecv(&regServiceInLAN{svc.publisherName, svc.serviceName, port}, nil)
   165  }
   166  
   167  func (svc *service) delServiceLAN() error {
   168  	c := NewClient(WithScope(ScopeProcess|ScopeOS), WithLogger(svc.s.lg)).SetDiscoverTimeout(0)
   169  	conn := <-c.Discover(BuiltinPublisher, SrvLANRegistry)
   170  	if conn == nil {
   171  		return errors.New("LANRegistry not found")
   172  	}
   173  	defer conn.Close()
   174  	return conn.Send(&delServiceInLAN{svc.publisherName, svc.serviceName})
   175  }
   176  
   177  // support wildcard
   178  func queryServiceLAN(publisherName, serviceName string, lg Logger) (serviceInfos []*ServiceInfo) {
   179  	c := NewClient(WithScope(ScopeProcess|ScopeOS), WithLogger(lg)).SetDiscoverTimeout(0)
   180  	conn := <-c.Discover(BuiltinPublisher, SrvLANRegistry)
   181  	if conn == nil {
   182  		return
   183  	}
   184  	defer conn.Close()
   185  	conn.SendRecv(&queryServiceInLAN{publisherName, serviceName}, &serviceInfos)
   186  	return
   187  }
   188  
   189  func (c *Client) lookupServiceLAN(publisherName, serviceName string, providerIDs ...string) (addrs []string) {
   190  	serviceInfos := queryServiceLAN(publisherName, serviceName, c.lg)
   191  	has := func(target string) bool {
   192  		if len(providerIDs) == 0 { // match all
   193  			return true
   194  		}
   195  		for _, str := range providerIDs {
   196  			if str == target {
   197  				return true
   198  			}
   199  		}
   200  		return false
   201  	}
   202  	for _, provider := range serviceInfos {
   203  		if has(provider.ProviderID) {
   204  			addrs = append(addrs, provider.Addr)
   205  		}
   206  	}
   207  	return
   208  }
   209  
   210  // taken from https://github.com/IBM/netaddr/blob/master/net_utils.go
   211  // NewIP returns a new IP with the given size. The size must be 4 for IPv4 and
   212  // 16 for IPv6.
   213  func newIP(size int) net.IP {
   214  	if size == 4 {
   215  		return net.ParseIP("0.0.0.0").To4()
   216  	}
   217  	if size == 16 {
   218  		return net.ParseIP("::")
   219  	}
   220  	panic("Bad value for size")
   221  }
   222  
   223  // BroadcastAddr returns the last address in the given network, or the broadcast address.
   224  func broadcastAddr(n *net.IPNet) net.IP {
   225  	// The golang net package doesn't make it easy to calculate the broadcast address. :(
   226  	broadcast := newIP(len(n.IP))
   227  	for i := 0; i < len(n.IP); i++ {
   228  		broadcast[i] = n.IP[i] | ^n.Mask[i]
   229  	}
   230  	return broadcast
   231  }
   232  
   233  type infoLAN struct {
   234  	ip        net.IP // self ip
   235  	ipnet     *net.IPNet
   236  	bcastAddr *net.UDPAddr
   237  }
   238  
   239  type packetMsg struct {
   240  	msg   interface{}
   241  	raddr net.Addr
   242  }
   243  
   244  type providerInfo struct {
   245  	timeStamp time.Time
   246  	addr      string
   247  	proxied   bool
   248  }
   249  
   250  type providers struct {
   251  	table map[string]*providerInfo // {"providerID1":{time, "192.168.0.11:12345"}, {time, "providerID2":"192.168.0.26:33556"}}
   252  }
   253  
   254  type serviceInfoTime struct {
   255  	timeStamp time.Time // last update time
   256  	si        []*ServiceInfo
   257  }
   258  
   259  type registryLAN struct {
   260  	s          *Server
   261  	packetConn net.PacketConn
   262  	infoLANs   []*infoLAN
   263  	sync.RWMutex
   264  	serviceInfoCache map[string]*serviceInfoTime
   265  	done             chan struct{}
   266  	cmdChan          chan interface{}
   267  }
   268  
   269  func (s *Server) newLANRegistry() (*registryLAN, error) {
   270  	packetConn, err := net.ListenPacket("udp4", ":"+s.broadcastPort)
   271  	if err != nil {
   272  		s.lg.Errorf("listen lan broadcast error: %v", err)
   273  		return nil, err
   274  	}
   275  	s.addCloser(ioCloser(packetConn.Close))
   276  
   277  	var infoLANs []*infoLAN
   278  	addrs, _ := net.InterfaceAddrs()
   279  	for _, addr := range addrs {
   280  		ip, ipnet, _ := net.ParseCIDR(addr.String())
   281  		if ip.To4() != nil && !ip.IsLoopback() {
   282  			bcast := broadcastAddr(ipnet)
   283  			bcastAddr, _ := net.ResolveUDPAddr("udp4", bcast.String()+":"+s.broadcastPort)
   284  			il := &infoLAN{
   285  				ip:        ip,
   286  				ipnet:     ipnet,
   287  				bcastAddr: bcastAddr,
   288  			}
   289  			infoLANs = append(infoLANs, il)
   290  		}
   291  	}
   292  
   293  	r := &registryLAN{
   294  		s:                s,
   295  		packetConn:       packetConn,
   296  		infoLANs:         infoLANs,
   297  		serviceInfoCache: make(map[string]*serviceInfoTime),
   298  		done:             make(chan struct{}),
   299  		cmdChan:          make(chan interface{}),
   300  	}
   301  
   302  	go r.run()
   303  	return r, nil
   304  }
   305  
   306  // msg must be pointer
   307  func (r *registryLAN) broadcast(msg interface{}) error {
   308  	bufMsg := gotiny.Marshal(&msg)
   309  	r.s.lg.Debugf("broadcast LAN msg %#v:  %s", msg, bufMsg)
   310  	for _, lan := range r.infoLANs {
   311  		if _, err := r.packetConn.WriteTo(bufMsg, lan.bcastAddr); err != nil {
   312  			return err
   313  		}
   314  	}
   315  	return nil
   316  }
   317  
   318  // ServiceInfo is service information.
   319  type ServiceInfo struct {
   320  	Publisher  string
   321  	Service    string
   322  	ProviderID string
   323  	Addr       string // "192.168.0.11:12345", "192.168.0.11:12345P" if proxied
   324  }
   325  
   326  type queryInLAN struct {
   327  	name string // "publisher_service"
   328  }
   329  
   330  type foundInLAN struct {
   331  	name       string // "publisher_service"
   332  	providerID string
   333  	port       string
   334  }
   335  
   336  func init() {
   337  	RegisterType(([]*ServiceInfo)(nil))
   338  	RegisterType((*queryInLAN)(nil))
   339  	RegisterType((*foundInLAN)(nil))
   340  }
   341  
   342  type cmdLANRegister struct {
   343  	name string // "publisher_service"
   344  	port string
   345  }
   346  
   347  type cmdLANDelete struct {
   348  	name string // "publisher_service"
   349  }
   350  
   351  type cmdLANQuery struct {
   352  	name            string // "publisher_service"
   353  	chanServiceInfo chan []*ServiceInfo
   354  }
   355  
   356  func (r *registryLAN) registerServiceInLAN(publisher, service, port string) {
   357  	name := publisher + "_" + service
   358  	r.cmdChan <- &cmdLANRegister{name, port}
   359  }
   360  
   361  func (r *registryLAN) deleteServiceInLAN(publisher, service string) {
   362  	name := publisher + "_" + service
   363  	r.cmdChan <- &cmdLANDelete{name}
   364  }
   365  
   366  // support wildcard
   367  func (r *registryLAN) queryServiceInLAN(publisher, service string) []*ServiceInfo {
   368  	name := publisher + "_" + service
   369  	r.Lock()
   370  	if len(r.serviceInfoCache) > 1000 {
   371  		r.serviceInfoCache = make(map[string]*serviceInfoTime)
   372  	}
   373  	sit := r.serviceInfoCache[name]
   374  	r.Unlock()
   375  
   376  	if sit != nil && time.Since(sit.timeStamp) < 15*time.Second {
   377  		return sit.si
   378  	}
   379  
   380  	cmd := &cmdLANQuery{name, make(chan []*ServiceInfo, 1)}
   381  	r.cmdChan <- cmd
   382  	si := <-cmd.chanServiceInfo
   383  
   384  	r.Lock()
   385  	r.serviceInfoCache[name] = &serviceInfoTime{time.Now(), si}
   386  	r.Unlock()
   387  
   388  	return si
   389  }
   390  
   391  func (r *registryLAN) run() {
   392  	pconn := r.packetConn
   393  	lg := r.s.lg
   394  	packetChan := make(chan *packetMsg)
   395  	// "publisher_service": "12345"
   396  	localServiceTable := make(map[string]string)
   397  	// "publisher_service": {time.Time, {"providerID1":"192.168.0.11:12345", "providerID2":"192.168.0.26:33556"}}
   398  	serviceCache := make(map[string]*providers)
   399  
   400  	f, err := os.Open("local_services.record")
   401  	if err == nil {
   402  		for {
   403  			var name, port string
   404  			_, err := fmt.Fscanln(f, &name, &port)
   405  			if err != nil {
   406  				break
   407  			}
   408  			localServiceTable[name] = port
   409  		}
   410  		f.Close()
   411  		os.Remove("local_services.record")
   412  	}
   413  
   414  	readConn := func() {
   415  		buf := make([]byte, 512)
   416  		for {
   417  			if r.done == nil {
   418  				break
   419  			}
   420  			pconn.SetReadDeadline(time.Now().Add(3 * time.Second))
   421  			n, raddr, err := pconn.ReadFrom(buf)
   422  			if err != nil {
   423  				if !os.IsTimeout(err) {
   424  					lg.Warnf("lan registry receive error: %v", err)
   425  				}
   426  				continue
   427  			}
   428  			var msg interface{}
   429  			gotiny.Unmarshal(buf[:n], &msg)
   430  			lg.Debugf("received LAN msg from %v: %#v", raddr, msg)
   431  			packetChan <- &packetMsg{msg, raddr}
   432  		}
   433  	}
   434  	go readConn()
   435  
   436  	replyTo := func(msg interface{}, raddr net.Addr) {
   437  		bufMsg := gotiny.Marshal(&msg)
   438  		lg.Debugf("sending LAN msg to %v: %#v", raddr, msg)
   439  		if _, err := pconn.WriteTo(bufMsg, raddr); err != nil {
   440  			lg.Warnf("lan registry send error: %v", err)
   441  		}
   442  	}
   443  
   444  	getServiceInfos := func(cmd *cmdLANQuery) {
   445  		var serviceInfos []*ServiceInfo
   446  		walkProviders := func(prvds *providers, name string) {
   447  			ss := strings.Split(name, "_")
   448  			for pID, pInfo := range prvds.table {
   449  				svcInfo := &ServiceInfo{Publisher: ss[0], Service: ss[1], ProviderID: pID, Addr: pInfo.addr}
   450  				serviceInfos = append(serviceInfos, svcInfo)
   451  				if time.Since(pInfo.timeStamp) > 15*time.Minute {
   452  					delete(prvds.table, pID)
   453  				}
   454  			}
   455  		}
   456  
   457  		if strings.Contains(cmd.name, "*") {
   458  			for name, prvds := range serviceCache {
   459  				if wildcardMatch(cmd.name, name) {
   460  					walkProviders(prvds, name)
   461  				}
   462  			}
   463  		} else {
   464  			if prvds, has := serviceCache[cmd.name]; has {
   465  				walkProviders(prvds, cmd.name)
   466  			}
   467  		}
   468  		cmd.chanServiceInfo <- serviceInfos
   469  	}
   470  
   471  	delService := func(name string) {
   472  		delete(localServiceTable, name)
   473  		prvds, has := serviceCache[name]
   474  		if has {
   475  			delete(prvds.table, r.s.providerID)
   476  		}
   477  	}
   478  
   479  	tLocalServiceUpdate := time.Now()
   480  	chanDelay := make(chan *cmdLANQuery, 8)
   481  	for {
   482  		select {
   483  		case <-r.done:
   484  			f, err := os.Create("local_services.record")
   485  			if err == nil {
   486  				for name, port := range localServiceTable {
   487  					fmt.Fprintln(f, name, port)
   488  				}
   489  				f.Close()
   490  			}
   491  			return
   492  		case cmd := <-r.cmdChan:
   493  			switch cmd := cmd.(type) {
   494  			case *cmdLANRegister:
   495  				localServiceTable[cmd.name] = cmd.port
   496  			case *cmdLANDelete:
   497  				delService(cmd.name)
   498  			case *cmdLANQuery:
   499  				if err := r.broadcast(&queryInLAN{cmd.name}); err != nil {
   500  					lg.Warnf("lan registry send broadcast error: %v", err)
   501  					break
   502  				}
   503  				time.AfterFunc(100*time.Millisecond, func() { chanDelay <- cmd })
   504  			default:
   505  				lg.Warnf("LAN receiver: unknown cmd: %v", cmd)
   506  			}
   507  		case cmd := <-chanDelay:
   508  			getServiceInfos(cmd)
   509  		case packetMsg := <-packetChan:
   510  			t := time.Now()
   511  			if t.After(tLocalServiceUpdate.Add(15 * time.Minute)) {
   512  				tLocalServiceUpdate = t
   513  				for name, port := range localServiceTable {
   514  					if err := pingService("127.0.0.1:" + port); err != nil {
   515  						delService(name)
   516  					}
   517  				}
   518  			}
   519  			msg := packetMsg.msg
   520  			raddr := packetMsg.raddr
   521  			switch msg := msg.(type) {
   522  			case *queryInLAN:
   523  				if strings.Contains(msg.name, "*") {
   524  					for name, port := range localServiceTable {
   525  						if wildcardMatch(msg.name, name) {
   526  							replyTo(&foundInLAN{name, r.s.providerID, port}, raddr)
   527  						}
   528  					}
   529  				} else {
   530  					port, has := localServiceTable[msg.name]
   531  					if has {
   532  						replyTo(&foundInLAN{msg.name, r.s.providerID, port}, raddr)
   533  					}
   534  				}
   535  			case *foundInLAN:
   536  				rhost, _, _ := net.SplitHostPort(raddr.String())
   537  				prvds, has := serviceCache[msg.name]
   538  				if !has {
   539  					prvds = &providers{table: make(map[string]*providerInfo)}
   540  					serviceCache[msg.name] = prvds
   541  				}
   542  				prvds.table[msg.providerID] = &providerInfo{time.Now(), rhost + ":" + msg.port, false}
   543  			default:
   544  				lg.Warnf("LAN receiver: unknown msg: %v", msg)
   545  			}
   546  		}
   547  	}
   548  }
   549  
   550  func (r *registryLAN) close() {
   551  	close(r.done)
   552  	r.done = nil
   553  }
   554  
   555  func (svc *service) regServiceWAN(port string) error {
   556  	c := NewClient(WithScope(ScopeWAN), WithLogger(svc.s.lg))
   557  	conn, err := c.newTCPConnection(svc.s.registryAddr)
   558  	if err != nil {
   559  		return err
   560  	}
   561  	defer conn.Close()
   562  	proxied := false
   563  	if svc.providerID != svc.s.providerID {
   564  		proxied = true
   565  	}
   566  	return conn.SendRecv(&regServiceInWAN{svc.publisherName, svc.serviceName, svc.providerID, port, proxied}, nil)
   567  }
   568  
   569  func (svc *service) delServiceWAN() error {
   570  	c := NewClient(WithScope(ScopeWAN), WithLogger(svc.s.lg))
   571  	conn, err := c.newTCPConnection(svc.s.registryAddr)
   572  	if err != nil {
   573  		return err
   574  	}
   575  	defer conn.Close()
   576  	return conn.Send(&delServiceInWAN{svc.publisherName, svc.serviceName, svc.providerID})
   577  }
   578  
   579  // support wildcard
   580  func queryServiceWAN(registryAddr, publisherName, serviceName string, lg Logger) (serviceInfos []*ServiceInfo) {
   581  	c := NewClient(WithScope(ScopeWAN), WithLogger(lg))
   582  	conn, err := c.newTCPConnection(registryAddr)
   583  	if err != nil {
   584  		lg.Errorf("connect to registry failed: %v", err)
   585  		return
   586  	}
   587  	defer conn.Close()
   588  
   589  	conn.SendRecv(&queryServiceInWAN{publisherName, serviceName}, &serviceInfos)
   590  	return
   591  }
   592  
   593  func (c *Client) lookupServiceWAN(publisherName, serviceName string, providerIDs ...string) (addrs []string) {
   594  	has := func(target string) bool {
   595  		if len(providerIDs) == 0 { // match all
   596  			return true
   597  		}
   598  		for _, str := range providerIDs {
   599  			if str == target {
   600  				return true
   601  			}
   602  		}
   603  		return false
   604  	}
   605  
   606  	serviceInfos := queryServiceWAN(c.registryAddr, publisherName, serviceName, c.lg)
   607  	for _, provider := range serviceInfos {
   608  		if has(provider.ProviderID) {
   609  			addrs = append(addrs, provider.Addr)
   610  		}
   611  	}
   612  	return
   613  }
   614  
   615  type providerMap struct {
   616  	sync.RWMutex
   617  	providers map[string]*providerInfo
   618  }
   619  
   620  type rootRegistry struct {
   621  	sync.RWMutex
   622  	// "publisher_service": {"providerID1":{timeStamp, "192.168.0.11:12345"}, "providerID2":{timeStamp, "192.168.0.26:33556"}}
   623  	serviceMap map[string]*providerMap
   624  }
   625  
   626  func pingService(addr string) error {
   627  	conn, err := net.DialTimeout("tcp", addr, time.Second)
   628  	if err != nil {
   629  		return ErrServiceNotReachable
   630  	}
   631  	conn.Close()
   632  	return nil
   633  }
   634  
   635  // reply OK or error
   636  type testReverseProxy struct {
   637  	port string
   638  }
   639  
   640  func (msg *testReverseProxy) Handle(stream ContextStream) (reply interface{}) {
   641  	ss := stream.(*streamServerStream)
   642  	rhost, _, _ := net.SplitHostPort(ss.netconn.RemoteAddr().String())
   643  
   644  	raddr := rhost + ":" + msg.port
   645  	if err := pingService(raddr); err != nil {
   646  		return err
   647  	}
   648  	return OK
   649  }
   650  
   651  // reply OK or error
   652  type regServiceInWAN struct {
   653  	publisher  string
   654  	service    string
   655  	providerID string
   656  	port       string
   657  	proxied    bool
   658  }
   659  
   660  func (msg *regServiceInWAN) Handle(stream ContextStream) (reply interface{}) {
   661  	rr := stream.GetContext().(*rootRegistry)
   662  	ss := stream.(*streamServerStream)
   663  	rhost, _, _ := net.SplitHostPort(ss.netconn.RemoteAddr().String())
   664  
   665  	raddr := rhost + ":" + msg.port
   666  	if err := pingService(raddr); err != nil {
   667  		return err
   668  	}
   669  
   670  	name := msg.publisher + "_" + msg.service
   671  	rr.Lock()
   672  	pmap, has := rr.serviceMap[name]
   673  	if !has {
   674  		pmap = &providerMap{
   675  			providers: make(map[string]*providerInfo),
   676  		}
   677  		rr.serviceMap[name] = pmap
   678  	}
   679  	rr.Unlock()
   680  
   681  	pinfo := &providerInfo{time.Now(), raddr, msg.proxied}
   682  	pmap.Lock()
   683  	pmap.providers[msg.providerID] = pinfo
   684  	pmap.Unlock()
   685  
   686  	return OK
   687  }
   688  
   689  // no reply
   690  type delServiceInWAN struct {
   691  	publisher  string
   692  	service    string
   693  	providerID string
   694  }
   695  
   696  func (msg *delServiceInWAN) Handle(stream ContextStream) (reply interface{}) {
   697  	rr := stream.GetContext().(*rootRegistry)
   698  	name := msg.publisher + "_" + msg.service
   699  	rr.RLock()
   700  	pmap, has := rr.serviceMap[name]
   701  	rr.RUnlock()
   702  	if !has {
   703  		return nil
   704  	}
   705  
   706  	pmap.Lock()
   707  	delete(pmap.providers, msg.providerID)
   708  	pmap.Unlock()
   709  
   710  	return nil
   711  }
   712  
   713  // reply []*ServiceInfo
   714  // support wildcard(*) matching
   715  type queryServiceInWAN struct {
   716  	publisher string
   717  	service   string
   718  }
   719  
   720  func (msg *queryServiceInWAN) Handle(stream ContextStream) (reply interface{}) {
   721  	rr := stream.GetContext().(*rootRegistry)
   722  	name := msg.publisher + "_" + msg.service
   723  	var serviceInfos []*ServiceInfo
   724  
   725  	walkProviderMap := func(service string, pmap *providerMap) {
   726  		pmap.RLock()
   727  		for pID, pInfo := range pmap.providers {
   728  			func() {
   729  				pmap.RUnlock()
   730  				defer pmap.RLock()
   731  				t := time.Now()
   732  				if t.After(pInfo.timeStamp.Add(15 * time.Minute)) {
   733  					if err := pingService(pInfo.addr); err != nil {
   734  						pmap.Lock()
   735  						delete(pmap.providers, pID)
   736  						pmap.Unlock()
   737  						return
   738  					}
   739  					pInfo.timeStamp = t
   740  				}
   741  				addr := pInfo.addr
   742  				if pInfo.proxied {
   743  					addr += "P"
   744  				}
   745  				svcInfo := &ServiceInfo{ProviderID: pID, Addr: addr}
   746  				if len(service) != 0 {
   747  					ss := strings.Split(service, "_")
   748  					svcInfo.Publisher = ss[0]
   749  					svcInfo.Service = ss[1]
   750  				}
   751  				serviceInfos = append(serviceInfos, svcInfo)
   752  			}()
   753  		}
   754  		pmap.RUnlock()
   755  	}
   756  
   757  	if strings.Contains(name, "*") {
   758  		rr.RLock()
   759  		for service, pmap := range rr.serviceMap {
   760  			rr.RUnlock()
   761  			if wildcardMatch(name, service) {
   762  				walkProviderMap(service, pmap)
   763  			}
   764  			rr.RLock()
   765  		}
   766  		rr.RUnlock()
   767  	} else {
   768  		rr.RLock()
   769  		pmap, has := rr.serviceMap[name]
   770  		rr.RUnlock()
   771  		if has {
   772  			walkProviderMap("", pmap)
   773  		}
   774  	}
   775  
   776  	return serviceInfos
   777  }
   778  
   779  func init() {
   780  	RegisterType((*regServiceInWAN)(nil))
   781  	RegisterType((*delServiceInWAN)(nil))
   782  	RegisterType((*queryServiceInWAN)(nil))
   783  	RegisterType((*testReverseProxy)(nil))
   784  }
   785  
   786  func (s *Server) registryCheckSaver() {
   787  	for {
   788  		time.Sleep(time.Minute)
   789  		svcs := queryServiceWAN(s.registryAddr, "*", "*", s.lg)
   790  		f, err := os.Create("services.record.updating")
   791  		if err != nil {
   792  			s.lg.Errorf("root registry: record file not created: %v", err)
   793  			return
   794  		}
   795  		for _, si := range svcs {
   796  			fmt.Fprintf(f, "%s %s %s %s\n", si.Publisher, si.Service, si.ProviderID, si.Addr)
   797  		}
   798  		f.Close()
   799  		os.Rename("services.record.updating", "services.record")
   800  	}
   801  }
   802  
   803  func (s *Server) startRootRegistry(port string) error {
   804  	svc := &service{
   805  		publisherName: BuiltinPublisher,
   806  		serviceName:   "rootRegistry",
   807  		providerID:    s.providerID,
   808  		knownMsgTypes: make(map[reflect.Type]struct{}),
   809  		s:             s,
   810  	}
   811  	svc.knownMsgTypes[reflect.TypeOf((*regServiceInWAN)(nil))] = struct{}{}
   812  	svc.knownMsgTypes[reflect.TypeOf((*delServiceInWAN)(nil))] = struct{}{}
   813  	svc.knownMsgTypes[reflect.TypeOf((*queryServiceInWAN)(nil))] = struct{}{}
   814  	svc.knownMsgTypes[reflect.TypeOf((*testReverseProxy)(nil))] = struct{}{}
   815  
   816  	rr := &rootRegistry{
   817  		serviceMap: make(map[string]*providerMap),
   818  	}
   819  	f, err := os.Open("services.record")
   820  	if err == nil {
   821  		for {
   822  			var publisher, service, providerID, addr string
   823  			_, err := fmt.Fscanln(f, &publisher, &service, &providerID, &addr)
   824  			if err != nil {
   825  				break
   826  			}
   827  			name := publisher + "_" + service
   828  			pmap := rr.serviceMap[name]
   829  			if pmap == nil {
   830  				pmap = &providerMap{providers: make(map[string]*providerInfo)}
   831  				rr.serviceMap[name] = pmap
   832  			}
   833  			pinfo := &providerInfo{time.Now(), addr, false}
   834  			if addr[len(addr)-1] == 'P' {
   835  				pinfo.addr = addr[:len(addr)-1]
   836  				pinfo.proxied = true
   837  			}
   838  			pmap.providers[providerID] = pinfo
   839  		}
   840  		f.Close()
   841  	}
   842  	svc.fnOnNewStream = func(ctx Context) {
   843  		ctx.SetContext(rr)
   844  	}
   845  	tran, err := svc.newTCPTransport(port)
   846  	if err != nil {
   847  		return err
   848  	}
   849  	s.addCloser(tran)
   850  	return nil
   851  }