from typing import Any, List, Tuple import grpc, logging from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method from device.proto.context_pb2 import Device, DeviceConfig, DeviceId, Empty from device.proto.device_pb2_grpc import DeviceServiceServicer from .data_cache.DataCache import DataCache from .driver_api._Driver import _Driver from .driver_api.DriverInstanceCache import DriverInstanceCache from .driver_api.FilterFields import FilterFieldEnum #from .Tools import check_device_id_request, check_device_request LOGGER = logging.getLogger(__name__) SERVICE_NAME = 'Device' METHOD_NAMES = ['AddDevice', 'ConfigureDevice', 'DeleteDevice', 'GetInitialConfig'] METRICS = create_metrics(SERVICE_NAME, METHOD_NAMES) class DeviceServiceServicerImpl(DeviceServiceServicer): def __init__(self, data_cache : DataCache, driver_instance_cache : DriverInstanceCache): LOGGER.debug('Creating Servicer...') self.data_cache = data_cache self.driver_instance_cache = driver_instance_cache LOGGER.debug('Servicer Created') @safe_and_metered_rpc_method(METRICS, LOGGER) def AddDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: device_id = request.device_id device_uuid = device_id.device_uuid.uuid self.data_cache.sync_device_from_context(device_uuid) db_device,_ = self.data_cache.set_device(request) driver_filter_fields = self.data_cache.get_device_driver_filter_fields(device_uuid) driver : _Driver = self.driver_instance_cache.get(device_uuid, **driver_filter_fields) driver.Connect() running_config_rules = driver.GetConfig() self.data_cache.update_device_config_in_local_database(device_uuid, 'running', running_config_rules) initial_config_rules = driver.GetInitialConfig() self.data_cache.update_device_config_in_local_database(device_uuid, 'initial', initial_config_rules) self.data_cache.sync_device_to_context(device_uuid) return DeviceId(**db_device.dump_id()) @safe_and_metered_rpc_method(METRICS, LOGGER) def ConfigureDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId: device_id = request.device_id device_uuid = device_id.device_uuid.uuid config_name = 'running' self.data_cache.sync_device_from_context(device_uuid) db_device,_ = self.data_cache.set_device(request) # Compute list of changes between device_config in context, and device_config in request set_changes : List[Tuple[str, Any]] = [] delete_changes : List[Tuple[str, Any]] = [] subscriptions : List[Tuple[str, Any]] = [] unsubscriptions : List[Tuple[str, Any]] = [] driver_filter_fields = self.data_cache.get_device_driver_filter_fields(device_uuid) driver : _Driver = self.driver_instance_cache.get(device_uuid, **driver_filter_fields) driver.Connect() result = driver.SetConfig(set_changes) # check result result = driver.DeleteConfig(delete_changes) # check result result = driver.SubscribeState(subscriptions) # check result result = driver.UnsubscribeState(unsubscriptions) # check result self.data_cache.sync_device_to_context(device_uuid) return DeviceId(**db_device.dump_id()) @safe_and_metered_rpc_method(METRICS, LOGGER) def DeleteDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: device_uuid = request.device_uuid.uuid self.data_cache.sync_device_from_context(device_uuid) db_device = self.data_cache.get_device(device_uuid) driver_filter_fields = self.data_cache.get_device_driver_filter_fields(device_uuid) driver : _Driver = self.driver_instance_cache.get(device_uuid, **driver_filter_fields) driver.Disconnect() self.data_cache.delete_device_from_context(device_uuid) db_device.delete() return Empty() @safe_and_metered_rpc_method(METRICS, LOGGER) def GetInitialConfig(self, request : DeviceId, context : grpc.ServicerContext) -> DeviceConfig: device_uuid = request.device_uuid.uuid self.data_cache.sync_device_from_context(device_uuid) db_device = self.data_cache.get_device(device_uuid) return DeviceConfig(device_config={'config_rules': db_device.dump_initial_config()})