From d3a9cf911b25ee20741c5187efb948a684576f2c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Sep 2023 12:34:13 -0400 Subject: [PATCH] thread repair --- .env | 2 +- ad.py | 8 +-- api.py | 178 ++++++++++++++++++++++++++---------------------- config/utils.py | 41 ++++++++--- item.py | 48 ++++++++----- kv/list.kv | 10 +-- list.py | 133 +++++++++++++++++++++++------------- main.py | 39 +++++++---- 8 files changed, 275 insertions(+), 184 deletions(-) diff --git a/.env b/.env index 5bdedce..8fca600 100644 --- a/.env +++ b/.env @@ -3,7 +3,7 @@ hostName = 'https://212.224.86.112:8443' dbPath = './DbFuncs/sql.db' adPath = '/img/ad.mp4' -screenX = 600 +screenX = 1000 screenY = 900 itemLength = 220 diff --git a/ad.py b/ad.py index dcfb4d6..e75019b 100644 --- a/ad.py +++ b/ad.py @@ -38,6 +38,7 @@ def retrieve_layout(self, dt): temp_file = path + os.environ.get('adPath') utils.write_to_file(ad.content, temp_file) + # videoPlayerLayout = VideoPlayerLayout('./img/ad.mp4') videoPlayerLayout = VideoPlayerLayout(temp_file) videoPlayerLayout.manager = self.manager videoPlayerLayout.bind(on_touch_up=videoPlayerLayout.on_video_touch_up) @@ -100,12 +101,8 @@ def __init__(self, temp_file, **kwargs): super(VideoPlayerLayout, self).__init__(**kwargs) self.manager = None self.temp_file = temp_file - # Create a VideoPlayer widget - self.player = Video(source=temp_file, state='play', - options={'eos': 'loop'}) - - # Add the VideoPlayer widget to the BoxLayout + self.player = Video(source=temp_file, state='play', options={'eos':'loop'}) self.add_widget(self.player) def on_video_touch_up(self, video, touch): @@ -113,4 +110,3 @@ def on_video_touch_up(self, video, touch): if video.collide_point(*touch.pos): self.manager.current = 'List' # os.remove(self.temp_file) - diff --git a/api.py b/api.py index d428f91..1161de2 100644 --- a/api.py +++ b/api.py @@ -17,32 +17,21 @@ from dotenv import load_dotenv load_dotenv() from config.global_vars import global_ads, global_machines, global_produts -from config.utils import lockList - +from config.utils import setThreadStatus, getThreadStatus, THREAD_INIT, THREAD_RUNNING, THREAD_STOPPING, THREAD_FINISHED +from config.utils import getDBLock, DBLOCK_ADS, DBLOCK_MACHINE, DBLOCK_PRODUCT +from websockets.exceptions import ConnectionClosed hostName = os.environ.get('hostName') # requestTimeStep = int(os.environ.get('requestTimeStep')) -# def create_connect(): -# ws = create_connection("wss://212.224.86.112:8443") -# print(ws.recv()) -# print("Sending 'Hello, World'...") -# ws.send("Hello, World") -# print("Sent") -# print("Receiving...") -# result = ws.recv() -# print("Received '%s'" % result) -# ws.close() - -# create_connect() - def send_get_ads_info(): url = "/api/machine/get_ads_info" # Send an HTTP GET request to a URL of your choice response = requests.post(hostName + url, verify=False) - if lockList[1]: + if getThreadStatus() == THREAD_STOPPING: return + # Check the response status code if response.status_code == 200: responseData = response.json() # {status : , message : , details : [{},]} @@ -52,7 +41,7 @@ def send_get_ads_info(): db.delete_ads() params = Ad(0, adData['type'], base64.b64decode(adData['content'])) global_ads.append(params) - if lockList[1]: + if getThreadStatus() == THREAD_STOPPING: return db.insert_ads(params) else: @@ -65,7 +54,7 @@ def send_get_machine_info(): url = "/api/machine/get_machine_info" response = requests.post(hostName + url, verify=False) - if lockList[1]: + if getThreadStatus() == THREAD_STOPPING: return # Check the response status code @@ -80,8 +69,8 @@ def send_get_machine_info(): global_machines.append(params) - if lockList[1]: - break + if getThreadStatus() == THREAD_STOPPING: + return db.insert_machine(params) else: print(f"Request failed with status code: {response.status_code}") @@ -91,7 +80,7 @@ def send_get_products_info(): # Send an HTTP GET request to a URL of your choice response = requests.post(hostName + url, verify=False) - if lockList[1]: + if getThreadStatus() == THREAD_STOPPING: return # Check the response status code @@ -104,7 +93,7 @@ def send_get_products_info(): params = Product(0, item['itemno'], item['name'], base64.b64decode(item['thumbnail']), item['nicotine'], item['batterypack'], item['tankvolumn'], item['price'], item['currency'], item['caution'], item['stock']) global_produts.append(params) - if lockList[1]: + if getThreadStatus() == THREAD_STOPPING: break db.insert_product(params) else: @@ -124,86 +113,111 @@ async def connect_to_server(): ssl_context.verify_mode = ssl.CERT_NONE print("wss thread id", threading.get_native_id()) + + setThreadStatus(THREAD_RUNNING) + + cnt = 0 try: - async with websockets.connect('wss://212.224.86.112:8443', ssl = ssl_context) as websocket: - print('connected') + websocket = await websockets.connect('wss://212.224.86.112:8443', ssl = ssl_context) + except: + pass + + while True: + try: + if getThreadStatus() == THREAD_STOPPING: + break + + if cnt % 50 != 0: + time.sleep(0.1) + cnt = (cnt+1) % 50 + print('cnt', cnt) + continue + + cnt = (cnt+1) % 50 + + # async with websockets.connect('wss://212.224.86.112:8443', ssl = ssl_context) as websocket: + + if getThreadStatus() == THREAD_STOPPING: + break + sendData = {'action': 'MachineConnect'} await websocket.send(json.dumps(sendData)) + if getThreadStatus() == THREAD_STOPPING: + break + # Receive data response = await websocket.recv() responseData = json.loads(response) - print(f"Received data: {responseData}") machineConnectStatus = responseData['status'] token = responseData['token'] - cnt = 0 + + if getThreadStatus() == THREAD_STOPPING: + break if machineConnectStatus == 'success': - while True: - if lockList[1]: - break - - if cnt % 50 != 0: - time.sleep(0.1) - cnt = cnt+1 - continue - - cnt = cnt+1 - # print(f'stopConnncet: {stopConnect}') - # if stopConnect: - # print('http_request_close') - # break - - statusData = { - 'action': "MachineSendStatus", - 'payload': { - 'serialno': "123-456-678", - 'temparature': "XXX", - 'token': token, - } + statusData = { + 'action': "MachineSendStatus", + 'payload': { + 'serialno': "123-456-678", + 'temparature': "XXX", + 'token': token, } - await websocket.send(json.dumps(statusData)) - if (lockList[1]): - break - - statusResponse = await websocket.recv() - if lockList[1]: - break - - statusResponseData = json.loads(statusResponse) - print(f'send_websockrt_every10s') - machineGetStatus = statusResponseData['status'] - machineGetType = statusResponseData['type'] - - if lockList[1]: - break - - if machineGetStatus == 1: - lockList[0].acquire() - if 'ads' in machineGetType: + } + await websocket.send(json.dumps(statusData)) + if getThreadStatus() == THREAD_STOPPING: + break + + statusResponse = await websocket.recv() + if getThreadStatus() == THREAD_STOPPING: + break + + statusResponseData = json.loads(statusResponse) + print(f'send_websockrt_every10s') + machineGetStatus = statusResponseData['status'] + machineGetType = statusResponseData['type'] + + if getThreadStatus() == THREAD_STOPPING: + break + + if machineGetStatus == 1: + if 'ads' in machineGetType: + getDBLock(DBLOCK_ADS).acquire() + try: send_get_ads_info() - if 'machine' in machineGetType: + except: + pass + getDBLock(DBLOCK_ADS).release() + if 'machine' in machineGetType: + getDBLock(DBLOCK_MACHINE).acquire() + try: send_get_machine_info() - if 'product' in machineGetType: + except: + pass + getDBLock(DBLOCK_MACHINE).release() + if 'product' in machineGetType: + getDBLock(DBLOCK_PRODUCT).acquire() + try: send_get_products_info() - lockList[0].release() - - else: + except: + pass + getDBLock(DBLOCK_PRODUCT).release() + + except (ConnectionClosed): + try: + websocket = await websockets.connect('wss://212.224.86.112:8443', ssl = ssl_context) + except: pass - - # if stopConnect: - # print('websocket_close') - # await websocket.close() + + try: + websocket.close() except: pass - # global_ads = db.get_ad() - # global_produts = db.get_products() - # global_machines = db.get_machines() - lockList[1] = 2 + + setThreadStatus(THREAD_FINISHED) def close_connect(): - pass -# asyncio.get_event_loop().run_until_complete(connect_to_server()) \ No newline at end of file + pass \ No newline at end of file diff --git a/config/utils.py b/config/utils.py index b653849..373ef3e 100644 --- a/config/utils.py +++ b/config/utils.py @@ -1,9 +1,7 @@ import os +import threading # dbPath = './DbFuncs/sql.db' -# screenX = 600 -# screenY = 900 - # itemLength = 220 @@ -20,11 +18,34 @@ def write_to_file(data, filename): file.write(data) print("Stored blob data into: ", filename, "\n") -lockList = [] -def initLock(lock): - global lockList - lockList.append(lock) -def initThreadLock(lock): - global lockList - lockList.append(lock) +DBLOCK_ADS = 0 +DBLOCK_MACHINE = 1 +DBLOCK_PRODUCT = 2 +dbLockList = [] +def initDBLock(): + global dbLockList + dbLockList.append(threading.Lock()) + dbLockList.append(threading.Lock()) + dbLockList.append(threading.Lock()) + +def getDBLock(db): + return dbLockList[db] + +THREAD_INIT = 0 +THREAD_RUNNING = 1 +THREAD_STOPPING = 2 +THREAD_FINISHED = 3 + +threadStatus = [] +def initThreadLock(): + global threadStatus + threadStatus.append(THREAD_INIT) + +def setThreadStatus(status): + global threadStatus + threadStatus[0] = status + +def getThreadStatus(): + global threadStatus + return threadStatus[0] diff --git a/item.py b/item.py index b68d367..1747f26 100644 --- a/item.py +++ b/item.py @@ -22,7 +22,8 @@ from kivy.graphics import RoundedRectangle, Color, Line import os from dotenv import load_dotenv -from config.utils import lockList +from config.utils import getDBLock, DBLOCK_ADS, DBLOCK_MACHINE, DBLOCK_PRODUCT + load_dotenv() class ItemScreen(Screen): @@ -30,16 +31,22 @@ def __init__(self, **kwargs): super(ItemScreen, self).__init__(**kwargs) self.itemId = None self.timer = None + self.caution = None def set_item_id(self, id): self.itemId = id self.timer = Clock.schedule_interval(self.draw_page, 0.03) def draw_page(self, dt): - if lockList[0].acquire(False) == False: + if getDBLock(DBLOCK_PRODUCT).acquire(False) == False: return - product = db.get_product(self.itemId) - lockList[0].release() + + try: + product = db.get_product(self.itemId) + except: + product = None + + getDBLock(DBLOCK_PRODUCT).release() if product: # display name @@ -47,12 +54,10 @@ def draw_page(self, dt): # display product (image, price, ...) self.draw_product_info(product) - - # inputMoneyLabel = Label(text='Geld einwerfen') - # self.ids.input_money_button.width = inputMoneyLabel.width - # self.ids.input_money_button.text = inputMoneyLabel.text - - self.draw_bigo(product.caution) + + self.caution = product.caution + self.draw_bigo() + # self.draw_bigo_img() self.ids.back_img.bind(on_touch_down = self.on_back_press) @@ -108,11 +113,13 @@ def draw_label(self, value): self.ids.info_layout.add_widget(boxLayout) # display bigo (labels, img on the top-right ) - def draw_bigo(self, cautionText): + def draw_bigo(self): bigoLayout = self.ids.bigo_layout - + bigoLayout.clear_widgets() + bigoLayout.canvas.clear() + for i in range (1): - caution = Label(text=cautionText) + caution = Label(text=self.caution) caution.halign='left' caution.valign = 'middle' caution.color = (.1,.1,.1,.5) @@ -125,13 +132,15 @@ def draw_bigo(self, cautionText): # Create an Image widget img = Image(source='./img/bigo.png') # Calculate the position for the image (top-right corner) - image_x = int(os.environ.get('screenX')) - img.width - 20 - image_y = int(os.environ.get('screenY')) / 3 - img.height / 2 -100 + screenX = Window.width + screenY = Window.height + image_x = screenX - img.width - 20 + image_y = screenY / 3 - img.height / 2 -100 # Draw the image on the canvas with bigoLayout.canvas: + Color(rgba=(1,1,1,1)) Rectangle(pos=(image_x, image_y), size=img.size, texture=img.texture) - def on_back_press(self, instance, touch): if instance.collide_point(*touch.pos): self.manager.current = 'List' @@ -144,6 +153,13 @@ def on_buy_press(self): def on_money_button_press(self): print('money_button_press') + def on_resize(self): + if self.caution: + self.draw_bigo() + + def kill_all_timers(self): + if self.timer != None: + self.timer.cancel() class CountNumber(GridLayout): def __init__(self, **kwargs): diff --git a/kv/list.kv b/kv/list.kv index 5d3ec47..6a5f58c 100644 --- a/kv/list.kv +++ b/kv/list.kv @@ -60,7 +60,7 @@ WindowManager: pos: self.pos[0], self.pos[1] + self.height / 2 size: self.width, self.height / 2 size_hint_y: 0.15 - padding: [root.WIDTH / 6, 0, 0, 0] + padding: [root.WIDTH / 8, 0, root.WIDTH / 8, 0] Image: id: up_image source: './img/up.png' @@ -86,7 +86,7 @@ WindowManager: pos: self.pos size: self.width, self.height / 2 size_hint_y: 0.15 - padding: [root.WIDTH / 6, 0, 0, 0] + padding: [root.WIDTH / 8, 0, root.WIDTH / 8, 0] Image: id: down_image source: './img/down.png' @@ -146,6 +146,7 @@ WindowManager: rectangle: self.x , self.y, self.width-10, self.height-30 GridLayout: + size_hint_x:0.4 rows: 5 spacing: 5 Label: @@ -181,6 +182,7 @@ WindowManager: halign: 'left' text_size: self.width, None GridLayout: + size_hint_x:0.6 rows: 5 spacing: 5 id: info_layout @@ -224,7 +226,7 @@ WindowManager: on_press:root.on_money_button_press() BoxLayout: size_hint_x: 0.4 - padding: [30, 0, 0, 0] + padding: [self.width / 5, 0, self.width / 5, 0] Button: id: round_button canvas.before: @@ -239,8 +241,6 @@ WindowManager: color: (1,1,1,1) font_size: 30 background_color: (1,1,1,0) - size_hint_x: None - size:(200, self.height) on_press: root.on_buy_press() BoxLayout: diff --git a/list.py b/list.py index ab8b17f..b30b168 100644 --- a/list.py +++ b/list.py @@ -26,7 +26,8 @@ from config.global_vars import global_machines, global_produts import os from dotenv import load_dotenv -from config.utils import lockList +from config.utils import getDBLock, DBLOCK_ADS, DBLOCK_MACHINE, DBLOCK_PRODUCT +from kivy.core.window import Window load_dotenv() @@ -37,9 +38,8 @@ def __init__(self, **kwargs): self.timer = Clock.schedule_interval(self.retrieve_image_layout, 0.03) Clock.schedule_once(self.retrieve_up_and_down_image) self.categoryTimer = Clock.schedule_interval(self.retrieve_category_layout, 0.05) - # self.imageList = [] - self.screenX = int(os.environ.get('screenX')) + self.screenX = Window.width self.itemLength = int(os.environ.get('itemLength')) self.productImageHeight = 0 @@ -47,43 +47,55 @@ def __init__(self, **kwargs): self.scroll_move_dis = self.itemLength self.scroll_y_dis = 0 self.scroll_y_offset = 0 + self.machines = [] + self.products = [] # prevent to delay, so we can get image_layou and draw dynamically def retrieve_image_layout(self, dt): - if lockList[0].acquire(False) == False: + if getDBLock(DBLOCK_PRODUCT).acquire(False) == False: return # get all products. - products = db.get_products() - lockList[0].release() + try: + self.products = db.get_products() + except: + self.products = None + + getDBLock(DBLOCK_PRODUCT).release() + + if self.timer != None: + self.timer.cancel() + + self.on_draw_item_images() + def on_draw_item_images(self): image_layout = self.ids.image_layout # Access the image_layout widget + image_layout.clear_widgets() # draw Items - if products: - # get scroll_y step - # self.scroll_y_dis = 1 / (math.ceil(len(products) / 2) - 1) - - for product in products: - image = self.on_draw_item(product) - self.productImageHeight = image.height - container = BoxLayout() - lp = (self.screenX / 2 - self.itemLength - 10) / 2 - container.padding = [lp ,10,lp,10] - container.size_hint_y = None - container.height = image.height + 10 - container.add_widget(image) - image_layout.add_widget(container) - - #stop clock - if self.timer != None: - self.timer.cancel() - - else: - image_layout.add_widget(Label(text='Image not found', color=(0,0,0,1))) + try: + if self.products: + # get scroll_y step + # self.scroll_y_dis = 1 / (math.ceil(len(products) / 2) - 1) + + for product in self.products: + image = self.on_draw_item(product) + self.productImageHeight = image.height + container = BoxLayout() + lp = (Window.width / 2 - self.productImageHeight - 10) / 2 + container.padding = [lp ,10,lp,10] + container.size_hint_y = None + container.height = image.height + 10 + container.add_widget(image) + image_layout.add_widget(container) + + rowCnt = math.ceil(len(self.products) / 2 + 1) + image_layout.height = rowCnt * self.productImageHeight + (rowCnt - 1) * 20 + + else: + image_layout.add_widget(Label(text='Image not found', color=(0,0,0,1))) + except: + pass - rowCnt = math.ceil(len(products) / 2 + 1) - image_layout.height = rowCnt * self.productImageHeight + (rowCnt - 1) * 20 - # draw one image def on_draw_item(self, product): @@ -99,12 +111,12 @@ def on_draw_item(self, product): ################################################################### def retrieve_up_and_down_image(self, dt): up_image = self.ids.up_image - up_image.size_hint_x = None - up_image.width = self.screenX * 2 / 3 + # up_image.size_hint_x = None + # up_image.width = self.screenX * 2 / 3 up_image.bind(on_touch_down = self.on_up_img_click) down_image = self.ids.down_image - down_image.size_hint_x = None - down_image.width = self.screenX * 2 / 3 + # down_image.size_hint_x = None + # down_image.width = self.screenX * 2 / 3 down_image.bind(on_touch_down = self.on_down_img_click) def on_up_img_click(self, instance, touch): @@ -137,25 +149,37 @@ def on_down_img_click(self, instance, touch): ######################################################################## def retrieve_category_layout(self, dt): - if lockList[0].acquire(False) == False: + if getDBLock(DBLOCK_MACHINE).acquire(False) == False: return + try: + self.machines = db.get_machines() + except: + self.machines = [] + + getDBLock(DBLOCK_MACHINE).release() + + if self.categoryTimer != None: + self.categoryTimer.cancel() + + self.on_draw_category_images() + + def on_draw_category_images(self): categoryLayout = self.ids.category_layout # Access the image_layout widget - machines = db.get_machines() - lockList[0].release() - - # machines = global_machines - if machines: - for machine in machines: - image = self.on_draw_category_item(machine) - categoryLayout.add_widget(image) - categoryLayout.width += image.width + categoryLayout.clear_widgets() + categoryLayout.width = 0 + try: + if self.machines: + for machine in self.machines: + image = self.on_draw_category_item(machine) + categoryLayout.add_widget(image) + categoryLayout.width += image.width + + else: + categoryLayout.add_widget(Label(text='Image not found', color=(0,0,0,1))) + except: + pass - #stop clock - if self.categoryTimer != None: - self.categoryTimer.cancel() - else: - categoryLayout.add_widget(Label(text='Image not found', color=(0,0,0,1))) def on_draw_category_item(self, machine): @@ -181,6 +205,17 @@ def on_draw_category_item(self, machine): return boxlayout + def on_resize(self): + self.on_draw_item_images() + self.on_draw_category_images() + + def kill_all_timeser(self): + if self.timer != None: + self.timer.cancel() + + if self.categoryTimer != None: + self.categoryTimer.cancel() + # product image item class ImageItem(Image): def __init__(self, **kwargs): diff --git a/main.py b/main.py index c11010b..e5f24b6 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,8 @@ from kivy.clock import Clock import threading import time -from config.utils import initLock, initThreadLock, lockList +from config.utils import initThreadLock, setThreadStatus, getThreadStatus, THREAD_INIT, THREAD_RUNNING, THREAD_STOPPING, THREAD_FINISHED +from config.utils import initDBLock from kivy.config import Config from kivy.uix.boxlayout import BoxLayout from kivy.uix.label import Label @@ -72,8 +73,8 @@ def build(self): global _thread print("main thread id", threading.get_native_id()) - initLock(threading.Lock()) - initThreadLock(0) + initDBLock() + initThreadLock() #connect db db.openDatabase() @@ -83,12 +84,9 @@ def build(self): width = int(os.environ.get('screenX')) height = int(os.environ.get('screenY')) + Window.size = (width, height) db_create.create_tables() - - Config.set('graphics', 'width', width) - Config.set('graphics', 'height', height) - Config.write() sm.add_widget(adScreen) sm.add_widget(listScreen) @@ -101,22 +99,21 @@ def build(self): itemScreen.bind(on_touch_down=self.touch_screen) Window.bind(on_request_close=self.on_request_close) - + Window.bind(on_resize=self.on_resize) return sm # if user action, ..... def touch_screen(self, instance, touch): global delta - delta = 0 - + delta = 0 def wait_apithread_stop(self, td): global _thread global loop try: _thread.join(0.1) - if lockList[1] == 2: + if getThreadStatus() == THREAD_FINISHED: _thread.join() self.stopEvent.cancel() self.stop() @@ -128,13 +125,16 @@ def count_time(self, dt): global delta delta += 1 print(f'delta:{delta}') - if delta > 10000: - sm.current = 'Ad' + if delta > 10: + listScreen.kill_all_timeser() listScreen.clear_widgets() listScreen.__init__() + + itemScreen.kill_all_timers() itemScreen.clear_widgets() itemScreen.__init__() delta = 0 + sm.current = 'Ad' def on_request_close(self, *args): print('request_close') @@ -142,8 +142,11 @@ def on_request_close(self, *args): return True def wait_threadstop(self, *args): - lockList[1] = 1 - self.stopEvent = Clock.schedule_interval(self.wait_apithread_stop, 0.2) + if getThreadStatus() != THREAD_FINISHED: + setThreadStatus(THREAD_STOPPING) + self.stopEvent = Clock.schedule_interval(self.wait_apithread_stop, 0.2) + else : + self.stop() def textpopup(self, title='', text=''): box = BoxLayout(orientation='vertical') @@ -155,6 +158,12 @@ def textpopup(self, title='', text=''): mybutton.bind(on_release=self.wait_threadstop) popup.open() + def on_resize(self, window, width, heigt): + print('main_resize') + listScreen.on_resize() + itemScreen.on_resize() + + if __name__ == '__main__': MainApp().run() db.closeDatabase() \ No newline at end of file