github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/network/handler/handler.go (about) 1 package handler 2 3 import ( 4 "context" 5 6 pb "github.com/tickoalcantara12/micro/v3/proto/network" 7 pbRtr "github.com/tickoalcantara12/micro/v3/proto/router" 8 "github.com/tickoalcantara12/micro/v3/service/errors" 9 log "github.com/tickoalcantara12/micro/v3/service/logger" 10 "github.com/tickoalcantara12/micro/v3/service/network" 11 "github.com/tickoalcantara12/micro/v3/service/network/mucp" 12 "github.com/tickoalcantara12/micro/v3/service/network/util" 13 "github.com/tickoalcantara12/micro/v3/service/router" 14 authns "github.com/tickoalcantara12/micro/v3/util/auth/namespace" 15 "github.com/tickoalcantara12/micro/v3/util/namespace" 16 ) 17 18 // Network implements network handler 19 type Network struct { 20 Network network.Network 21 } 22 23 func flatten(n network.Node, visited map[string]bool) []network.Node { 24 // if node is nil runaway 25 if n == nil { 26 return nil 27 } 28 29 // set visisted 30 if visited == nil { 31 visited = make(map[string]bool) 32 } 33 34 // create new list of nodes 35 //nolint:prealloc 36 var nodes []network.Node 37 38 // check if already visited 39 if !visited[n.Id()] { 40 // append the current node 41 nodes = append(nodes, n) 42 } 43 44 // set to visited 45 visited[n.Id()] = true 46 47 // visit the list of peers 48 for _, node := range n.Peers() { 49 nodes = append(nodes, flatten(node, visited)...) 50 } 51 52 return nodes 53 } 54 55 func (n *Network) Connect(ctx context.Context, req *pb.ConnectRequest, resp *pb.ConnectResponse) error { 56 if len(req.Nodes) == 0 { 57 return nil 58 } 59 60 // get list of existing nodes 61 nodes := n.Network.Options().Nodes 62 63 // generate a node map 64 nodeMap := make(map[string]bool) 65 66 for _, node := range nodes { 67 nodeMap[node] = true 68 } 69 70 for _, node := range req.Nodes { 71 // TODO: we may have been provided a network only 72 // so process anad resolve node.Network 73 if len(node.Address) == 0 { 74 continue 75 } 76 77 // already exists 78 if _, ok := nodeMap[node.Address]; ok { 79 continue 80 } 81 82 nodeMap[node.Address] = true 83 nodes = append(nodes, node.Address) 84 } 85 86 log.Infof("Network.Connect setting peers: %v", nodes) 87 88 // reinitialise the peers 89 n.Network.Init( 90 network.Nodes(nodes...), 91 ) 92 93 // call the connect method 94 n.Network.Connect() 95 96 return nil 97 } 98 99 // Nodes returns the list of nodes 100 func (n *Network) Nodes(ctx context.Context, req *pb.NodesRequest, resp *pb.NodesResponse) error { 101 // root node 102 nodes := map[string]network.Node{} 103 104 // get peers encoded into protobuf 105 peers := flatten(n.Network, nil) 106 107 // walk all the peers 108 for _, peer := range peers { 109 if peer == nil { 110 continue 111 } 112 if _, ok := nodes[peer.Id()]; ok { 113 continue 114 } 115 116 // add to visited list 117 nodes[n.Network.Id()] = peer 118 119 resp.Nodes = append(resp.Nodes, &pb.Node{ 120 Id: peer.Id(), 121 Address: peer.Address(), 122 }) 123 } 124 125 return nil 126 } 127 128 // Graph returns the network graph from this root node 129 func (n *Network) Graph(ctx context.Context, req *pb.GraphRequest, resp *pb.GraphResponse) error { 130 depth := uint(req.Depth) 131 if depth <= 0 || depth > mucp.MaxDepth { 132 depth = mucp.MaxDepth 133 } 134 135 // get peers encoded into protobuf 136 peers := util.PeersToProto(n.Network, depth) 137 138 // set the root node 139 resp.Root = peers 140 141 return nil 142 } 143 144 // Routes returns a list of routing table routes 145 func (n *Network) Routes(ctx context.Context, req *pb.RoutesRequest, resp *pb.RoutesResponse) error { 146 // default the network to the current users namespace 147 if req.Query == nil { 148 req.Query = &pb.Query{} 149 } 150 if len(req.Query.Network) == 0 { 151 req.Query.Network = namespace.FromContext(ctx) 152 } 153 154 // authorize the request 155 if err := authns.AuthorizeAdmin(ctx, req.Query.Network, "network.Network.Routes"); err != nil { 156 return err 157 } 158 159 // build query 160 var qOpts []router.LookupOption 161 if len(req.Query.Address) > 0 { 162 qOpts = append(qOpts, router.LookupAddress(req.Query.Address)) 163 } 164 if len(req.Query.Gateway) > 0 { 165 qOpts = append(qOpts, router.LookupGateway(req.Query.Gateway)) 166 } 167 if len(req.Query.Router) > 0 { 168 qOpts = append(qOpts, router.LookupRouter(req.Query.Router)) 169 } 170 171 // for users in the default namespace, allow access to all namespaces 172 if req.Query.Network != namespace.DefaultNamespace { 173 qOpts = append(qOpts, router.LookupNetwork(req.Query.Network)) 174 } 175 176 var routes []router.Route 177 var err error 178 179 // if a service is specified to a router Lookup 180 if len(req.Query.Service) > 0 { 181 routes, err = n.Network.Options().Router.Lookup(req.Query.Service, qOpts...) 182 } else { 183 // otherwise list and filter 184 routes, err = n.Network.Options().Router.Table().Read() 185 if err == nil { 186 // filter the routes 187 routes = router.Filter(routes, router.NewLookup(qOpts...)) 188 } 189 } 190 191 if err != nil { 192 return errors.InternalServerError("network.Network.Routes", "failed to list routes: %s", err) 193 } 194 195 for _, route := range routes { 196 resp.Routes = append(resp.Routes, &pbRtr.Route{ 197 Service: route.Service, 198 Address: route.Address, 199 Gateway: route.Gateway, 200 Network: route.Network, 201 Router: route.Router, 202 Link: route.Link, 203 Metric: int64(route.Metric), 204 }) 205 } 206 207 return nil 208 } 209 210 // Services returns a list of services based on the routing table 211 func (n *Network) Services(ctx context.Context, req *pb.ServicesRequest, resp *pb.ServicesResponse) error { 212 // authorize the request. only accounts issued by micro (root accounts) can access this endpoint 213 if err := authns.AuthorizeAdmin(ctx, authns.DefaultNamespace, "network.Network.Services"); err != nil { 214 return err 215 } 216 217 routes, err := n.Network.Options().Router.Table().Read() 218 if err != nil { 219 return errors.InternalServerError("network.Network.Services", "failed to list services: %s", err) 220 } 221 222 services := make(map[string]bool) 223 224 for _, route := range routes { 225 if route.Service == "*" { 226 continue 227 } 228 229 if _, ok := services[route.Service]; ok { 230 continue 231 } 232 services[route.Service] = true 233 resp.Services = append(resp.Services, route.Service) 234 } 235 236 return nil 237 }