def open_listener(): from GlobalContext import DispatchContext for each_line in DispatchContext.lines: # start a thread to listen line server ip_port = str(each_line.ip) + ':' + str(each_line.port) if ip_port in DispatchContext.address_list: continue DispatchContext.address_list.append(ip_port) thread_listener = threading.Thread(target=listen_a_port, args=(each_line.ip, each_line.port), name=('listener:' + ip_port)) thread_listener.setDaemon(True) thread_listener.start() Logger.info("start a new thread for listener a port.") # listen query port for each_line in DispatchContext.lines: # start a thread to listen line server ip_port = str(each_line.query_ip) + ':' + str(each_line.query_port) if ip_port in DispatchContext.address_list: continue DispatchContext.address_list.append(ip_port) thread_listener = threading.Thread(target=listen_a_port, args=(each_line.query_ip, each_line.query_port), name=('listener:' + ip_port)) thread_listener.setDaemon(True) thread_listener.start() Logger.info("start a new thread for listener a port to query.") return 0
def get_dedicated_connection(cls): # 专用连接:数据库服务端一个专有进程处理该连接,相对于共享连接而言 try: return cls.pool.dedicated_connection() except Exception as e: Logger.error("when get dedicated connection from pool!") Logger.error(repr(e)) return None
def send_order_status_to_database(order_no_value, order_status_value, order_id): Logger.info('try to update order line ,id:' + str(order_id) + ' ,order_no :' + str(order_no_value) + ',order_status :' + str(order_status_value)) if order_id is None: Logger.info('order_id is None for send_order_status_to_database!') return -1 if order_no_value is None: Logger.info( 'order_no_value is None for send_order_status_to_database!') return -2 if order_status_value is None: Logger.info( 'order_status_value is None for send_order_status_to_database!') return -3 sql_sentence = SqlCollection.update_order_info.format( order_no=r"'" + str(order_no_value) + r"'", order_status_id=order_status_value, id=order_id) from GlobalContext import DispatchContext rows, error_info = DatabaseInterface.execute_commit_sql( DispatchContext.db_connect, sql_sentence) if error_info is not None or rows is None: Logger.error('send_order_status_to_database error!!! error_info: ' + str(error_info)) return -2 return 0
def get_connection(cls): try: return cls.pool.connection() except Exception as e: Logger.error("when get connection from pool!") Logger.error(repr(e)) return None
def load_sql_interfaces(cls): try: # 如果文件不是uft-8编码方式,读取文件可能报错 cls.get_order_info = cls.process_sql_file_special_character(open('sql/get_order_info.sql', 'r', encoding='utf-8').read()) cls.update_order_info = cls.process_sql_file_special_character(open('sql/update_order_info.sql', 'r', encoding='utf-8').read()) return 0 except Exception as e: Logger.error('when SqlCollection.load_sql_interfaces()!') Logger.error(repr(e)) return -1
def get_order_info(database_connection): db_conn = database_connection sql_sentence = SqlCollection.get_order_info rows, error_info = DatabaseInterface.execute_commit_sql( db_conn, sql_sentence) if error_info is not None or rows is None: Logger.error("get agv info failed due to SQL execution! error_info: " + str(error_info)) return None else: return rows
def create_pool(cls): try: cls.pool = PooledDB(psycopg2, maxconnections = configs.max_connection_num, mincached = configs.min_cached_num, maxcached = configs.max_cached_num, maxshared = configs.max_shared_num, application_name = configs.application_name_for_database_connection, host = configs.database_host, port=configs.database_port, dbname = configs.database_name, user = configs.database_user_name, password=configs.database_password) return cls except Exception as e: Logger.fatal("failed to initialize Database Connection Pool. System is exiting!") Logger.fatal(repr(e)) ToolFunctions.sys_exit(301)
def load_config_from_database(cls, database_connection): # 这里从数据库中读取所有配置参数 # rows, error_info = DatabaseInterface.execute_commit_sql( database_connection, "select 1") if error_info is not None: Logger.error( 'cannot load configuration from the database since the SQL execution fails.' ) return cls configs.configs_from_database = cls return cls
def update_order_status_to_database() -> int: from GlobalContext import DispatchContext for this_line in DispatchContext.lines: if this_line.messages is None: Logger.info('this_line message is not responed !') continue else: if this_line.messages.request_message is not None and this_line.messages.is_response is True: ''' 临时方案 需要将返回来的数据中获取订单编号订单状态 目前暂定 4 ,即接收到回复之后将订单置为4''' temp_order_num = str( this_line.messages.response_message['data']) temp_order_status = 4 send_result = send_order_status_to_database( temp_order_num, temp_order_status, this_line.order_id) this_line.sent_back_database_times += 1 if send_result < 0: Logger.info('send io basket_num to database failed !!!') else: Logger.info(' this line message is not responsed!') if this_line.sent_back_database_times >= 3: # 内存回收 temp_order_id = this_line.order_id DispatchContext.lines_listindex_dict.pop( int(DispatchContext.lines.index(this_line))) DispatchContext.lines_id_dict.pop(int(this_line.order_id)) DispatchContext.lines.remove(this_line) Logger.info( 'line has been removed from DispatchContext.lines for order_id :' + str(temp_order_id)) return 0
def execute_commit_sql(database_connection, sql_sentence): rows = None error_info = None try: cur = database_connection.cursor() cur.execute(sql_sentence) rows = cur.fetchall() database_connection.commit() cur.close() # Logger.debug('One SQL was successfully executed: \n' + sql_sentence) except Exception as e: Logger.error( 'One SQL failed to execute: \n' + str(sql_sentence) ) # need use str() conversion to avoid sql_sentence is None error_info = 'Error: ' + str(repr(e)) Logger.error(error_info) return rows, error_info
def load_order_info(rows) -> int: if rows is None: Logger.error('input row is None!') return -1 line_count = len(rows) if line_count <= 0: Logger.info("no line info to load.") return 0 for each_line in range(0, line_count): current_row = rows[each_line] order_line_info = resolve_line_info(current_row) if order_line_info is None: Logger.error('orderdata ignored row = ' + str(current_row)) continue # if line_info.ip is None or line_info.port is None or line_info.type_id is None: # Logger.error('linedata ignored2. row = ' + str(current_row)) # continue from GlobalContext import DispatchContext if order_line_info.order_id not in DispatchContext.lines_id_dict.keys( ): DispatchContext.lines.append(order_line_info) DispatchContext.lines_listindex_dict[DispatchContext.lines.index( order_line_info)] = order_line_info DispatchContext.lines_id_dict[ order_line_info.order_id] = order_line_info return 0
def Work_Interaction_Loop(): Logger.info('start interaction logic loop') from GlobalContext import DispatchContext # Logger.info('data_package_id : ' + str(DispatchContext.data_package_id)) while True: DispatchContext.all_lock.acquire() try: for current_line in DispatchContext.lines: if current_line.messages is None: current_line.send_generate_task_mesg() Logger.info('send the request message !!!' + str(current_line.messages.request_message)) print(current_line.messages) print(current_line) # print(DispatchContext.lines_id_dict[each_line_info.order_id]) except Exception as e: Logger.error('when execute dispatch logic!') Logger.error(repr(e)) DispatchContext.all_lock.release() Logger.info('Thread for interaction logic keeps alive.') time.sleep(0.3) # sleep time unit is second
def reload_config_from_database(): while (True): database_connection = None try: database_connection = db_pool.get_connection() ConfigFromDatabase.load_config_from_database(database_connection) except Exception as e: Logger.error("when reload configurations from database!") Logger.error(repr(e)) if database_connection is not None: try: database_connection.close() except Exception as e2: Logger.error( 'when try to close the database connection after error during reloading configurations from database.' ) Logger.error(repr(e2)) database_connection.close() Logger.info('Thread to reload config from database keeps alive.') time.sleep(configs.reload_config_from_database_interval)
def resolve_line_info(current_row) -> OrderData or None: if current_row is None: Logger.error('input current_row is None for resolve_line_info!') return None try: # 数据解析 order_line_info = OrderData() order_line_info.order_id = int(current_row[0]) if current_row[1] is not None: order_line_info.order_type_id = int(current_row[1]) else: order_line_info.order_type_id = None if current_row[2] is not None: order_line_info.order_status_id = int(current_row[2]) else: order_line_info.order_status_id = None if current_row[3] is not None: order_line_info.location_id = str(current_row[3]) else: order_line_info.location_id = None if current_row[4] is not None: order_line_info.location_name = current_row[4] else: order_line_info.location_name = None if current_row[5] is not None: order_line_info.destination_location_id = int(current_row[5]) else: order_line_info.destination_location_id = 0 if current_row[6] is not None: order_line_info.destination_location_name = current_row[6] else: order_line_info.destination_location_name = None if current_row[7] is not None: order_line_info.priority = int(current_row[7]) else: order_line_info.priority = 0 order_line_info.is_sent = False return order_line_info except Exception as e: Logger.error("cannot resolve loaded line_info: " + str(current_row)) Logger.error(repr(e)) return None
def do_connect(host,port): from GlobalContext import DispatchContext sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) # DispatchContext.all_lock.acquire() result = None try: str_address = str(host) + ':' + str(port) if str_address in DispatchContext.ip_and_port_connect_dict.keys(): return DispatchContext.ip_and_port_connect_dict[str_address] Logger.info('start to connect this server:' + str_address) sock.connect((host, port)) Logger.info('socket connect success!address: ' + str_address) DispatchContext.ip_and_port_connect_dict[str_address] = sock Logger.info('connect' + str_address + ' success') result = sock except Exception as e : Logger.info('tcp connect error,ip: ' + str(host) + ' ,port:' + str(port)) # time.sleep(3) # DispatchContext.all_lock.release() return result
def listen_a_port(this_ip, this_port): # connect from GlobalContext import DispatchContext ip_and_port = str(this_ip) + ':' + str(this_port) this_socket = do_connect(this_ip, this_port) while True: try: if this_socket is None: Logger.info('connect ' + str(ip_and_port) + ' error,try again!') this_socket = do_connect(this_ip, this_port) continue data = this_socket.recv(1024).decode('utf8') Logger.info('recv data package: ' + str(data)) if is_heartbeat(data, this_socket): Logger.info('is_heartbeat ok') continue check_result = check_and_update_package_data(data) if check_result: Logger.info('add to line.messages') if data == '': # 连接中断时返回'' if ip_and_port in DispatchContext.ip_and_port_connect_dict.keys(): DispatchContext.ip_and_port_connect_dict[ip_and_port].close() DispatchContext.ip_and_port_connect_dict.pop(ip_and_port) Logger.info('pop socket:' + str(ip_and_port)) this_socket = do_connect(this_ip, this_port) time.sleep(1) except Exception as e: Logger.error("when get data from tcp!") try: this_socket.send('HEAD00010006000000041234TAIL'.encode('utf8')) # 发送心跳报文测试连接状态 except: this_socket = do_connect(this_ip, int(this_port)) time.sleep(0.1)
def send_generate_task_mesg(self): ''' 发送 任务方法 ''' from GlobalContext import DispatchContext # if self.is_sent is False: # Logger.info('this line.message has not sent!,try to send message!') # return -1 if self.messages is None: new_message = OrderMessage() new_message.data_package_id = get_data_package_id() temp_message = { "reqCode": "2312257536", "taskTyp": "W01", "wbCode": "", "positionCodePath": [{ "positionCode": "A2", "type": "00" }, { "positionCode": "A4", "type": "00" }], "podCode": "-1", "AgvCode": "6" } #选择发送订单的模板 # 1 : W01 2:W02 数据库插入时 需要控制 订单类型 即模板类型 if self.order_type_id == 1: # 1 : W01 2:W02 temp_message['taskTyp'] = 'W01' else: # 1 : W01 2:W02 temp_message['taskTyp'] = 'W02' temp_message["reqCode"] = str(new_message.data_package_id) temp_message['positionCodePath'][0]['positionCode'] = str( self.location_name) temp_message['positionCodePath'][1]['positionCode'] = str( self.destination_location_name) new_message.request_message = json.dumps(temp_message) try: url = "http://192.168.101.34:80/cms/services/rest/hikRpcService/genAgvSchedulingTask" a = requests.post(url) headers = {'content-type': 'application/json'} ret = requests.post(url, data=new_message.request_message, headers=headers) new_message.request_times = 1 new_message.request_time = time.time() self.is_sent = True Logger.info( 'this line has sent the request for generating task!!') print(ret.status_code) if ret.status_code == 200: Logger.info( ' this line message has been responed, send status:200!' ) text = json.loads(ret.text) Logger.info('recv the return message ' + str(text)) new_message.is_response = True # 发送已收到回复 new_message.response_message = text # 记录发送之后,收到的回复的数据 new_message.return_code = 0 # 发送已收到回复 else: Logger.info( ' the status_code is not 200 some error occur! please check it now' + str(ret.status_code)) self.messages = new_message DispatchContext.package_id_line_dict[ new_message.data_package_id] = self except Exception as e: Logger.error('the socket connect failed!') Logger.error(repr(e)) else: ''' 消息 不为空 表示已经发送了 消息 ''' if self.messages.is_response: # 消息发送已经收到回复 Logger.info( 'this request message is responsed,need not to send message again!' ) else: # when return != 0 发送了没有收到回复 需要再次发送 self.messages.request_times += 1 self.messages.request_time = time.time() url = "http://192.168.101.34:80/cms/services/rest/hikRpcService/genAgvSchedulingTask" a = requests.post(url) headers = {'content-type': 'application/json'} ret = requests.post(url, data=self.messages.request_message, headers=headers) print(ret.status_code) if ret.status_code == 200: text = json.loads(ret.text) Logger.info('recv the return message ' + str(text)) self.messages.response_message = text self.messages.return_code = 0 Logger.info('message is not responsed,send again:' + str(self.messages.request_message)) return 0
def synchronize_data(): if DatabaseResource.database_connection is None or DispatchContext.db_connect: DatabaseResource.database_connection = db_pool.get_connection() db_conn = DatabaseResource.database_connection DispatchContext.db_connect = db_conn Logger.info('Starting to synchronize data with database in this cycle...') while True: try: error_flag = False Logger.info( 'Starting to synchronize data with database in this cycle...') # synchronizing data # data_package_id # write config_file_path to config.ini import configparser import os config_file_path = os.getcwd() + "/config/config.ini" config_writer = configparser.ConfigParser() config_writer.read(config_file_path) config_writer.set('tcp_connect_config', 'data_package_id', str(DispatchContext.data_package_id)) config_writer.write(open(config_file_path, 'w')) try: DispatchContext.all_lock.acquire() # 实时 将数据库中的数据 读取到内存中 lines = get_order_info(db_conn) load_result = load_order_info(lines) if load_result < 0: Logger.error('send_database_agv_command failed!') error_flag = True # 实时将 订单返回的数据 回写到数据库 update_result = update_order_status_to_database() if update_result < 0: Logger.error( 'send_database to order_info order_status failed!') error_flag = True # update_result = refresh_line_io_states(db_conn) # if update_result < 0: # Logger.error('send_database_agv_command failed!') # error_flag = True # update_result = update_line_status_to_database() # if update_result < 0: # print(update_result)this_line basket num for update_all_io_to_zero! # Logger.error('send_database line status to io_state failed!') # error_flag = True except Exception as e: Logger.error('when refresh data to DispatchContext!') Logger.error(repr(e)) DispatchContext.all_lock.release() if error_flag: raise Exception('error happened when synchronize data!') # from GlobalContext import DispatchContext for each_line_info in DispatchContext.lines: print(each_line_info) print(DispatchContext.lines_id_dict[each_line_info.order_id]) # from Line import send_order_status_to_database # send_order_status_to_database('erghyfjugkyf',4,2) except Exception as e: Logger.error("when synchronizing data with database!") Logger.error(repr(e)) # test database connection test_db_result = DatabaseInterface.test_database_connection( db_conn) if test_db_result: Logger.info( 'database connection for synchronization data was tested and showed to be good.' ) else: # connection is bad, try to close current connection and get a new one Logger.error( "synchronize_data(): database connection is bad, trying to close current connection and get a new one." ) old_db_conn = db_conn new_db_conn = db_pool.get_connection() if new_db_conn is None: Logger.error( "synchronize_data(): cannot get a new database connection!" ) else: Logger.info( "synchronize_data(): already got a new database connection." ) db_conn = DatabaseResource.database_connection = new_db_conn try: old_db_conn.close() except Exception as e2: Logger.error( 'synchronize_data(): when try to close the old database connection after getting a new one!' ) Logger.error(repr(e2)) Logger.info('Thread for data synchronization keeps alive.') time.sleep(0.3) # sleep time unit is second
def check_and_update_package_data(package_data): package_data = package_data.strip() message_len = len(package_data) # print('the data length:' + str(len(package_data))) Logger.info('check_and_update_package_data this message') # if message_len != 28 or message_len != 40: # Logger.info('package_data len error,ignore it!') # return False # 交互响应 if message_len == 28: if package_data[0:4] != 'HEAD' or package_data[24:28] != 'TAIL': Logger.info('package_data formal error,ignore it!') return False data_package_id = int(package_data[4:8]) do_code = int(package_data[8:12]) error_code = int(package_data[12:16]) data_len = int(package_data[16:20]) return_code = int(package_data[20:24]) if do_code != 2 or error_code != 0: Logger.info('do_code or error_code error ignore it!') return False from GlobalContext import DispatchContext if data_package_id not in DispatchContext.package_id_line_dict.keys(): Logger.info('have not send this package id') return False if return_code != 0: return False this_line: LineData = DispatchContext.package_id_line_dict[data_package_id] if this_line.messages is None: Logger.info('messages is None for check_and_update_package_data,line: ' + str(this_line)) return False current_message = this_line.messages current_message.response_time = time.time() current_message.is_response = True current_message.response_message = package_data current_message.return_code = return_code Logger.info('add data to line!') return True # 查询回复 if message_len == 40: if package_data[0:4] != 'HEAD' or package_data[36:40] != 'TAIL': Logger.info('package_data formal error,ignore it!') return False # print('data length is :'+str(message_len)) '''将 数量 返回到 轨道类中 并更新到数据库''' data_package_id = int(package_data[4:8]) opt_code = int(package_data[8:12]) error_code = int(package_data[12:16]) data_len = int(package_data[16:20]) return_code = int(package_data[20:24]) line_id = int(package_data[24:28]) slice_num = int(package_data[28:32]) real_basket_num = int(package_data[32:36]) if opt_code != 3 or error_code != 0: Logger.info('do_code or error_code error ignore it!') return False from GlobalContext import DispatchContext if data_package_id not in DispatchContext.query_package_id_line_dict.keys(): Logger.info('have not send this package id') return False this_line: LineData = DispatchContext.query_package_id_line_dict[data_package_id] if this_line.id == line_id: Logger.info('set line' + str(this_line.id) + '.basket_num = ' + str(real_basket_num) + ',slice_num = ' + str(slice_num)) this_line.basket_num = real_basket_num this_line.slice_num = slice_num else: Logger.info('return line: ' + str(line_id) + '+basket num to line:' + str(this_line.id) + ', ignore it!') if this_line.query_messages is None: Logger.info('query_messages is None for check_and_update_package_data,line: ' + str(this_line)) return False current_query_message = this_line.query_messages current_query_message.response_time = time.time() current_query_message.is_response = True current_query_message.response_message = package_data current_query_message.return_code = return_code return True