Skip to content
Closed
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 synapse-api
34 changes: 16 additions & 18 deletions synapse/cli/device_info_display.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import time
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.tree import Tree
from google.protobuf.json_format import MessageToDict
from synapse.client.device import Device


def visualize_configuration(info_dict):
def visualize_configuration(info_dict, status):
nodes_status = status.get("signal_chain", {}).get("nodes", {})
config = info_dict.get("configuration", {})
if config:
tree = Tree("Configuration")
for node in config.get("nodes", []):
for index, node in enumerate(config.get("nodes", [])):
node_type = node.get("type", "").replace("k", "")
node_name = node.get("name", "Unknown")
node_tree = tree.add(f"{node_name}")
node_tree = tree.add(f"{node_type}")
node_tree.add(f"ID: {node.get('id', 'Unknown')}")
node_tree.add(f"Type: {node_type}")

if node_type == "Application":
app = node.get("application", {})
name = app.get("name", "Unknown")
running = app.get("running", False)
status = "[green]Running[/green]" if running else "[red]Stopped[/red]"

application_status = nodes_status[index].get("application", None)
running = application_status.get("running", False)
if not running:
error_logs = application_status.get(
"error_logs", "Could not get error logs"
)

node_tree.add(f"Name: {name}")
node_tree.add(f"Status: {status}")
node_tree.add(f"Running: {running}")
if not running:
node_tree.add(f"Error Logs:\n{error_logs}")
elif node_type == "BroadbandSource":
source = node.get("broadband_source", {})
name = source.get("name", "Unknown")
running = source.get("running", False)
status = "[green]Running[/green]" if running else "[red]Stopped[/red]"
node_tree.add(f"Name: {name}")
node_tree.add(f"Status: {status}")
if "signal" in source and "electrode" in source["signal"]:
channels = source["signal"]["electrode"].get("channels", [])
electrode_ids = [
Expand Down Expand Up @@ -113,4 +111,4 @@ def summary(self, device: Device):
)

self.console.print(visualize_peripherals(info_dict))
self.console.print(visualize_configuration(info_dict))
self.console.print(visualize_configuration(info_dict, status))
32 changes: 15 additions & 17 deletions synapse/cli/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@
from typing import Optional

import synapse as syn
from synapse.api.synapse_pb2 import DeviceConfiguration
from synapse.api.query_pb2 import QueryRequest, QueryResponse, StreamQueryRequest
from synapse.api.status_pb2 import StatusCode

from google.protobuf import text_format
from google.protobuf.json_format import Parse

from rich.console import Console
from rich.pretty import pprint

from synapse.cli.query import StreamingQueryClient
from synapse.utils.log import log_entry_to_str
from synapse.cli.device_info_display import DeviceInfoDisplay
from synapse.utils.proto import load_config


def add_commands(subparsers):
Expand Down Expand Up @@ -196,10 +195,7 @@ def start(args):

# Load the configuration proto and build Config object
try:
with open(cfg_path, "r") as f:
json_text = f.read()
cfg_proto = Parse(json_text, DeviceConfiguration())
config_obj = syn.Config.from_proto(cfg_proto)
config_obj = load_config(cfg_path, console)
except Exception as e:
console.print(
f"[bold red]Failed to parse configuration file[/bold red]: {e}"
Expand Down Expand Up @@ -267,17 +263,19 @@ def configure(args):
print("Configuration file must be a JSON file")
return False

with open(args.config_file) as config_json:
console = Console()
config_proto = Parse(config_json.read(), DeviceConfiguration())
console.print("Configuring device with the following configuration:")
config = syn.Config.from_proto(config_proto)
console.print(config.to_proto())

config_ret = syn.Device(args.uri, args.verbose).configure_with_status(config)
if not config_ret:
console.print("[bold red]Internal error configuring device")
return
console = Console()
config_obj = load_config(args.config_file, console)
if not config_obj:
console.print("[bold red]Failed to parse configuration file")
return

console.print("Configuring device with the following configuration:")
console.print(config_obj.to_proto())

config_ret = syn.Device(args.uri, args.verbose).configure_with_status(config_obj)
if not config_ret:
console.print("[bold red]Internal error configuring device")
return
if config_ret.code != StatusCode.kOk:
console.print(f"[bold red]Error configuring\n{config_ret.message}")
return
Expand Down
7 changes: 4 additions & 3 deletions synapse/client/nodes/application_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
class ApplicationNode(Node):
type = NodeType.kApplication

def __init__(self, name: str):
def __init__(self, name: str, parameters):
self.name = name
self.parameters = parameters

def _to_proto(self):
n = NodeConfig()
p = ApplicationNodeConfig(name=self.name)
p = ApplicationNodeConfig(name=self.name, parameters=self.parameters)
n.application.CopyFrom(p)
return n

Expand All @@ -22,4 +23,4 @@ def _from_proto(proto: ApplicationNodeConfig):
if not isinstance(proto, ApplicationNodeConfig):
raise ValueError("proto is not of type ApplicationNodeConfig")

return ApplicationNode(name=proto.name)
return ApplicationNode(name=proto.name, parameters=proto.parameters)
84 changes: 84 additions & 0 deletions synapse/utils/proto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import os
from pathlib import Path
from google.protobuf import descriptor_pb2, descriptor_pool
from google.protobuf.json_format import Parse
from synapse.api.synapse_pb2 import DeviceConfiguration
from synapse.api.app_pb2 import AppManifest
import synapse as syn


def load_client_protos(descriptor_file_paths, console):
if not descriptor_file_paths:
return

pool = descriptor_pool.Default()
for desc_path in descriptor_file_paths:
if not os.path.exists(desc_path):
console.print(f"[red]Warning:[/red] Descriptor file not found: {desc_path}")
continue
try:
with open(desc_path, "rb") as f:
descriptor_data = f.read()

file_descriptor_set = descriptor_pb2.FileDescriptorSet()
file_descriptor_set.ParseFromString(descriptor_data)

for file_desc in file_descriptor_set.file:
try:
pool.Add(file_desc)
console.print(
f"[green]Successfully loaded descriptor:[/green] {file_desc.name}"
)
except Exception as e:
console.print(
f"[red]Warning:[/red] Could not add {file_desc.name} to pool: {e}"
)

except Exception as e:
console.print(f"[red]Error:[/red] Loading descriptor {desc_path}: {e}")


def load_config(path_to_config, console):
# We support either a manifest or a device configuration.
# First, try to load a device configuration
try:
json_text = open(path_to_config, "r").read()
cfg_proto = Parse(json_text, DeviceConfiguration())
return syn.Config.from_proto(cfg_proto)
except Exception:
pass

# We couldn't load a device configuration, so try to load a manifest
try:
json_text = open(path_to_config, "r").read()
manifest_proto = Parse(json_text, AppManifest())

# First, load the descriptors from the proto_files (but look for .desc)
manifest_dir = Path(path_to_config).resolve().parent

desc_files = []
for proto_file in manifest_proto.proto_files:
# Convert .proto path to .desc path
desc_file = Path(proto_file).with_suffix(".desc")
desc_path = manifest_dir / desc_file
desc_files.append(str(desc_path))

if desc_files:
load_client_protos(desc_files, console)

# Now load the device configuration from the specified path
device_config_path = manifest_dir / manifest_proto.device_config_path

if device_config_path.exists():
device_config_text = device_config_path.read_text()
cfg_proto = Parse(device_config_text, DeviceConfiguration())
return syn.Config.from_proto(cfg_proto)
else:
raise FileNotFoundError(f"Device config not found: {device_config_path}")

except Exception:
raise ValueError(
f"Could not parse {path_to_config} as either device configuration or manifest"
)

return None