diff --git a/definitions.py b/definitions.py index d0b5122..de4d1a3 100644 --- a/definitions.py +++ b/definitions.py @@ -1,10 +1,10 @@ import os from dotenv import load_dotenv - +import getpass +username = getpass.getuser() load_dotenv() -LOG_SOURCE = os.getenv("LOG_SOURCE") +LOG_SOURCE = username SMS_TIMEOUT = 120 -BAUDRATE = 115200 ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/logs/LogSender.py b/logs/LogSender.py index a9740a5..efad0cf 100644 --- a/logs/LogSender.py +++ b/logs/LogSender.py @@ -10,9 +10,8 @@ import definitions from logs.AppLogging import init_logger from pojo import ReserveResultPojo from pojo.ReserveResultPojo import PublishType - # Log subjects -from pojo.serial_modem import SerialModem +from pojo.contact_pojo import ContactPojo LOG_SUBJECT_EVENT = "EVENT" LOG_SUBJECT_SMS = "SMS" @@ -102,8 +101,8 @@ class LogSender: msg = "from:{}, sms:{}, ccid:{}".format(phone, sms_text, ccid) self.send_log(msg=msg, subject=LOG_SUBJECT_SMS, type=TYPE_SMS_RECEIVED) - def send_timeout_log(self, serial_modem: SerialModem): - msg = "phone:{}, ccid:{}".format(serial_modem.phone_number, serial_modem.ccid) + def send_timeout_log(self, contact: ContactPojo): + msg = "phone:{}, mail:{}".format(contact.phone, contact.mail) self.send_log(msg, type=LOG_APPOINTMENT_TIMEOUT) def send_contact_not_found(self, msg: str): diff --git a/main.py b/main.py index 098f17c..dc14c4d 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,11 @@ import logging -import random import sys -import time from concurrent.futures import ThreadPoolExecutor -from typing import Union - -from gsmmodem import GsmModem import params -from workers.commandor_page import CommandorPage from logs.AppLogging import init_logger -from params import oracle_log_sender -from pojo.serial_modem import SerialModem from utils.excel_reader import ExcelHelper +from workers.commandor_page import CommandorPage OTP_TIMEOUT = 240 current_gsm_modem = None @@ -23,65 +16,17 @@ logger = logging.getLogger() logger.addHandler(logging.StreamHandler(stream=sys.stdout)) -def send_command(cmd: str, ser, wait_time_in_s: int = 0) -> bytes: - ser.write(cmd.encode()) - msg = ser.read(100) - count = 0 - while 'OK' not in str(msg) and count < wait_time_in_s: - time.sleep(1) - count = count + 1 - msg = ser.read(100) - print(msg) - return msg - - -def create_modem_for_port(port: str) -> Union[SerialModem, None]: - logger.info('Initializing modem... for ' + port) - serial_modem = None - try: - modem = GsmModem(port) - return SerialModem(modem=modem) - except Exception as ext: - logger.error(ext) - return serial_modem - - def start_book(start_number, end_number, store=0): # read the contact, and contact the 2 objects together excel_reader = ExcelHelper() contacts = excel_reader.read_contacts()[start_number - 1: end_number - 1] print(contacts) - # for i in contacts_range: - # logger.info("will switch to contact {}".format(i)) - # with ThreadPoolExecutor(max_workers=10) as executor: - # for modem in modem_list: - # current_sim_position = current_sim_position + 1 - # try: - # modem.get_ccid() - # # find the contact with ccid - # contact = [contact for contact in contacts if - # contact.ccid.replace("F", "") == modem.ccid.replace("F", "")] - # if len(contact) > 0: - # modem.phone_number = contact[0].phone - # modem.contact = contact[0] - # else: - # logger.info("contact not found for this ccid:{}".format(modem.ccid)) - # error_msg = "slot({}):sim({}):ccid({})".format(i, current_sim_position, modem.ccid) - # oracle_log_sender.send_contact_not_found(error_msg) - # modem.modem.close() - # continue - # if modem.contact: - # logger.info("contact found for this ccid") - # signal = modem.modem.signalStrength - # logger.info("信号强度: " + str(signal)) - # proxy = get_proxy(modem.phone_number) - # commandor = CommandorPage(modem, sim_position=current_sim_position, - # slot_position=current_card_pool_slot, store_type=store) - # # start the task in thread - # executor.submit(commandor.start_page, proxy) - # except Exception as error: - # print(error) - # continue + with ThreadPoolExecutor(max_workers=10) as executor: + for contact in contacts: + proxy = get_proxy(contact.phone_number) + commandor = CommandorPage(contact, store_type=store) + # start the task in thread + executor.submit(commandor.start_page, proxy) def get_proxy(phone_number): diff --git a/pojo/ReserveResultPojo.py b/pojo/ReserveResultPojo.py index 3f6fee5..c783f33 100644 --- a/pojo/ReserveResultPojo.py +++ b/pojo/ReserveResultPojo.py @@ -1,5 +1,7 @@ from dataclasses import dataclass from enum import Enum +from typing import Union + from dataclasses_json import dataclass_json @@ -15,9 +17,9 @@ class ReserveResultPojo: phone: str message: str url: str - firstName: None - lastName: None - email: None + firstName: Union[None, str] + lastName: Union[None, str] + email: Union[None, str] id = None accepted = None passport: str = "" diff --git a/pojo/serial_modem.py b/pojo/serial_modem.py deleted file mode 100644 index f639638..0000000 --- a/pojo/serial_modem.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging -from dataclasses import dataclass - -from gsmmodem import GsmModem - - -@dataclass -class SerialModem(): - ccid: str - phone_number = None - modem: GsmModem - contact = None - - def __init__(self, modem: GsmModem, ccid: str = None): - self.modem = modem - self.ccid = ccid - self.logger = logging.getLogger("SerialModem") - - def get_ccid(self): - cmd = "AT+CCID" - self.modem.connect("0000") - self.logger.info("try to get ccid") - response = self.modem.write(cmd, True) - self.ccid = response[0].split(" ")[1].replace("\"", "") - self.logger.info("The SIM card ccid is:" + self.ccid) - # print("try to get phone number") - # cmd_phone_number = "AT+CPBS=ON" - # openBook = self.modem.write(cmd_phone_number, True) - # print("response is :" + str(openBook)) - # cmd_phone_number = "AT+CNUM" - # response2 = self.modem.write(cmd_phone_number, True) - # print("The SIM phone number is:" + str(response2)) diff --git a/requirements.txt b/requirements.txt index 48d7596..db5d9e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ dataclasses_json==0.5.6 firebase_admin==5.2.0 pandas==1.4.1 -playwright==1.20.1 +playwright==1.21.0 pyserial==3.5 pydotenv==0.0.7 dataclasses~=0.6 diff --git a/wait_for_sms.py b/wait_for_sms.py deleted file mode 100644 index e77bba6..0000000 --- a/wait_for_sms.py +++ /dev/null @@ -1,99 +0,0 @@ -import logging -import sys -import time -from concurrent.futures import ThreadPoolExecutor -from typing import Union - -from gsmmodem import GsmModem - -import params -from definitions import SMS_TIMEOUT -from logs.AppLogging import init_logger -from modems.ModemPool import ModemPool -from modems.card_pool import CardPool -from params import MODEM_POOL_PORTS, CARD_POOL_PORT -from pojo.serial_modem import SerialModem -from utils.excel_reader import ExcelHelper -from workers.wait_sms_worker import WaitSmsWorker - -thread_event = None -current_gsm_modem = None -card_pool = CardPool(CARD_POOL_PORT) -init_logger() -logger = logging.getLogger() -logger.addHandler(logging.StreamHandler(stream=sys.stdout)) - - -def get_devices_ports() -> list: - return MODEM_POOL_PORTS - - -def create_modem_for_port(port: str) -> Union[SerialModem, None]: - logger.info('Initializing modem... for ' + port) - serial_modem = None - try: - modem = GsmModem(port) - return SerialModem(modem=modem) - except Exception as ext: - logger.error(ext) - return serial_modem - - -def timeout_occurred(serial_modem: SerialModem): - logger.info("will close timeout modem") - serial_modem.modem.close() - - -def init_modems() -> list: - modems = [] - for port in get_devices_ports(): - serial_modem = create_modem_for_port(port) - if serial_modem: - modems.append(serial_modem) - return modems - - -def start_waiting_sms(start_slot_number, end_slot_sum): - params.oracle_log_sender.send_wait_sms_log() - slot_list = list(range(start_slot_number, end_slot_sum + 1)) - for i in slot_list: - card_pool.reset() - logger.info("will switch to " + str(i)) - card_pool.switch_to_slot(i) - modem_pool = ModemPool(get_devices_ports()) - modem_pool.reset_all_modems() - modem_list = init_modems() - # read the contact, and merge the 2 objects together - excel_reader = ExcelHelper() - contacts = excel_reader.read_contacts() - with ThreadPoolExecutor(max_workers=len(MODEM_POOL_PORTS)) as executor: - for modem in modem_list: - try: - modem.get_ccid() - # find the contact with ccid - contact = [contact for contact in contacts if - contact.ccid.replace("F", "") == modem.ccid.replace("F", "")] - if len(contact) > 0: - modem.phone_number = contact[0].phone - modem.contact = contact[0] - if modem.contact: - logger.info("contact found for this ccid") - commandor = WaitSmsWorker(modem) - # start the task in thread - executor.submit(commandor.run()) - except Exception as error: - print(error) - continue - listen_at = time.time() - now = time.time() - while (listen_at + SMS_TIMEOUT + 5) > now: - now = time.time() - # print("sleep for 2 s") - time.sleep(2) - print("will call continue") - modem_pool.close() - continue - -#等短信 -if __name__ == '__main__': - start_waiting_sms(1, 32) diff --git a/workers/commandor_page.py b/workers/commandor_page.py index d9a8b1e..a36b0a9 100644 --- a/workers/commandor_page.py +++ b/workers/commandor_page.py @@ -1,27 +1,22 @@ -import datetime import logging import random -import re import string import threading import time from typing import Union -from gsmmodem import GsmModem from playwright.sync_api import sync_playwright import params from params import PROXY_SERVER, PROXY_PASSWORD from pojo.ReserveResultPojo import ReserveResultPojo, PublishType from pojo.contact_pojo import ContactPojo -from pojo.serial_modem import SerialModem from utils.excel_reader import ExcelHelper -from utils.operator import Operator, check_operator -RDV_URL = "https://rendezvousparis.hermes.com/client/register" +# RDV_URL = "https://rendezvousparis.hermes.com/client/register" # RDV_URL = "file:///Users/lpan/Downloads/test_appointment.html" -# RDV_URL = "https://api.ipify.org" +RDV_URL = "https://api.ipify.org" # RDV_URL ="https://bot.sannysoft.com/" otp_value = None user_agent_list = ExcelHelper().read_user_agent_list() @@ -47,75 +42,24 @@ class Tls(threading.local): class CommandorPage: tls = Tls() - def __init__(self, serial_modem: SerialModem, slot_position, sim_position, store_type=0): + def __init__(self, contact: ContactPojo, store_type=0): self.otp_value = None self.logger = logging.getLogger("CommandorPage") self.is_finished = False - self.current_gsm_modem = serial_modem - self.slot_position = slot_position - self.sim_position = sim_position - self.contact = serial_modem.contact + self.contact = contact self.store_type = store_type def on_success(self, result: ReserveResultPojo): self.logger.info("on_success called.") self.logger.info(result) params.oracle_log_sender.send_appoint_result(result) - self.current_gsm_modem.modem.close() self.is_finished = True - def handle_sms(self, sms): - self.logger.info( - u'== SMS message received ==\nFrom: {0}\nTime: {1}\nMessage:\n{2}\n'.format(sms.number, sms.time, sms.text)) - # extract the otp number - date = str(sms.time)[0:10] - params.oracle_log_sender.send_sms_reception_log(sms.number, sms.text, self.current_gsm_modem.ccid) - if date == str(datetime.date.today()): - self.logger.info("this sms is for today") - if "rendez-vous" in sms.text or "appointment" in sms.text: - self.logger.info("try to extract the otp") - pattern = r'\d{6,8}' - # if re.match(pattern, sms.text): - match = re.search(pattern, sms.text) - otp = match.group(0) - self.logger.info("otp is " + otp) - self.otp_value = otp - self.logger.info("will set thread event") - self.thread_event.set() - self.is_finished = True - else: - self.logger.info("The sms is not for RDV") - else: - self.logger.info("The sms is not for today") - - def set_up_sms_listener(self): - if check_operator(self.current_gsm_modem.ccid) == Operator.LYCAMOBILE: - # lycamobile - self.current_gsm_modem.modem.deleteMultipleStoredSms(memory="SM") - self.current_gsm_modem.modem.smsReceivedCallback = self.handle_sms - self.is_finished = False - self.current_gsm_modem.smsTextMode = False - self.logger.info('Waiting for SMS message, for phone number ' + str(self.current_gsm_modem.phone_number)) - listen_at = time.time() - while not self.is_finished: - time.sleep(2) - # check whether timeout - now = time.time() - if (listen_at + OTP_TIMEOUT) < now: - self.logger.info("time out for {}, switch to next contact".format(self.current_gsm_modem.phone_number)) - # save the contact in timeout - self.timeout_occurred() - self.current_gsm_modem.modem.close() - return - return - def timeout_occurred(self): - params.firebase_store_manager.save_timeout_contact(self.current_gsm_modem.contact) - params.oracle_log_sender.send_timeout_log(self.current_gsm_modem) + params.oracle_log_sender.send_timeout_log(self.contact) self.logger.info("will close timeout modem") self.thread_event.set() - self.current_gsm_modem.modem.close() - self.reset_air_plan_mode() + self.termine() def _run(self, e: threading.Event, proxy): print("will start browser") @@ -143,7 +87,6 @@ class CommandorPage: # wait for sms_code field # self.clickOnValidBtn() self.thread_event = e - self.set_up_sms_listener() otp_input = self.page.locator(OTP_FIELD_ID) otp_input.wait_for(state='visible', timeout=TIME_OUT) event_is_set = e.wait() @@ -163,7 +106,7 @@ class CommandorPage: self.publish_message_to_queue(self.contact, PublishType.SUCCESS, self.page.url) else: self.logger.info("timeout") - self.reset_air_plan_mode() + self.termine() def start_browser(self, proxy, pwright, device) -> Union[str, None]: try: @@ -300,7 +243,7 @@ class CommandorPage: time.sleep(get_random_wait_time()) self.page.fill(OTP_FIELD_ID, otp) - def reset_air_plan_mode(self): + def termine(self): self.logger.info("will close browser") self.browser.close() @@ -311,8 +254,6 @@ class CommandorPage: firstName=contact.first_name, lastName=contact.last_name, email=contact.mail, passport=contact.passport, ccid=contact.ccid) result.id = id - result.sim_position = self.sim_position - result.slot_position = self.slot_position params.firebase_store_manager.save(result) if status is PublishType.SUCCESS: self.on_success(result) @@ -353,12 +294,8 @@ def launch_page(): contact = ContactPojo(phone_number="+33758912245", passport_number=passport_number, last_name="XU", first_name="xingzhen", mail="ColbyPatel653@gmail.com", ccid="", position=0) - modem = GsmModem("/dev/tty.usbmodem1422307") - serial_modem = SerialModem(modem) - serial_modem.contact = contact - serial_modem.phone_number = contact.phone - page = CommandorPage(serial_modem, slot_position=1, sim_position=1, store_type=1) - return page.start_page(proxy) + page = CommandorPage(contact, store_type=1) + return page.start_page(None) def wait_for_otp(event: threading.Event, commandor: CommandorPage): diff --git a/workers/wait_sms_worker.py b/workers/wait_sms_worker.py deleted file mode 100644 index d0b770d..0000000 --- a/workers/wait_sms_worker.py +++ /dev/null @@ -1,87 +0,0 @@ -import datetime -import logging -import threading -import time -from typing import Union - -from gsmmodem.modem import Sms - -import params -from definitions import SMS_TIMEOUT -from notification.AcceptedResultPojo import get_accepted_result_from -from notification.mailer import Mailer -from pojo.SimInfoPojo import SimInfoPojo -from pojo.serial_modem import SerialModem -from utils.excel_reader import ExcelHelper - - -class WaitSmsWorker: - HERMES_RDV = "HERMES RDV" - ACCEPT_SENTENCE = "We are pleased to confirm your appointment" - - def __init__(self, serial_modem: SerialModem): - self.serial_modem = serial_modem - self.logger = logging.getLogger("WaitSmsWorker") - - def handle_sms(self, sms): - self.logger.info( - "sms received for phone:{}(ccid:{})".format(self.serial_modem.phone_number, self.serial_modem.ccid)) - self.logger.info( - u'== SMS message received ==\nFrom: {0}\nTime: {1}\nMessage:\n{2}\n'.format(sms.number, sms.time, sms.text)) - params.oracle_log_sender.send_sms_reception_log(sms.number, sms.text, self.serial_modem.ccid) - if self.serial_modem.phone_number: - self.check_sms(sms, int(self.serial_modem.phone_number)) - - def run(self): - t = threading.Thread(target=self.start_wait) - t.start() - - def start_wait(self): - try: - self.serial_modem.modem.deleteMultipleStoredSms(memory="SM") - except Exception as error: - print(error) - - self.serial_modem.modem.smsReceivedCallback = self.handle_sms - self.serial_modem.modem.smsTextMode = False - self.logger.info('Waiting for SMS message, for phone number ' + str(self.serial_modem.phone_number)) - listen_at = time.time() - while True: - # self.logger.info("sleep for 2s in thread({})".format(threading.currentThread().name)) - time.sleep(5) - # check whether timeout - now = time.time() - if (listen_at + SMS_TIMEOUT) < now: - self.logger.info("time out for {}, switch to next contact".format(self.serial_modem.phone_number)) - # save the contact in timeout - self.serial_modem.modem.close() - return - - @staticmethod - def find_info_via_ccid(ccid) -> Union[None, SimInfoPojo]: - sim_list = ExcelHelper().read_sim_info() - found_sim_list = [contact for contact in sim_list if - contact.ccid.replace("F", "") == ccid.replace("F", "")] - if len(found_sim_list) > 0: - print(found_sim_list[0].to_firestore_dict()) - return found_sim_list[0] - else: - return None - - def check_sms(self, sms: Sms, phone: int): - self.logger.info("核查 sms") - if sms.number == self.HERMES_RDV: - if self.ACCEPT_SENTENCE in sms.text: - self.logger.info("收到来自hermes的短信,准备发送邮件") - mailer = Mailer() - result_pojo = params.firebase_store_manager.find_appointment_detail_via_phone( - str(datetime.date.today()), phone) - accepted_result = get_accepted_result_from(sms, result_pojo) - mailer.send_email(accepted_result) - - -if __name__ == '__main__': - worker = WaitSmsWorker(None) - sms = Sms("HERMES RDV", - "We are pleased to confirm your appointment. You will be welcomed on Apr 14, 2022 in our store at 17 rue de Sèvres at 4:45 PM. The given hour may be subje") - worker.check_sms(sms, int('628973387'))