def sync_manual(self): ''' 手动同步, 与ats进行同步 { cmd: "get_time_table", data: { "date": '2019-08-13' } }, { cmd: "get_cur_train_info", data: { "location": 99, # 99 高大路, 98板桥 } } :return: ''' today_obj = pendulum.today("UTC").add(hours=8) today_str = today_obj.format("YYYY-MM-DD") ban_qiao = self.env.ref("metro_park_base_data_10.ban_qiao").id gao_da_lu = self.env.ref("metro_park_base_data_10.gao_da_lu").id self.env["metro_park_dispatch.msg_client"] \ .get_time_tables([{ "location": ban_qiao, "date": today_str }, { "location": gao_da_lu, "date": today_str }]) LogManage.put_log(content='手动同步', mode='manual_sync') raise exceptions.Warning("命令已发送,请等待ats回传信息")
def add_plan_operation_log(self, location): ''' 添加信号楼日志 :return: ''' LogManage.put_log(content="消息回调处理异常{error}".format(error=callback_error), mode="socketio_log")
async def disconnect(): ''' 断开连接 :return: ''' _logger.info('the app server connect is dropped!') LogManage.put_log(content="socketio 客户端断开!", mode="socketio_client_log")
async def on_connect(): ''' 连接成功 :return: ''' _logger.info('connect to app server success!') LogManage.put_log(content="socketio 客户端已经联接", mode="socketio_client_log")
async def execute_msg(msg): ''' 后台任务发送消息 :return: ''' count = 0 try: if msg["msg_type"] and msg["data"]: _logger.info("begin deal socketio msg...!") room = msg.get("room", None) callback_info = msg.get("callback_info", None) if callback_info: def call_back(_callback_info, *args, **kwargs): try: res_ids = _callback_info.get('ids', []) context = _callback_info.get('context', []) model_env.deal_event(data={ "msg_type": "call", "uid": _callback_info.get("uid", None), "room": room, "model": _callback_info["model"], "name": _callback_info["name"], 'res_ids': res_ids, "args": args, "kwargs": kwargs, 'context': context }) except Exception as callback_error: import traceback traceback.print_exc() _logger.error(callback_error) LogManage.put_log(content="消息回调处理异常{error}".format(error=callback_error), mode="socketio_log") await sio.emit(msg["msg_type"], data=msg["data"], to=msg.get("sid", None), callback=partial(call_back, copy.deepcopy(callback_info)), room=room) else: await sio.emit(msg["msg_type"], data=msg["data"], to=msg.get('sid', None), room=room) _logger.info("deal socketio msg finished...!") # 用于查看后台是否正常运行 if count > 50: count = 0 LogManage.put_log(content="socketio 后台服务处理数据完成!", mode="socketio_log") else: count += 1 except Exception as tmp_error: import traceback traceback.print_exc() _logger.error(tmp_error) LogManage.put_log(content="消息处理异常{error}".format(error=tmp_error), mode="socketio_log")
def _update_last_login(self): ''' 登录成功之后将当日失败次数清零,清空失败起始时间,限制时间回到1分 :return: ''' super()._update_last_login() LogManage.put_log(content='用户登录系统', mode='login') self.env.user.write({ 'today_continuous_error_count': 0, 'no_login_minute': 1, 'no_login_start_time': None })
async def inner_run(): ''' 内部运行 :return: ''' socket_host = config.options.get('socket_io_app_server', '') or '0.0.0.0:9080' url = 'http://' + socket_host _logger.info('connect to socketio server, address %s' % url) LogManage.put_log(content='connect to socketio server, address %s' % url, mode="socketio_client_log") # 服务端有可能还没启动,client_io在第一次连接成功以后才会重联 connected = False await client_io.connect(url) await client_io.wait() LogManage.put_log(content="客户退退出!", mode="socketio_client_log")
def get_sio_cookies(cls, environ): ''' 从sio取得cookie :param environ: :return: ''' try: cookie = {} if 'HTTP_COOKIE' in environ and environ['HTTP_COOKIE']: http_cookie = environ['HTTP_COOKIE'].strip().split(';') for ck in http_cookie: k, v = ck.strip().split('=') cookie[k] = v return cookie return None except Exception as tmp_error: _logger.info( "can not get cookie: {environ}".format(environ=environ)) LogManage.put_log(content='处理cookie发生错误 {error}'.format(error=tmp_error), mode="socketio_log")
def call_back(_callback_info, *args, **kwargs): try: res_ids = _callback_info.get('ids', []) context = _callback_info.get('context', []) model_env.deal_event(data={ "msg_type": "call", "uid": _callback_info.get("uid", None), "room": room, "model": _callback_info["model"], "name": _callback_info["name"], 'res_ids': res_ids, "args": args, "kwargs": kwargs, 'context': context }) except Exception as callback_error: import traceback traceback.print_exc() _logger.error(callback_error) LogManage.put_log(content="消息回调处理异常{error}".format(error=callback_error), mode="socketio_log")
def init_cur_train(self): ''' 初始化现车, 这里应当是调用ats的现车信息 :return: ''' trains = self.env['metro_park_maintenance.train_dev'].search([]) train_cache = {train.id: train for train in trains} train_ids = trains.ids records = self.search([]) # 当前车辆的id cur_train_ids = records.mapped("train.id") vals = [] for tmp_id in train_ids: if tmp_id not in cur_train_ids: val = { 'train': tmp_id, 'train_status': 'wait', 'cur_location': train_cache[tmp_id].location.id, 'old_status': 'wait', } vals.append(val) self.create(vals) LogManage.put_log(content='同步车辆', mode='synchronous_vehicles')
def notify_train_position_changed(self, rail_location=None): ''' 模拟车辆到达 :return: ''' self.ensure_one() if self.cur_switch or self.cur_rail: alias = self.cur_location.alias state = self.make_position_info() self.trigger_up_event('funenc_socketio_server_msg', data={ "msg_type": "update_train_position", "location_alias": alias, "msg_data": [state] }) LogManage.put_log(content='通知车{name}到达位置{position}'.format( name=state["name"], position=state["position"]), mode='cur_train_position_change') else: try: # 可能是后台来的,没法区分用户 alias = self.env.user.cur_location.alias or rail_location state = self.make_position_info() self.trigger_up_event('funenc_socketio_server_msg', data={ "msg_type": "update_train_position", "location_alias": alias, "msg_data": [state] }) LogManage.put_log( content='通知移除{name}位置'.format(name=state["name"]), mode='cur_train_position_change') except Exception as error: _logger.info( "update position error!{error}".format(error=error))
def get_uid_id_from_sio(cls, environ): ''' 取得session_id, 用于从odoo查询用户信息 :param environ: :return: ''' cookies = cls.get_sio_cookies(environ) if cookies: session_id = cookies.get("session_id", None) if not session_id: return False try: session_info = root.session_store.get(session_id) if not session_info: _logger.info("the user is login out!") return False except Exception as tmp_error: _logger.info("get session store error, {error}".format(error=tmp_error)) LogManage.put_log(content='get session store error {error}'.format(error=tmp_error), mode="socketio_log") uid = session_info.get('context', {}).get("uid", False) return uid else: return False
def deal_event(self, data=None): """ 处理事件消息,类似rpc :param data: :return: """ LogManage.put_log(content="收到中转服务器请求", mode="socketio_client_log") try: with api.Environment.manage(), self.db_registry.cursor() as cr: env = api.Environment(cr, SUPERUSER_ID, {}) model_name = data.get('model', False) model = env[model_name] args = data.get('args', []) kwargs = data.get('kwargs', {}) data_rec = getattr(model, data.get('method'))(*args, **kwargs) LogManage.put_log(content="socketio客户端数据处理完成", mode="socketio_client_log") return data_rec except Exception as error: LogManage.put_log(content="处理中转服务器请求出错{error}".format(error=error), mode="socketio_client_log") return False
def update_position(self, location, dev_no, rail_no): ''' 更新现车位置 :param location: :param dev_no: :param rail_no: :return: ''' run_train = self.search([("train.dev_no", "=", dev_no)]) if not run_train: # 没有就创建车辆 run_train = self.create_run_train(dev_no, run_train) # 为了防止车号被行调删除(出现过被正线行调强行删除的情况,真是坑),直接返回,使用联锁进行判断 if not rail_no: return run_train.id rail = self.env["metro_park_base.rails_sec"]\ .search([('no', '=', rail_no), ('location', '=', location)]) if rail: # 由于ATS B股可能会出错,所以这里避开 if rail.port and rail.port == "B": return run_train.id rail_type_back_sec_id = self.env.ref( "metro_park_base.rail_type_back_sec").id rail_type_out_sec_id = self.env.ref( "metro_park_base.rail_type_out_sec").id LogManage.put_log( content='车{name}到达出{position}, ATS记录,不改变位置'.format( name=run_train["train_no"], position=rail["no"]), mode='cur_train_position_change') # 到达迁出线时删除车号 if rail.rail_type.id == rail_type_back_sec_id \ or rail.rail_type.id == rail_type_out_sec_id: # 两个都给清除掉 run_train.cur_switch = False run_train.cur_rail = False # 提前提交,防止别的线程访问不到数据, 这里是因为socketio的这个机制是要等侍回调返回, # 而别的地方使用的是另外的cursor,所以会访问不到数据 self._cr.commit() run_train.notify_train_position_changed(rail.location.alias) # 通知前端位置发生变化, 清除了无法知道位置 LogManage.put_log( content='车{name}到达{position}, 清除位置, ATS'.format( name=run_train["train_no"], position=rail["no"]), mode='cur_train_position_change') else: # 只有在转换轨道的时候才更新位置 rail_type_exchange_id = \ self.env.ref("metro_park_base.rail_type_exchange").id if rail.rail_type.id == rail_type_exchange_id: # 有可能联锁占压判断以后,它发又车还原回去了,所以只能车原来在转换轨道的时候发送 # 出去的时候无所谓,出去全部由mdias判断, 转换轨不设置车位置,所以车辆的当状轨道 # 和道岔只能为空 if not (run_train.cur_rail and run_train.cur_switch): run_train.cur_rail = rail.id run_train.cur_switch = False # 到达转换轨 LogManage.put_log( content='车{name}到达{position}, 到达转换轨-ATS'.format( name=run_train["train_no"], position=rail["no"]), mode='cur_train_position_change') # 提前提交,防止别的线程访问不到数据 self._cr.commit() # 通知前端位置发生变化 run_train.notify_train_position_changed() else: LogManage.put_log( content='车{name}到达{position}, 但原车已经在在场内-ATS'. format(name=run_train["train_no"], position=rail["no"]), mode='cur_train_position_change') else: # 记录, 用于联锁推断不出来的时候使用ats来更正 run_train.ats_position = rail_no return run_train.id
def on_ok(self): ''' 导入运行图 :return: ''' cur_location = self.env.user.cur_location if not cur_location: raise exceptions.ValidationError("当前用户没有配置位置信息。") main_line = self.env.ref( "metro_park_base_data_6.main_line_location").id hui_long = self.env.ref("metro_park_base_data_6.hui_long").id pi_tong = self.env.ref("metro_park_base_data_6.pi_tong").id time_table_model = self.env['metro_park_base.time_table'] locations_model = self.env['metro_park_base.location'] time_table_data_model = self.env['metro_park_base.time_table_data'] # 分为从时刻表导入和从运行图概要导入 if self.type == 'run_plan': time_table = time_table_model.create({ 'no': self.no, 'time_table_type': self.time_table_type, }) datas = self.read_excel() # 检查表头 if len(datas) < 2: raise exceptions.ValidationError('数据表格式不正确,行数小于2') # 检查表头 header_row = datas[0] if header_row[INDEX_COL] != '序号': raise exceptions.Warning('表头"序号"不正确, 请修正后再导入!') if header_row[TRAIN_NO_COL] != '车底ID': raise exceptions.Warning('表头"车底ID"不正确, 请修正后再导入!') if header_row[PLAN_OUT_LOCATION_COL] != '出库位置': raise exceptions.Warning('表头"出库位置"不正确, 请修正后再导入!') if header_row[PLAN_OUT_TIME_COL] != '出车场时间': raise exceptions.Warning('表头"出车场时间"不正确, 请修正后再导入!') if header_row[PLAN_BACK_LOCATION_COL] != '入库位置': raise exceptions.Warning('表头"入库位置"不正确, 请修正后再导入!') if header_row[PLAN_BACK_TIME_COL] != '回车场时间': raise exceptions.Warning('表头"回车场时间"时间不正确, 请修正后再导入!') # 取得所有的场段名称 valid_rows = [] locations_ar = [] for row in datas: if len(row) > 1: index = row[0] if re.match(r'^\d+(.0)?$', str(index)): valid_rows.append(row) locations_ar.append(row[PLAN_OUT_LOCATION_COL]) locations_ar.append(row[PLAN_BACK_LOCATION_COL]) locations = locations_model.search([('name', 'in', locations_ar)]) if len(locations) == 0: raise exceptions.ValidationError("没有找到位置数据!") location_cache = { location['name']: location['id'] for location in locations } vals = [] for row in valid_rows: out_location = row[PLAN_OUT_LOCATION_COL].strip() back_location = row[PLAN_BACK_LOCATION_COL].strip() # 只要有一个就添加数据 if out_location in location_cache or back_location in location_cache: if out_location not in location_cache: out_location = main_line else: out_location = location_cache.get(out_location) if back_location not in location_cache: back_location = main_line else: back_location = location_cache.get(back_location) # 转换为utc时间 plan_out_time = pendulum.parse('2019-01-01 ' + str(row[PLAN_OUT_TIME_COL])) plan_out_time = plan_out_time.subtract(hours=8) plan_back_time = pendulum.parse( '2019-01-01 ' + str(row[PLAN_BACK_TIME_COL])) plan_back_time = plan_back_time.subtract(hours=8) # 时间格式检验 vals.append({ 'sequence': int(row[INDEX_COL]), 'train_no': str(row[TRAIN_NO_COL]), 'out_location': out_location, 'plan_out_time': plan_out_time.format( 'YYYY-MM-DD HH:mm:ss'), # 这里时间查询时要注意 'plan_in_time': plan_back_time.format( 'YYYY-MM-DD HH:mm:ss'), # 这里时间查询时要注意 'back_location': back_location, 'time_table_id': time_table['id'] }) if len(vals) == 0: raise exceptions.ValidationError('没有导入任何数据,请检查文件是否正确') time_table_data_model.create(vals) LogManage.put_log(content='导入运行图', mode='import_diagram') return False else: time_table = time_table_model.create({ 'no': self.no, 'time_table_type': self.time_table_type, }) bin_data = base64.b64decode(self.xls_file) workbook = xlrd.open_workbook(file_contents=bin_data) sheet = workbook.sheet_by_index(0) vals = [] for i in range(1, sheet.nrows): data = sheet.row_values(i) if data[4] == "回龙停车场": out_location = hui_long elif data[4] == "郫筒": out_location = pi_tong else: out_location = main_line if data[5] == "回龙停车场": back_location = hui_long elif data[5] == "郫筒": back_location = pi_tong else: back_location = main_line plan_out_time = pendulum.parse('2019-01-01 ' + str(data[6])) plan_out_time = plan_out_time.subtract(hours=8) plan_back_time = pendulum.parse('2019-01-01 ' + str(data[8])) if plan_back_time.hour < 3: plan_back_time = pendulum.parse('2019-01-03 ' + str(data[8])) plan_back_time = plan_back_time.subtract(hours=8) vals.append({ 'sequence': data[0], 'train_no': data[1], 'out_location': out_location, 'plan_out_time': plan_out_time.format('YYYY-MM-DD HH:mm:ss'), # 这里时间查询时要注意 'plan_in_time': plan_back_time.format('YYYY-MM-DD HH:mm:ss'), # 这里时间查询时要注意 'back_location': back_location, 'time_table_id': time_table['id'], 'miles': data[11] }) if len(vals) == 0: raise exceptions.ValidationError('没有导入任何数据,请检查文件是否正确') time_table_data_model.create(vals) LogManage.put_log(content='导入车底运用指标', mode='import_diagram')
def receive_train(self): ''' 接车, 开始排列进路, 进路开始排了才是 :return: ''' location = self.get_location_spell() data = self.get_plan_data() if data: if data["instructs"] == []: try: # 添加日志 log_record = self.env[ "metro_park_dispatch.train_in_out_log"].create([{ "type": "out_plan", "train_dev": self.train_id.train.id, "operation": "收车计划勾计划为空:{out_instructs}".format( out_instructs=str(data["instructs"])) }]) data["log_id"] = log_record.id except Exception as error: _logger.info("log error {error}".format(error=error)) else: try: # 添加日志 log_record = self.env[ "metro_park_dispatch.train_in_out_log"].create([{ "type": "out_plan", "train_dev": self.train_id.train.id, "operation": "收车计划勾计划:{out_instructs}".format( out_instructs=str(data["instructs"])) }]) data["log_id"] = log_record.id except Exception as error: _logger.info("log error {error}".format(error=error)) self.state = 'preparing' try: # 添加日志 log_record = self.env[ "metro_park_dispatch.train_in_out_log"].create([{ "type": "out_plan", "train_dev": self.train_id.train.id, "operation": "推送收车计划:{start_rail}-{end_rail}到信号楼".format( start_rail=self.real_start_rail.no, end_rail=self.plan_back_rail.no) }]) data["log_id"] = log_record.id except Exception as error: _logger.info("log error {error}".format(error=error)) # 之前出现指令重复的情况,防止重复 cache = dict() instructs = data["instructs"] new_instructs = [] for instruct in instructs: if instruct["start_rail"] not in cache: new_instructs.append(instruct) cache[instruct["start_rail"]] = True data["instructs"] = new_instructs # 添加计划, 信号楼如果已经有了则只是更新信息 try: self._cr.commit() self.trigger_up_event( "funenc_socketio_server_msg", data={ "msg_type": "add_plan", "msg_data": [data], "location": location }, room="xing_hao_lou", callback_name="_send_add_plan_success_callback") except Exception as error: LogManage.put_log( content='推送添加收车计划失败{error}'.format(error=error), mode='train_plan_log') # 添加日志 excute_record = None try: # 这个必需要加,不然回调处理record回出错, # 回调应当是一直在等侍,但回调函数在另一线程 excute_record = self.env[ "metro_park_dispatch.train_in_out_log"].create([{ "type": "out_plan", "train_dev": self.train_id.train.id, "operation": "推送执行收车计划:{start_rail}-{end_rail}到信号楼".format( start_rail=self.real_start_rail.no, end_rail=self.plan_back_rail.no) }]) except Exception as error: _logger.info("log error {error}".format(error=error)) # 执行计划,发送给信号楼 try: # 这个必需要加,不然回调处理record回出错, # 回调应当是一直在等侍,但回调函数在另一线程 self._cr.commit() self.trigger_up_event( "funenc_socketio_server_msg", data={ "msg_type": "excute_plan", "location": location, "msg_data": { "id": self.id, "type": 'train_back', "location": location, "log_id": excute_record.id if excute_record else None } }, room="xing_hao_lou", callback_name="_send_execute_plan_success_callback") except Exception as error: _logger.info("log error {error}".format(error=error)) LogManage.put_log( content='推送执行收车计划失败{error}'.format(error=error), mode='train_plan_log')