Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def main():
if not args.no_gui:
go_server_cmd ="cd ./frontend/go_server && go run main.go"
open_terminal(go_server_cmd)
time.sleep(0.5)
time.sleep(2)
gui_cmd = "source venv/bin/activate && python3 ./frontend/gui/main.py"
open_terminal(gui_cmd)

Expand Down
81 changes: 81 additions & 0 deletions frontend/go_server/back_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package main

import (
"fmt"
"log"
"net"
"os"
"time"
)

const (
defaultServerAddress = "localhost:12345" // Default address if no flag is provided
)

// Establish connection to the C++ backend server
func connectToBackend(serverAddress string) (net.Conn, error) {
conn, err := net.Dial("tcp", serverAddress)
if err != nil {
return nil, fmt.Errorf("error connecting to server: %v", err)
}
return conn, nil
}

// Send request to fetch network state
func sendRequest(conn net.Conn) (string, error) {
_, err := conn.Write([]byte("GET_NETWORK_STATE\n"))
if err != nil {
return "", fmt.Errorf("error sending request: %v", err)
}

// Read the response from the server
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return "", fmt.Errorf("error reading response: %v", err)
}

return string(buf[:n]), nil
}

// Fetch network state from the C++ backend
func fetchNetworkState(serverAddress string) (string, error) {
conn, err := connectToBackend(serverAddress)
if err != nil {
return "", err
}
defer conn.Close()

return sendRequest(conn)
}


func main() {
// Establish connection to the C++ backend
conn, err := net.Dial("tcp", serverAddress)
if err != nil {
log.Fatalf("Error connecting to server: %v", err)
}
defer conn.Close()

// Send true state to alert the server that this is a GUI-type connection
_, err = conn.Write([]byte("1\n")) // Sending "1" to indicate GUI type
if err != nil {
log.Fatalf("Error sending connection type: %v", err)
}

// Send request to fetch network state
_, err = conn.Write([]byte("GET_NETWORK_STATE\n"))
if err != nil {
log.Fatalf("Error sending request: %v", err)
}

// Read the response from the server
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Fatalf("Error reading response: %v", err)
}

fmt.Printf("Received network state: %s\n", string(buf[:n]))
}
148 changes: 93 additions & 55 deletions frontend/go_server/main.go
Original file line number Diff line number Diff line change
@@ -1,75 +1,113 @@
package main

import (
"context"
"encoding/json"
"fmt"
"log"
"net"

pb "netmap/proto" // Ensure this is the correct relative path to your generated proto file
"google.golang.org/grpc"
"context"
"fmt"
"log"
"net"
"time"

"google.golang.org/grpc"
"netmap/proto" // Adjust this import path as needed
)

const (
grpcServerAddress = "localhost:50051" // Python gRPC server address
backendServerAddr = "localhost:12345" // C++ backend server address
)

// NetMapServer struct implements the gRPC server interface
type NetMapServer struct {
pb.UnimplementedNetMapServer
// Define the server struct implementing the proto interface for gRPC communication with Python
type server struct {
proto.UnimplementedNetMapServer
}

// GetState: Fetch current netmap state and send it to the Python client
func (s *NetMapServer) GetState(ctx context.Context, req *pb.NetworkDataRequest) (*pb.NetworkDataResponse, error) {
// Fetch network state from the C++ backend
data := queryCPlusPlusBackend()
// SendNetworkData is the method that sends data to the Python client and receives a response
func (s *server) SendNetworkData(ctx context.Context, req *proto.NetworkDataRequest) (*proto.NetworkDataResponse, error) {
fmt.Println("Received data from Python frontend:", req.NetworkData)
// Process the data if needed, then send a response back to the Python client
return &proto.NetworkDataResponse{Message: "Data received and processed!"}, nil
}

// Convert to JSON for Python GUI
jsonData, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("failed to marshal data: %v", err)
}
func startGRPCServer() {
// Set up the gRPC server to listen on port 50051 for the Python client
listener, err := net.Listen("tcp", grpcServerAddress)
if err != nil {
log.Fatalf("Failed to listen on port 50051: %v", err)
}
defer listener.Close()

// Return the response with the JSON data
return &pb.NetworkDataResponse{Message: string(jsonData)}, nil
// Create a new gRPC server
grpcServer := grpc.NewServer()

// Register the gRPC server with the NetMap implementation
proto.RegisterNetMapServer(grpcServer, &server{})

// Start serving requests for the Python frontend
fmt.Println("Starting gRPC server for Python frontend on port 50051...")
if err := grpcServer.Serve(listener); err != nil {
log.Fatalf("Failed to serve gRPC server: %v", err)
}
}

func (s *NetMapServer) SendNetworkData(ctx context.Context, req *pb.NetworkDataRequest) (*pb.NetworkDataResponse, error) {
// Handle the request and return a response
fmt.Println("Received network data:", req.GetNetworkData())
return &pb.NetworkDataResponse{
Message: "Network data received successfully",
}, nil
func startBackendClient() {
// Set up the connection to the C++ backend server
conn, err := net.Dial("tcp", backendServerAddr)
if err != nil {
log.Fatalf("Failed to connect to C++ backend server: %v", err)
}
defer conn.Close()

// Send request to the C++ backend for network state
_, err = conn.Write([]byte("1\n"))
if err != nil {
log.Fatalf("Error sending request to C++ backend: %v", err)
}

// Read the response from the C++ backend
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
log.Fatalf("Error reading response from C++ backend: %v", err)
}

networkState := string(buf[:n])
fmt.Printf("Received network state from C++ backend: %s\n", networkState)

// Sending the network state to the Python client (if necessary)
sendToPythonFrontend(networkState)
}

// Function to query C++ backend (over a socket or another method)
func queryCPlusPlusBackend() map[string]interface{} {
// Placeholder: Implement the actual socket or inter-process communication with C++ backend
// Example mock data returned from the C++ backend for demonstration
return map[string]interface{}{
"nodes": []map[string]string{
{"ip": "192.168.1.1", "mac": "AA:BB:CC:DD:EE:FF"},
},
"links": []map[string]string{
{"source": "192.168.1.1", "target": "192.168.1.2"},
},
}
func sendToPythonFrontend(networkState string) {
// Set up connection to Python gRPC server
conn, err := grpc.Dial(grpcServerAddress, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("Failed to connect to Python gRPC server: %v", err)
}
defer conn.Close()

client := proto.NewNetMapClient(conn)

// Send network data to the Python frontend
req := &proto.NetworkDataRequest{NetworkData: networkState}
resp, err := client.SendNetworkData(context.Background(), req)
if err != nil {
log.Fatalf("Failed to send request to Python frontend: %v", err)
}

// Print the response from the Python frontend
fmt.Println("Response from Python frontend:", resp.GetMessage())
}

func main() {
// Listen for incoming connections on TCP port 50051
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Failed to listen on port 50051: %v", err)
}

// Create a new gRPC server
grpcServer := grpc.NewServer()
// Start the gRPC server in a separate goroutine for the Python frontend
go startGRPCServer()

// Register the NetMapServer with the gRPC server
pb.RegisterNetMapServer(grpcServer, &NetMapServer{})
// Simulate a delay to ensure the gRPC server is ready
time.Sleep(1 * time.Second)

fmt.Println("gRPC Server is running on port 50051")
// Start the backend client to fetch network data and send it to Python frontend
startBackendClient()

// Start serving requests
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve gRPC server: %v", err)
}
// To keep the main function running while servers are active
select {}
}
36 changes: 0 additions & 36 deletions frontend/go_server/socket_client.go

This file was deleted.

49 changes: 38 additions & 11 deletions frontend/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
QGraphicsScene, QGraphicsView, QGraphicsEllipseItem, QGraphicsTextItem, QVBoxLayout, QWidget, QLineEdit)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QBrush, QColor
import seed # Assuming SEED library is installed

class NetworkNode(QGraphicsEllipseItem):
def __init__(self, x, y, ip, details):
Expand Down Expand Up @@ -58,6 +59,9 @@ def __init__(self, port):
self.backend_thread.new_data.connect(self.update_network)
self.backend_thread.start()

# SEED Network Visualization Setup
self.network = seed.Network()

def scan_network(self):
self.backend_thread.send_command("scan")

Expand All @@ -71,16 +75,39 @@ def update_network(self, data):
self.scene.clear()
nodes = data.split(";")
x, y = 50, 50
for node_info in nodes:
parts = node_info.split(",")
if len(parts) >= 2:
ip, details = parts[0], parts[1]
node = NetworkNode(x, y, ip, details)
self.scene.addItem(node)
x += 100
if x > 800:
x = 50
y += 100

# Example static network data for visualization
# Normally, this would come from your backend data
example_nodes = [
{"name": "Node 1", "type": "Router", "ip": "192.168.0.1", "details": "Main Router"},
{"name": "Node 2", "type": "Device", "ip": "192.168.0.2", "details": "Device A"},
{"name": "Node 3", "type": "Device", "ip": "192.168.0.3", "details": "Device B"}
]
example_edges = [
{"source": "Node 1", "destination": "Node 2"},
{"source": "Node 1", "destination": "Node 3"}
]

# Add nodes to SEED network (for visualization)
for node_info in example_nodes:
self.network.add_node(node_info['name'], **node_info)

# Add edges to SEED network
for edge in example_edges:
self.network.add_edge(edge['source'], edge['destination'])

# Visualization with SEED
self.network.display()

# Also adding graphical elements to PyQt6's QGraphicsView
for node_info in example_nodes:
ip, details = node_info['ip'], node_info['details']
node = NetworkNode(x, y, ip, details)
self.scene.addItem(node)
x += 100
if x > 800:
x = 50
y += 100

class BackendThread(QThread):
new_data = pyqtSignal(str)
Expand Down Expand Up @@ -112,4 +139,4 @@ def run():
sys.exit(app.exec())

if __name__ == "__main__":
run()
run()
Loading