diff --git a/appstore/sbomp_test_ip/README.md b/appstore/sbomp_test_ip/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..ff2b84188a72e94caac4b839c9cf83cb1ee0fc39
--- /dev/null
+++ b/appstore/sbomp_test_ip/README.md
@@ -0,0 +1,10 @@
+一个测试IP是否能用的模块
+
+应用场景
+ 1、需要对接的终端设备很多、且终端设备IP大部分不相同的场景
+ 2、对sql_lite使用的一种演示
+ 3、DTCLOUD 如何调用另外一个模块的函数
+
+使用方法
+ self.env['sbomp.test.ip'].test_net_is_used(in_ip='127.0.0.1', in_port=503, connect_mode='socket')
+ self.env['sbomp.test.ip'].error_connect_ip(in_ip='127.0.0.1', in_port=503, connect_mode='socket',connect_error_info='未知错误')
\ No newline at end of file
diff --git a/appstore/sbomp_test_ip/__init__.py b/appstore/sbomp_test_ip/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0650744f6bc69b9f0b865e8c7174c813a5f5995e
--- /dev/null
+++ b/appstore/sbomp_test_ip/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/appstore/sbomp_test_ip/__manifest__.py b/appstore/sbomp_test_ip/__manifest__.py
new file mode 100644
index 0000000000000000000000000000000000000000..647da2d1e4f27a009c5363be3906e583d184e770
--- /dev/null
+++ b/appstore/sbomp_test_ip/__manifest__.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+# DTCloud360
+# QQ:35350428
+# 邮件:35350428@qq.com
+# 手机:13584935775
+# 作者:'扶程星云'
+# 公司网址: http://www.dtcloud360.com/
+# Copyright 中亿丰信息科技(苏州)有限公司
+# 日期:2021/10/15
+# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+
+{
+ 'name': '测试IP地址',
+ 'summary': """
+ sbomp_test_ip
+ """,
+ 'category': 'Tools',
+ 'sequence': 3,
+ 'author': '扶程星云',
+ 'website': "http://www.dtcloud360.com/",
+ 'depends': ['base'],
+ 'version': '0.1',
+ 'data': [
+ # 'data/sbomp_test_ip_reset.xml',
+ ],
+ 'installable': True,
+ 'application': True,
+ 'auto_install': True,
+ 'description': """
+ 有时候,我们需要测试IP是否可用,然后再进行操作,特别是大量重复IP,
+ 我们在一定时间内是不需要重复检查一个IP是否可用的,如果一定时间内是不通的,
+ 我们会直接返回不通,直到再次测试时间到达。
+""",
+
+}
diff --git a/appstore/sbomp_test_ip/data/sbomp_test_ip_reset.xml b/appstore/sbomp_test_ip/data/sbomp_test_ip_reset.xml
new file mode 100644
index 0000000000000000000000000000000000000000..49d5fcbbd13332e6b9d6166397485f13c23e6a68
--- /dev/null
+++ b/appstore/sbomp_test_ip/data/sbomp_test_ip_reset.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/appstore/sbomp_test_ip/models/__init__.py b/appstore/sbomp_test_ip/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..47f9415719e6647facc4faa733fbda8443bcdc44
--- /dev/null
+++ b/appstore/sbomp_test_ip/models/__init__.py
@@ -0,0 +1,2 @@
+from . import sbomp_test_ip
+
diff --git a/appstore/sbomp_test_ip/models/sbomp_test_ip.py b/appstore/sbomp_test_ip/models/sbomp_test_ip.py
new file mode 100644
index 0000000000000000000000000000000000000000..fae24a37f523306a6b80867a4e5da1075e05d3ac
--- /dev/null
+++ b/appstore/sbomp_test_ip/models/sbomp_test_ip.py
@@ -0,0 +1,246 @@
+# -*- coding: utf-8 -*-
+from datetime import timedelta
+
+from dtcloud import models, fields, api
+
+from dtcloud.tools.sql_lite_tools import nebula_delete_sql_lite, nebula_create_sql_lite
+
+
+
+def net_is_used(in_ip='127.0.0.1', in_port=503):
+ ip = in_ip
+ table_name = 'sbomp_test_ip'
+ db_name = 'sbomp.db'
+ connect_datetime = get_location_time()
+ reconnect_datetime = get_location_time(add_minutes=10)
+ # 如果传进来的是 '192.168.3.3:503'
+ ip_port_list = in_ip.split(':')
+ if len(ip_port_list) == 2:
+ # print(f'ip_port_list:{ip_port_list} in_ip:{in_ip}')
+ ip_tmp = ip_port_list[0]
+ ip = ip_tmp.replace('\'', '')
+ port_tmp = ip_port_list[1]
+ port = port_tmp.replace('\'', '')
+ # print(f'ip_port_list ip_port_list :{ip_port_list} in_ip:{in_ip}, ip:{ip},port:{port}')
+ port = int(port)
+ else: # 如果传进来的端口是字符
+ if type(in_port) == str:
+ port = int(in_port)
+ else:
+ port = in_port
+
+ # 测试本地IP是否正常
+ # 先查看有没有这条记录
+ ip_address = str(ip)
+ str_port = str(port)
+
+ where_values = 'ip_address=? and port=?'
+ in_parameters = (ip_address, str_port)
+ check_table_sbomp_test_ip()
+ select_sql = get_select_sql_base(table_name=table_name, select_values='id,connect_state,reconnect_datetime',
+ where_values=where_values)
+ re_state, db_list = nebula_select_sql_lite(select_sql, db_name=db_name, in_parameters=in_parameters)
+ if re_state: # 有返回值,正常
+ for db_one in db_list: # 如果是断开状态,而且日期是小于重新检查时间,则直接返回False
+ s_none_format = "%Y-%m-%d %H:%M:%S"
+ db_one_connect_state = bool(db_one[1])
+ db_one_reconnect_datetime_str = db_one[
+ 2] # 2021-03-17 03:10:42.817235+08:00' does not match format '%Y-%m-%d %H:%M:%S.%f%z'
+
+ s_tz = db_one_reconnect_datetime_str.split('+')[1]
+ s_format = s_none_format + '.%f+' + s_tz
+ db_one_reconnect_datetime = datetime.strptime(db_one_reconnect_datetime_str, s_format)
+
+ # db_one_reconnect_datetime = datetime.strptime(db_one_reconnect_datetime_str,
+ # "%Y-%m-%d %H:%M:%S.%f%z") # "%Y-%m-%d %H:%M:%S.%f%z Y-%m-%dT%H:%M:%S.%f
+
+ # print(f'db_one_reconnect_datetime:')
+
+ db_one_reconnect_datetime = datetime.strptime(db_one_reconnect_datetime.strftime(s_none_format),
+ s_none_format)
+
+ connect_datetime = datetime.strptime(connect_datetime.strftime(s_none_format), s_none_format)
+
+ if (not db_one_connect_state) and (connect_datetime <= db_one_reconnect_datetime):
+ d_temp = db_one_reconnect_datetime - connect_datetime
+ print(f'net_is_used 离下次检查时间还有{d_temp}')
+ return False
+
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ s.connect((ip, port))
+ s.shutdown(1)
+ print('net_is_used %s:%d is used' % (ip, port))
+ return True
+ except Exception as e:
+ print(f'net_is_used 目标地址:{ip},目标端口:{port}出错,出错信息:{e}')
+ connect_state = False
+ if re_state:
+ if len(db_list): # 如果有返回值,更新数据
+ set_values = 'connect_datetime=?,reconnect_datetime=?,connect_state=?'
+ update_sql = get_update_sql_base(table_name=table_name, set_values=set_values,
+ where_values=where_values)
+ in_parameters = (connect_datetime, reconnect_datetime, connect_state, ip_address, str_port)
+ re_state, re_info = nebula_update_sql_lite(update_sql, db_name=db_name, in_parameters=in_parameters)
+ else: # 是新记录,需要插入
+ set_parameters = 'ip_address,port,connect_datetime,reconnect_datetime,connect_state'
+ insert_sql = get_insert_sql_base(table_name=table_name, set_parameters=set_parameters)
+ in_parameters = (ip_address, str_port, connect_datetime, reconnect_datetime, connect_state)
+ re_state, re_info = nebula_update_sql_lite(update_sql=insert_sql, db_name=db_name,
+ in_parameters=in_parameters)
+ print(f'net_is_used re_state:{re_state}, db_list:{db_list}')
+ return False
+
+class sbomp_test_ip(models.Model):
+ _name = 'sbomp.test.ip'
+ _description = '测试IP地址'
+ _order = 'id desc'
+
+ name = fields.Char(string='IP地址信息', copy=False, index=True, default=lambda self: u'New')
+ ip_address = fields.Char(string='IP地址', copy=False, index=True)
+ port = fields.Char(string='端口号', copy=False)
+ slave_number = fields.Char(string='从站地址', copy=False)
+ connect_datetime = fields.Datetime(string='本次测试时间', copy=False, default=lambda self: fields.Datetime.today())
+ reconnect_datetime = fields.Datetime(string='重新测试时间', copy=False, default=lambda self: fields.Datetime.today())
+ connect_state = fields.Boolean(string='联通状态', default=True)
+ connect_error_info = fields.Char(string='出错信息')
+ connect_mode = fields.Selection([
+ ('socket', 'socket'),
+ ('ping', 'ping'),
+ ], '连接模式状态', copy=False, default='socket')
+
+ @api.model
+ def delete_sql_lite_api(self): # 删除内存表
+ print(f'delete_sql_lite_api -- begin--')
+ re, info = nebula_delete_sql_lite(db_name='sbomp.db', table_name='sbomp_test_ip_slave')
+ if re:
+ print(f'删除sbomp_test_ip_slave成功')
+ else:
+ print(f'删除sbomp_test_ip_slave失败{info}')
+
+ re, info = nebula_delete_sql_lite(db_name='sbomp.db', table_name='sbomp_test_ip')
+ if re:
+ print(f'删除sbomp_test_ip成功')
+ else:
+ print(f'删除sbomp_test_ip失败{info}')
+ print(f'delete_sql_lite_api -- end--')
+
+ def delete_sql_lite(self): # 删除内存表
+ print(f'delete_sql_lite -- begin--')
+ re, info = nebula_delete_sql_lite(db_name='sbomp.db', table_name='sbomp_test_ip_slave')
+ if re:
+ self.env.user.notify_success(message='删除sbomp_test_ip_slave成功')
+ else:
+ self.env.user.notify_warning(message=info)
+
+ re, info = nebula_delete_sql_lite(db_name='sbomp.db', table_name='sbomp_test_ip')
+ if re:
+ self.env.user.notify_success(message='删除sbomp_test_ip成功')
+ else:
+ self.env.user.notify_warning(message=info)
+ print(f'delete_sql_lite ok')
+
+
+ def create_sql_lite(self): # 创建内存数据表
+ print(f'create_sql_lite -- begin--')
+ sql_text = '''CREATE TABLE IF NOT EXISTS sbomp_test_ip_slave
+ (
+ id integer primary key autoincrement not null,
+ name varchar ,
+ ip_address varchar ,
+ port varchar,
+ slave_number varchar,
+ connect_datetime DATETIME NOT NULL,
+ reconnect_datetime DATETIME NOT NULL,
+ connect_state BOOLEAN NOT NULL,
+ connect_error_info TEXT,
+ connect_mode TEXT);'''
+
+ re, info = nebula_create_sql_lite(db_name='sbomp.db', create_sql=sql_text)
+ if re:
+ self.env.user.notify_success(message='建表成功')
+ else:
+ self.env.user.notify_warning(message=info)
+ print(f'create_sql_lite -- end--')
+
+ def net_db_used(self):
+ self.test_net_is_used(self.ip_address, self.port, self.connect_mode)
+
+ def error_connect_ip(self, in_ip='127.0.0.1', in_port=503, slave_number='-1', connect_mode='socket',
+ connect_error_info='未知错误'): # 如果连接其他异常也设置为不可用 172.16.79.11
+ now_datetime = fields.datetime.now()
+ domain = [('ip_address', '=', in_ip), ('port', '=', in_port), ('connect_mode', '=', connect_mode),
+ ('slave_number', '=', slave_number)]
+
+ reconnect_datetime = now_datetime + timedelta(minutes=10)
+ values = {
+ 'connect_state': False,
+ 'connect_datetime': now_datetime,
+ 'connect_error_info': connect_error_info,
+ 'reconnect_datetime': reconnect_datetime,
+ }
+ db_list = self.env['sbomp.test.ip'].sudo().search(domain)
+ if db_list:
+ db_list.sudo().write(values)
+ else: # 新建
+ my_name = 'ip:' + in_ip + ', port:' + str(in_port)
+ values['name'] = my_name
+ values['ip_address'] = in_ip
+ values['port'] = in_port
+ values['connect_mode'] = connect_mode
+ self.env['sbomp.test.ip'].sudo().create(values)
+ print(
+ f'error_connect_ip in_ip:{in_ip}, port:{in_port}, slave_number:{slave_number},connect_error_info:{connect_error_info}')
+
+ def test_net_is_used(self, in_ip='null', in_port=503, slave_number='-1', connect_mode='socket'):
+ print(f'test_net_is_used -- in_ip:{in_ip}:{in_port}--')
+ if in_ip == 'null':
+ return False
+ ip = in_ip
+ now_datetime = fields.datetime.now()
+ # 如果传进来的是 '192.168.3.3:503'
+ ip_port_list = in_ip.split(':')
+ if len(ip_port_list) == 2:
+ ip_tmp = ip_port_list[0]
+ ip = ip_tmp.replace('\'', '')
+ port_tmp = ip_port_list[1]
+ port = port_tmp.replace('\'', '')
+ port = int(port)
+ else: # 如果传进来的端口是字符
+ if type(in_port) == str:
+ port = int(in_port)
+ else:
+ port = in_port
+
+ # 流程: 1. 传入ip、端口号、连接方式
+ # 2. 检查这些参数在数据库中是不是存在,如果是 在小于重新检查时间,且上次检查是不通的,直接返回false,以避免时间浪费,后期可以用内存表的方式来遍历
+ # 3. 如果不存在,或者已经到了重新检查的时间,就检查.
+ # 4.如果存在,还没有过重新检查时间,直接返回false..........
+ # 5.检查结果,返回检查结果。
+ # 6.利用finally功能,返回结果后将检查结果保存到数据中。 没有从地址,从地址=-1
+ if net_is_used(in_ip=ip, in_port=port):
+ domain = [('ip_address', '=', ip), ('port', '=', port), ('connect_mode', '=', connect_mode),
+ ('slave_number', '=', slave_number),
+ ('reconnect_datetime', '>', now_datetime),
+ ('connect_state', '=', False)] # 小于重新检查时间,且上次检查是不通的,直接返回false
+ try:
+ if self.env['sbomp.test.ip'].sudo().search(domain, limit=1).id:
+ print(f'小于重新检查时间,且上次检查是不通的,直接返回false')
+ return False
+ except Exception as e:
+ print(f'目标地址:{ip},目标端口:{port},从站地址:{slave_number}出错,出错信息:{e}')
+ # 重新检查是否可用
+ # if connect_mode == 'socket':
+ # return net_is_used(in_ip=ip, in_port=port)
+ # else:
+ # return True
+
+ return True
+ else:
+ return False
+
+# 使用方法
+# odoo 如何调用另外一个模块的函数
+# self.env['model.name'].function_name()
+# self.env['sbomp.test.ip'].test_net_is_used(in_ip='127.0.0.1', in_port=503, connect_mode='socket')
+# self.env['sbomp.test.ip'].error_connect_ip(in_ip='127.0.0.1', in_port=503, connect_mode='socket',connect_error_info='未知错误')
diff --git a/appstore/sbomp_test_ip/security/ir.model.access.csv b/appstore/sbomp_test_ip/security/ir.model.access.csv
new file mode 100644
index 0000000000000000000000000000000000000000..bdd764dedf0b80e160ca00b1d81ba3ee6417504f
--- /dev/null
+++ b/appstore/sbomp_test_ip/security/ir.model.access.csv
@@ -0,0 +1,5 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+access_sbomp_test_ip_admin,sbomp_test_ip,model_sbomp_test_ip,base.group_system,1,1,1,1
+access_sbomp_test_ip_user,sbomp_test_ip,model_sbomp_test_ip,base.group_user,1,0,0,1
+
+
diff --git a/appstore/sbomp_test_ip/static/description/icon.png b/appstore/sbomp_test_ip/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..633a8639c2faa4b2b58e114ab7ccc3545796f5f8
Binary files /dev/null and b/appstore/sbomp_test_ip/static/description/icon.png differ
diff --git a/appstore/sbomp_test_ip/views/sbomp_test_ip_views.xml b/appstore/sbomp_test_ip/views/sbomp_test_ip_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bf7931f8bd7e1e837edfb0a78a68e76a052eec48
--- /dev/null
+++ b/appstore/sbomp_test_ip/views/sbomp_test_ip_views.xml
@@ -0,0 +1,65 @@
+
+
+
+
+ sbomp.test.ip.form
+ sbomp.test.ip
+
+
+
+
+
+
+
+ sbomp.test.ip.tree
+ sbomp.test.ip
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IP测试
+ sbomp.test.ip
+ tree,form
+
+
+
+
+
\ No newline at end of file
diff --git a/dtcloud/tools/sql_lite_tools.py b/dtcloud/tools/sql_lite_tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..c487bf5c9d3fe051cd4032cabaf6744f16c264a3
--- /dev/null
+++ b/dtcloud/tools/sql_lite_tools.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+# DTCloud360
+# QQ:35350428
+# 邮件:35350428@qq.com
+# 手机:13584935775
+# 作者:'扶程星云'
+# 公司网址: http://www.dtcloud360.com/
+# Copyright 中亿丰信息科技(苏州)有限公司
+# 日期:2021/10/15
+# 功能: 针对 sqlite3的操作
+# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
+
+
+import sqlite3
+
+
+def nebula_delete_sql_lite(db_name='sbomp.db', table_name='sbomp_test_ip'): # 删除内存表
+ # 创建与数据库的连接
+
+ conn = sqlite3.connect(db_name)
+ # 删除表
+ drop_sql = "drop table IF EXISTS " + table_name
+ try:
+ conn.execute(drop_sql)
+ return True, 'ok'
+ except Exception as e:
+ return False, e
+ finally:
+ conn.close()
+
+
+def nebula_create_sql_lite(create_sql, db_name='sbomp.db'): # 创建内存表
+ conn = sqlite3.connect(db_name)
+ # 创建一个游标 cursor
+ cur = conn.cursor()
+ # 建表的sql语句
+ sql_text = create_sql
+ # 执行sql语句
+ try:
+ cur.execute(sql_text)
+ return True, 'ok'
+ except Exception as e:
+ return False, e
+ finally:
+ # 关闭游标
+ cur.close()
+ # 关闭连接
+ conn.close()
+
+
+def nebula_select_sql_lite(select_sql, in_parameters, db_name='sbomp.db'): # 查询记录
+ conn = sqlite3.connect(db_name)
+ # 创建一个游标 cursor
+ cur = conn.cursor()
+ # 建表的sql语句
+ sql_text = select_sql
+ # 执行sql语句
+ try:
+ cur.execute(sql_text, in_parameters)
+ db_list = cur.fetchall()
+ return True, db_list
+ except Exception as e:
+ return False, e
+ finally:
+ # 关闭游标
+ cur.close()
+ # 关闭连接
+ conn.close()
+
+
+def nebula_update_sql_lite(update_sql, in_parameters, db_name='sbomp.db'): # 更新记录
+ conn = sqlite3.connect(db_name)
+ # 创建一个游标 cursor
+ cur = conn.cursor()
+ # 更新表的sql语句
+ sql_text = update_sql
+ # 执行sql语句
+ try:
+ cur.execute(sql_text, in_parameters)
+ conn.commit()
+ print(f'nebula_update_sql_lite ok')
+ return True, 'ok'
+ except Exception as e:
+ conn.rollback()
+ print(e)
+ return False, e
+ finally:
+ # 关闭游标
+ cur.close()
+ # 关闭连接
+ conn.close()
+