import configparser import socket import select import abc import sys from . import settings DEBUG_FILE = True ''' Generic class for simulators. Initializes the sockets and the grammar, reads the CONFIG_FILE. Classes inheriting from it must call the __init__ function with their name (Telescope, CameraVIS, ...) ''' class DeviceSim(object): __metaclass__ = abc.ABCMeta name = "" config_socket_file = "../../config/socket_config.ini" config = None connected = False sock = None ip = None port = None connections = [] def __init__(self, device_name): super().__init__() def setDevice(self, device_name): self.name = device_name self.getConfig() #self.getConnection(device_name) self.getConnection() self.listen() def configSocket(self): self.sock.settimeout(1) @abc.abstractmethod def set(self, command: str, *args): return @abc.abstractmethod def do(self, command: str, *args): return @abc.abstractmethod def get(self, command: str, *args): return def forceLog(self, name, message: str): print(name + " FORCE LOG : " + message) def accept(self): try: # Accept a connection. # The socket must be bound to an address and listening for connections. # The return value is a pair (conn, address) # where conn is a new socket object usable to send and receive data on the connection, # and address is the address bound to the socket on the other end of the connection. connection, address = self.sock.accept() except socket.timeout: if len(self.connections) == 0: print(self.name, "No connection established") self.log(self.name, "No connection established") return False except socket.error as e: print(str(e)) print(self.name, "No connection established") self.log(self.name, "No connection established") return False self.connections.append({"connection": connection, "address": address}) self.log(self.name, "Connection successfully established") return True def close(self, connection_address): if (connection_address): connection_address["connection"].close() self.connections.remove(connection_address) return (0) return (1) def sendMessage(self, message: str, co) -> int: if (not co["connection"] or not co["address"]): #(EP) return (1) raise Exception("sendMessage(): no connection or no address") try: readable, writable, exceptional = select.select([], [co["connection"]], [co["connection"]], 0) if not (writable or exceptional): raise (Exception("Socket not writable " + str(co["address"]))) co["connection"].send(bytes(message, "UTF-8")) #self.forceLog(self.name, "Message sent [" + message + "] to " + str(co["address"])) self.forceLog(self.name, "Message sent to " + str(co["address"]) +" : [" + message + "]") self.log(self.name, "Message sent to " + str(co["address"]) +" : [" + message + "]") except Exception as e: if (settings.DEBUG): print(self.name, "Could not send message on socket "+ str(co["address"]) +" : " + message + " -> " + str(e)) self.log(self.name, "Could not send message on socket "+ str(co["address"]) +" : " + message + " -> " + str(e)) return (1) return (0) def isError(self, message: str): if (message == "FAILED" or message == "NOT_SET" or message == "DISCONNECTED"): return (True) return (False) def isConnected(self): self.accept() if not self.connections: return False return True def readBytes(self, size, co) -> str: if (not co["connection"] or not co["address"]): #(EP) return ("NOT_SET") raise Exception("NOT_SET, no connection or address") try: readable, writable, exceptional = select.select([co["connection"]], [], [co["connection"]], 0) if not (readable or exceptional): raise (Exception("Socket not readable" + str(co["address"]))) ret = co["connection"].recv(size).decode() if (not ret): if (settings.DEBUG): print(self.name, "Connection has been killed" + str(co["address"])) self.log(self.name, "Connection has been killed" + str(co["address"])) self.connections.remove(co) #(EP) return ("DISCONNECTED") raise Exception("DISCONNECTED") self.forceLog(self.name, "Message received on " + str(co["address"]) +" : [" + ret + "]") self.log(self.name, "Message received on " + str(co["address"]) + " : [" + ret + "]") except Exception as e: if (settings.DEBUG): print(self.name, "Socket not readable : " + str(e)) self.log(self.name, "Socket not readable : " + str(e)) return ("FAILED") #raise Exception("FAILED") return (ret) def blockAndReadBytes(self, size) -> str: self.sock.setblocking(1) return (self.readBytes(size)) def blockAndReadMessage(self) -> str: return (self.blockAndReadBytes(2048)) def setBlocking(self, flag, connection): if (not connection["connection"]): return (1) connection["connection"].setblocking(flag) return (0) # TODO maybe read more than 2048 bytes for a single message ????? def readMessage(self, connection) -> str: return self.readBytes(2048, connection) #def getConnection(self, device_name): def getConnection(self): #self.ip = self.config.get(device_name, "ip") #self.port = int(self.config.get(device_name, "port")) self.ip = self.config.get(self.name, "ip") self.port = int(self.config.get(self.name, "port")) return (0) def getConfig(self): self.config = configparser.ConfigParser() self.config.read(self.config_socket_file) return (0) def log(self, device_name: str, message: str): if DEBUG_FILE: print("From simulator : " + device_name + " -> " + message, file=sys.stderr) return (0) def listen(self): if (self.ip is None or self.port is None): self.log(self.name, "Ip or Port not initialized") # (EP) It's a serious bug, so raise exception !!! #return (1) raise Exception(self.name +" has no ip or port") try: self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.settimeout(1) self.sock.bind((self.ip, self.port)) self.sock.listen(122) except Exception as e: if (settings.DEBUG): self.log(self.name, "Failed to listen to " + str(self.ip) + ":" + str(self.port)) # (EP) It's a serious bug, so raise exception !!! #return (1) raise Exception(self.name, "failed to listen to " + str(self.ip) + ":" + str(self.port)) self.connected = True return (0) # class Device(): # def __init__(self, simul_name): # # config = configparser.ConfigParser() # config.read(CONFIG_FILE) # # ip = config.get(simul_name, "ip") # port = int(config.get(simul_name, "port")) # # self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # self.sock.bind((ip, port)) # self.sock.listen(122) # # self.set_msgs = [] # self.get_msgs = [] # self.do_msgs = [] # # self.enums = {} # # with open(GRAMMAR_FILE) as grammar_file: # grammar = json.load(grammar_file) # # enums = grammar["Enums"] # # for enum in enums : # self.enums[enum] = enums[enum] # # if simul_name[:6] == "Camera": # device = grammar["Camera"] # # for item in device["set"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # ''' This transforms 'int' string to type ''' # param_type = locate(param_type) # self.set_msgs.append((item["name"], item["nb_param"], param_type)) # for item in device["get"]: # self.get_msgs.append(item) # for item in device["do"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.do_msgs.append((item["name"], item["nb_param"], param_type)) # # device = grammar[simul_name] # # for item in device["set"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.set_msgs.append((item["name"], item["nb_param"], param_type)) # for item in device["get"]: # self.get_msgs.append(item) # for item in device["do"]: # param_type = item["param_type"] # if len(param_type) < 4 or param_type[:4] != "Enum": # param_type = locate(param_type) # self.do_msgs.append((item["name"], item["nb_param"], param_type))