package controller import ( "context" "encoding/json" "errors" "strings" "github.com/gravitl/netmaker/functions" nodepb "github.com/gravitl/netmaker/grpc" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" ) // NodeServiceServer - represents the service server for gRPC type NodeServiceServer struct { nodepb.UnimplementedNodeServiceServer } // NodeServiceServer.ReadNode - reads node and responds with gRPC func (s *NodeServiceServer) ReadNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { // convert string id (from proto) to mongoDB ObjectId macAndNetwork := strings.Split(req.Data, "###") if len(macAndNetwork) != 2 { return nil, errors.New("could not read node, invalid node id given") } node, err := GetNode(macAndNetwork[0], macAndNetwork[1]) if err != nil { return nil, err } node.SetLastCheckIn() // Cast to ReadNodeRes type nodeData, err := json.Marshal(&node) if err != nil { return nil, err } node.Update(&node) response := &nodepb.Object{ Data: string(nodeData), Type: nodepb.NODE_TYPE, } return response, nil } // NodeServiceServer.CreateNode - creates a node and responds over gRPC func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { // Get the protobuf node type from the protobuf request type // Essentially doing req.Node to access the struct with a nil check var node models.Node data := req.GetData() if err := json.Unmarshal([]byte(data), &node); err != nil { return nil, err } //Check to see if key is valid //TODO: Triple inefficient!!! This is the third call to the DB we make for networks validKey := functions.IsKeyValid(node.Network, node.AccessKey) network, err := functions.GetParentNetwork(node.Network) if err != nil { return nil, err } if !validKey { //Check to see if network will allow manual sign up //may want to switch this up with the valid key check and avoid a DB call that way. if network.AllowManualSignUp == "yes" { node.IsPending = "yes" } else { return nil, errors.New("invalid key, and network does not allow no-key signups") } } node, err = logic.CreateNode(node, node.Network) if err != nil { return nil, err } nodeData, err := json.Marshal(&node) // return the node in a CreateNodeRes type response := &nodepb.Object{ Data: string(nodeData), Type: nodepb.NODE_TYPE, } err = logic.SetNetworkNodesLastModified(node.Network) if err != nil { return nil, err } return response, nil } // NodeServiceServer.UpdateNode updates a node and responds over gRPC func (s *NodeServiceServer) UpdateNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { // Get the node data from the request var newnode models.Node if err := json.Unmarshal([]byte(req.GetData()), &newnode); err != nil { return nil, err } macaddress := newnode.MacAddress networkName := newnode.Network node, err := functions.GetNodeByMacAddress(networkName, macaddress) if err != nil { return nil, err } err = node.Update(&newnode) if err != nil { return nil, err } nodeData, err := json.Marshal(&newnode) if err != nil { return nil, err } return &nodepb.Object{ Data: string(nodeData), Type: nodepb.NODE_TYPE, }, nil } // NodeServiceServer.DeleteNode - deletes a node and responds over gRPC func (s *NodeServiceServer) DeleteNode(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { nodeID := req.GetData() err := DeleteNode(nodeID, true) if err != nil { return nil, err } return &nodepb.Object{ Data: "success", Type: nodepb.STRING_TYPE, }, nil } // NodeServiceServer.GetPeers - fetches peers over gRPC func (s *NodeServiceServer) GetPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { macAndNetwork := strings.Split(req.Data, "###") if len(macAndNetwork) == 2 { // TODO: Make constant and new variable for isServer node, err := GetNode(macAndNetwork[0], macAndNetwork[1]) if err != nil { return nil, err } if node.IsServer == "yes" && logic.IsLeader(&node) { logic.SetNetworkServerPeers(&node) } excludeIsRelayed := node.IsRelay != "yes" var relayedNode string if node.IsRelayed == "yes" { relayedNode = node.Address } peers, err := logic.GetPeersList(macAndNetwork[1], excludeIsRelayed, relayedNode) if err != nil { return nil, err } peersData, err := json.Marshal(&peers) functions.PrintUserLog(node.Address, "checked in successfully", 3) return &nodepb.Object{ Data: string(peersData), Type: nodepb.NODE_TYPE, }, err } return &nodepb.Object{ Data: "", Type: nodepb.NODE_TYPE, }, errors.New("could not fetch peers, invalid node id") } // NodeServiceServer.GetExtPeers - returns ext peers for a gateway node func (s *NodeServiceServer) GetExtPeers(ctx context.Context, req *nodepb.Object) (*nodepb.Object, error) { // Initiate a NodeItem type to write decoded data to //data := &models.PeersResponse{} // collection.Find returns a cursor for our (empty) query macAndNetwork := strings.Split(req.Data, "###") if len(macAndNetwork) != 2 { return nil, errors.New("did not receive valid node id when fetching ext peers") } peers, err := logic.GetExtPeersList(macAndNetwork[0], macAndNetwork[1]) if err != nil { return nil, err } var extPeers []models.Node for i := 0; i < len(peers); i++ { extPeers = append(extPeers, models.Node{ Address: peers[i].Address, Address6: peers[i].Address6, Endpoint: peers[i].Endpoint, PublicKey: peers[i].PublicKey, PersistentKeepalive: peers[i].KeepAlive, ListenPort: peers[i].ListenPort, LocalAddress: peers[i].LocalAddress, }) } extData, err := json.Marshal(&extPeers) if err != nil { return nil, err } return &nodepb.Object{ Data: string(extData), Type: nodepb.EXT_PEER, }, nil }