class MatchView(View): @staticmethod @Analyse.r(q=[ P('phrase').process(Processor(phrase_processor, yield_name='phonetics')), P('phrase_len').default(0).process(int), P('min_max_match').default(0).process(int), P('cluster').process(lambda x: x.upper()), P('cluster_type').process(cluster_type_processor), ]) def get(r): return worker.match(**r.d.dict())
class ArticleView(View): @staticmethod @Analyse.r(q=[P('role', '角色').default('owner')]) @Auth.require_login def get(r): user = r.user # type: MiniUser if r.d.role == 'owner': return user.article_set.order_by('-pk').all().dict(Article.d_base) else: return list( map(lambda aid: Article.get(aid).d_base(), user.get_commented_articles())) @staticmethod @Analyse.r([ ArticleP.title, ArticleP.origin, ArticleP.author, ArticleP.self_product, ArticleP.require_review, ArticleP.allow_open_reply, ]) @Auth.require_login def post(r): Weixin.msg_sec_check(r.d.title) Weixin.msg_sec_check(r.d.origin) Weixin.msg_sec_check(r.d.author) return Article.create(r.user, **r.d.dict()).d_create()
class TicketView(View): """/space/:space_id/ticket""" PTicket = P('ticket', yield_name='spaceman').process(Auth.analyse_invite_ticket) @staticmethod @Analyse.r(a=[SpaceP.space_getter]) @Auth.require_space_member def get(r): """生成邀请""" return Auth.get_invite_ticket(r.spaceman) @staticmethod @Analyse.r(b=[PTicket]) @Auth.require_login def post(r): """获取邀请信息""" return r.d.spaceman.d_invite() @staticmethod @Analyse.r(b=[PTicket]) @Auth.require_login def put(r): """进入星球""" space = r.d.spaceman.space space.not_member_checker(r.user) space.add_member(r.user) return 0
class PinyinService(Service): name = 'pinyin' desc = '汉字转拼音' long_desc = Lines("👉pinyin 林俊杰", "✅lín jùn jié", "当输入单个汉字且是多音字时,默认返回该字的所有拼音", "👉pinyin 给", "✅gěi/jǐ", "可以使用-s或--single来获得单个拼音", "👉pinyin -s 给", "✅gěi") PSingle = Parameter(P(read_name='多音字返回一个拼音').default(), long='single', short='s') @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): if not args: return cls.need_help() text = args[0] heteronym_when_single = not pd.has(cls.PSingle) resp = Tools.get(Tools.Pinyin, { 'text': text, 'heteronym_when_single': heteronym_when_single }) resp = list(filter(lambda x: x, resp)) return ' /'[len(text) == 1].join(resp) @classmethod def init(cls): cls.validate(cls.PSingle)
class SpaceP: space_id, name, rename_card, access = Space.P('space_id', 'name', 'rename_card', 'access') space_getter = space_id.clone().rename('space_id', yield_name='space', stay_origin=True).process(Space.get) spaceman_getter = P('space_user', yield_name='spaceman').process(SpaceMan.get_by_union)
class AxiosValidateView(View): @staticmethod @Analyse.r(b=[ P('geetest_challenge', 'challenge'), P('geetest_seccode', 'seccode'), P('geetest_validate', '验证码') ]) def post(request): gt = GeetestLib(geetest_id, geetest_key) challenge = request.d.geetest_challenge validate = request.d.geetest_validate seccode = request.d.geetest_seccode status = request.session[gt.GT_STATUS_SESSION_KEY] user_id = request.session["user_id"] if status: result = gt.success_validate(challenge, validate, seccode, user_id) else: result = gt.failback_validate(challenge, validate, seccode) result = {"status": "success"} if result else {"status": "fail"} return HttpResponse(json.dumps(result))
class TalkContentView(View): @staticmethod @Analyse.r(a=[ P('tid', 'talkid', 'talk').process(int).process(Talk.get_talk_by_pk) ], b=[ P('last', '最后一条commit的时间').default( 0, through_processors=True).process(last_timer), P('count', '每页数目').default(5).process(int) ]) @Auth.require_login def post(request): """POST /api/talk/@<int:tid> 获取此talk的内容及commit """ return dict( talk=request.d.talk.d(), commits=Commit.get_commit(**request.d.dict()), )
class ImageTokenView(View): @staticmethod @Analyse.r(a=[AlbumP.id_getter], q=[P('image_num', '图片数量').process(boundary(max_=99, min_=1))]) @Auth.require_album_member def get(r): album = r.d.album # type: Album image_num = r.d.image_num return Image.get_tokens(action=ImageUploadAction.ALBUM, num=image_num, album_id=album.res_id)
class UserView(View): @staticmethod @Auth.require_login def get(request): """ GET /api/user/ 获取我的信息 """ user = request.user # print(user.username) return UsernameView.get_info(user.username) @staticmethod @Analyse.r(b=[UserP.username, UserP.password, UserP.invite_code]) def post(request): """ POST /api/user/ 创建用户 """ print(1111) invite_code = request.d.invite_code if invite_code is not None: # print(invite_code) user = User.create_invite(**request.d.dict()) else: user = User.create(**request.d.dict('username', 'password')) return Auth.get_login_token(user) @staticmethod @Analyse.r( b={ UserP.password.clone().default(None), UserP.password.clone().rename('old_password').default(None), P('nickname', '昵称').default(None) # 教学示范 }) @Auth.require_login def put(request): """ PUT /api/user/ 修改用户信息 """ user = request.user password = request.d.password nickname = request.d.nickname old_password = request.d.old_password if password is not None: user.change_password(password, old_password) else: user.modify_info(nickname) return user.d()
class CommitView(View): @staticmethod @Analyse.r(a=[ P('tid', 'talkid').process(int), ], b=[ CommitP.commit, ]) @Auth.require_login def post(request): """POST /api/talk/@<int:tid>/commit 添加评论 """ return Commit.create(request.d.commit, request.d.tid, request.user).d()
def __init__(self, p: Union[P, str, None] = None, long=None, short=None, default=NotSet, allow_default=True): self.p = P(p) if isinstance(p, str) else p self.short = short self.long = long self.default = default self.allow_default = allow_default if not self.short and not self.long: raise ServiceMessage.PARAM_NAME
class TokenView(View): @staticmethod @Analyse.r(q=PDict().set_fields( SpaceP.name_getter, AlbumP.name, P('image_num', '图片数量').process(boundary(max_=99, min_=1))).process(Album.getter)) @Auth.require_admin def get(r): album = r.d.album image_num = r.d.image_num return Foto.get_tokens( num=image_num, album=album.name, space=album.space.name, )
class LSService(Service): name = 'ls' desc = '查看工具箱' long_desc = Lines('👉ls lang', '👉ls ../web') PLong = Parameter(P(read_name='是否显示完整信息').default(), short='l') @staticmethod def find_path(current: Service, paths: str): if paths and paths[0] == '/': current = ServiceDepot.get(ROOT_NAME) paths = paths.split('/') for path in paths: if path == '..': if not current.parent: raise LSMessage.PARENT current = current.parent elif path != '.' and path != '': current = current.get(path) if not current: raise LSMessage.NOT_FOUND(path) if not current.as_dir: raise LSMessage.CD_DIR(current.name) return current @classmethod def init(cls): cls.validate(cls.PLong) @classmethod def run(cls, directory: Service, storage: ServiceData, pd: ParamDict, *args): paths = args[0] if args else '' terminal = cls.find_path(directory, paths) long = cls.PLong.is_set_in(pd) messages = ['%s中拥有以下工具:' % terminal.name] for child in terminal.get_services(): name = child.name + ['(工具)', '(工具箱)'][child.as_dir] if long: messages.append('%s\t%s' % (name, child.desc)) else: messages.append(name) return '\n'.join(messages)
class RoomMemberView(View): @staticmethod @Auth.require_login @Analyse.r(a=[RoomP.room_number]) @Roomm.is_room_member def post(request): """POST /api/room/member/@<int:number> 获取房间信息 """ return request.d.room.d() @staticmethod @Auth.require_login @Analyse.r(a=[RoomP.room_number]) @Roomm.is_room_member def delete(request): """DELETE /api/room/member/@<int:number> 退出房间 """ room_number = request.d.room.number Member.leave_room(request.user) Room.change_position(Room.get_room_by_number(room_number)) @staticmethod @Auth.require_login @Analyse.r(a=[RoomP.room_number], b=[P('ready', '是否准备').default(True).process(bool)]) @Roomm.is_room_member def put(request): """PUT /api/room/member/@<int:number> 房间状态操作(开始游戏(两人准备)/准备) """ return Room.room_ready_status(request.user, **request.d.dict('room', 'ready')).d()
class MilestoneP: name, start_date = Milestone.P('name', 'start_date') start_date.process( lambda s: datetime.datetime.strptime(s, '%Y-%m-%d').date(), begin=True) id_getter = P('mid', yield_name='milestone').process(Milestone.get)
class BindPhoneService(Service): name = 'bind' desc = '绑定手机号' long_desc = Lines('用于推送其他功能产生的结果', '手机号绑定后允许更改', '设置手机号并发送验证码:bind -p13xxxxxxxxx', '非中国大陆手机号发送验证码格式为:bind -p+地区代码+手机号', '如香港代码为852,则bind -p+85212345678', '验证码反馈完成手机绑定:bind -c123456') WAIT = 0 DONE = 1 PPhone = Parameter( P(read_name='手机号').process(str).validate(phone_validator), long='phone', short='p') PCaptcha = Parameter(P(read_name='验证码').default(), long='captcha', short='c') @classmethod def init(cls): cls.validate(cls.PPhone, cls.PCaptcha) @staticmethod def readable_send_wait(send_wait: int): s = '' send_wait = int(send_wait) if send_wait // 60: s += '%s分' % (send_wait // 60) if send_wait % 60: s += '%s秒' % (send_wait % 60) return s @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): data = storage.classify() # if data.status: # 设置手机号 # raise BindPhoneError.MODIFY_NOT_ALLOWED crt_time = datetime.datetime.now().timestamp() last_time = data.last_time or 0 if pd.has(cls.PPhone): phone = pd.get(cls.PPhone) captcha = get_random_string(length=6, allowed_chars='1234567890') send_wait = last_time + 60 - crt_time if send_wait > 0: raise BindPhoneMessage.SEND_WAIT(send_wait) Phone.validate(phone, captcha) storage.update( dict( phone=phone, captcha=captcha, last_time=crt_time, attempt=3, )) raise BindPhoneMessage.CAPTCHA_SENT elif pd.has(cls.PCaptcha): if not data.attempt: raise BindPhoneMessage.CAPTCHA_RESENT data.attempt -= 1 storage.update(data) if last_time + 5 * 60 < crt_time: raise BindPhoneMessage.TIME_EXPIRED captcha = pd.get(cls.PCaptcha) if captcha != data.captcha: raise BindPhoneMessage.CAPTCHA_WRONG(data.attempt) storage.user.set_phone(data.phone) storage.update(dict(status=cls.DONE)) raise BindPhoneMessage.SUCCESS else: return cls.need_help()
class RoomP: password, number, = Room.get_params('password', 'number') room_number = P('number', '房间号', 'room').process(Room.get_room_by_number) room_password = P('password', '房间密码')
class MeatP: content, status = Meat.get_params('content', 'status') notification = P('notification', '目标日期').default(False).process(bool) target_time = P('target_time', '目标时间').process(int).process(target_timer) mid = P('mid', '天鹅肉id', 'meat').process(int).process(Meat.get_meat_by_pk)
@E.register() class MathError: DIV_ZERO = E("除数不能为0") POSITIVE = E("需要为正数") def positive_check(v): """check if value is positive""" if v < 0: raise MathError.POSITIVE def not_zero(v): """check if value is zero""" if v == 0: raise MathError.DIV_ZERO pos_num = P('positive', '正数').process(float).validate(positive_check) divided_num = pos_num.clone().rename('divided').validate(not_zero) @Analyse.p(pos_num, divided_num) def div(positive, divided): return positive // divided print(div(999.9, '-0.2'))
class Service: """服务""" name = 'NAME' desc = 'DESCRIPTION' long_desc = """暂无详细说明""" as_dir = False parent = None async_user_task = False async_service_task = False PHelper = Parameter(P(read_name='获取帮助').default(), long='help', short='h') PInline = Parameter(P(read_name='批处理模式').default(), long='inline') __parameters = [PHelper, PInline] # type: List[Parameter] __services = [] # type: List['Service'] @classmethod def init(cls): pass @classmethod def get_global_storage(cls): return ServiceData.get_or_create(cls.name, None) @classmethod def need_help(cls): return '请使用%s -h查看本工具的使用方法' % cls.name @classmethod def helper(cls): messages = ['%s: %s' % (cls.name, cls.desc), str(cls.long_desc), '', '功能参数说明:'] for parameter in cls.__parameters: messages.append('%s: %s' % (str(parameter), parameter.p.read_name)) return '\n'.join(messages) @classmethod def work(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): if cls.as_dir: raise ServiceMessage.DIR_NOT_CALLABLE if not pd.has(cls.PHelper): return str(cls.run(directory, storage, pd, *args)) return cls.helper() @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): pass @classmethod def get(cls, name): for service in cls.__services: if service.name == name: return service @classmethod def process_parameters(cls, kwargs: dict): parameters = dict() for parameter in cls.__parameters: value = parameter.get_from(kwargs) if value == Parameter.NotFound: if parameter.default == Parameter.NotSet and not parameter.allow_default: raise ServiceMessage.PARAM_NO_VALUE(str(parameter)) else: value = parameter.default else: _, value = parameter.p.run(value) parameters[parameter] = value return parameters @classmethod def register(cls, service: 'Service'): ServiceDepot.register(service) service.init() return service @classmethod def contains(cls, *services): if cls.__services: cls.__services.extend(services) else: cls.__services = list(services) for service in services: service.parent = cls @classmethod def validate(cls, *parameters): cls.__parameters = cls.__parameters + list(parameters) @classmethod def get_services(cls): return cls.__services @classmethod def async_user_handler(cls, storage_list: List[ServiceData]): pass @classmethod def async_user(cls, storage: ServiceData): pass @classmethod def async_service(cls, storage: ServiceData): pass
class WatchService(Service): name = 'watch' desc = '网页变化监控' long_desc = Lines('当网页发送变化时,将会发送短信提醒,且任务自动结束', '⚠️监控最短时间单位为1分钟', '⚠️暂不支持中文域名网址监控', '⚠️网页格式规范,应以http/https开头', '👉watch -n百度 https://www.baidu.com', '👉watch -i2 https://www.zju.edu.cn') async_user_task = True PInterval = Parameter(P(read_name='监控时间单位').default(5).process(int), long='interval', short='i') PName = Parameter(P(read_name='监控名').default(), long='name', short='n') PCancel = Parameter(P(read_name='取消当前任务').default(), long='cancel') PStatus = Parameter(P(read_name='查看当前任务').default(), long='status') @staticmethod def readable_time(create_time): return datetime.datetime.fromtimestamp(create_time).strftime( '%m-%d %H:%M') @classmethod def init(cls): cls.validate(cls.PName, cls.PCancel, cls.PStatus, cls.PInterval) @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): storage.user.require_phone() data = storage.classify() if pd.has(cls.PCancel): data.work = False storage.update(data) return '任务已取消' if pd.has(cls.PStatus): if not data.work: return '暂无监控任务' return Lines( '正在监控:%s' % data.name, '任务开始时间:%s' % cls.readable_time(data.create_time), '已监控次数:%s' % data.visit_times, '监控时间间隔:%s分钟' % (data.interval or cls.PInterval.p.default_value)) if not args: return cls.need_help() url = args[0] if not url_validate(url): raise WatchError.URL key = cls.get_key_of(url) name = urlparse(url).netloc if pd.has(cls.PName): name = pd.get(cls.PName) interval = pd.get(cls.PInterval) crt_time = datetime.datetime.now().timestamp() storage.update( dict( work=True, name=name, url=url, visit_times=0, error_times=0, create_time=crt_time, last_visit_time=crt_time, key=key, interval=interval, )) return '监控已开启' @classmethod def async_user_handler(cls, storage_list: List[ServiceData]): for service_data in storage_list: cls.async_user(service_data) @staticmethod def get_key_of(url): try: with requests.get(url, timeout=3) as r: content = r.content # type: bytes except Exception: raise WatchError.GET_URL return md5(content) @classmethod def async_user(cls, storage: ServiceData): data = storage.classify() data.interval = data.interval or cls.PInterval.p.default_value if not data.work: return crt_time = datetime.datetime.now().timestamp() if data.last_visit_time + 60 * data.interval > crt_time: return data.last_visit_time = crt_time data.visit_times += 1 try: key = cls.get_key_of(data.url) data.error_times = 0 except E: data.error_times += 1 if data.error_times == 3: Phone.announce(storage.user, cls, '监控任务%s网页连续三次无法访问,已停止任务' % data.name) storage.update(dict(work=False)) return if data.key != key: Phone.announce(storage.user, cls, '监控任务%s的网页发生变化' % data.name) storage.update(dict(work=False)) return storage.update(data)
class BOCService(Service): name = 'boc' desc = '中银外汇牌价监测' long_desc = Lines( '监测中国银行外汇牌价', '⚠️支持多个币种现汇/现钞的买入/卖出价格', '⚠️使用短信提醒功能时需要设定具体的现汇/现钞和买入/卖出参数', '👉通过boc GBP -a命令获取英镑(GBP)的实时卖出价', '👉通过boc -s命令获取货币简写名称列表', '👉通过boc USA --ask --bn --sms=min命令监测美元的现钞卖出价,价格低于历史时会发短信提醒', ) FX = { 'GBP': '英镑', 'UK': '英镑', 'HKD': '港币', 'HK': '港币', 'USD': '美元', 'US': '美元', 'USA': '美元', 'CHF': '瑞士法郎', 'DEM': '德国马克', 'FRF': '法国法郎', 'FF': '法国法郎', 'SGD': '新加坡元', 'SEK': '瑞典克朗', 'DKK': '丹麦克朗', 'NOK': '挪威克朗', 'JPY': '日元', 'JP': '日元', 'CAD': '加拿大元', 'CA': '加拿大元', 'AUD': '澳大利亚元', 'AU': '澳大利亚元', 'EUR': '欧元', 'EU': '欧元', 'MOP': '澳门元', 'MO': '澳门元', 'PHP': '菲律宾比索', 'THB': '泰国铢', 'NZD': '新西兰元', 'KIWI': '新西兰元', 'WON': '韩元', 'SK': '韩元', 'RUB': '卢布', 'RU': '卢布', 'MYR': '林吉特', 'SEN': '林吉特', 'NTD': '新台币', 'TW': '新台币', 'ESP': '西班牙比塞塔', 'ITL': '意大利里拉', 'ANG': '荷兰盾', 'BEF': '比利时法郎', 'FIM': '芬兰马克', 'INR': '印度卢比', 'IDR': '印尼卢比', 'BRL': '巴西里亚尔', 'AED': '阿联酋迪拉姆', 'ZAF': '南非兰特', 'SAR': '沙特里亚尔', 'TRY': '土耳其里拉', 'YTL': '土耳其里拉' } FX_REVERSE = dict() KEY_TRANS = dict(SE_BID='现汇买入价', BN_BID='现钞买入价', SE_ASK='现汇卖出价', BN_ASK='现钞卖出价') M_TRANS = dict(min='低', max='高') async_user_task = True START = 1 STOP = 0 PSpotEx = Parameter(P(read_name='现汇价').default(), long='se') PBankNo = Parameter(P(read_name='现钞价').default(), long='bn') PBid = Parameter(P(read_name='买入价').default(), long='bid', short='b') PAsk = Parameter(P(read_name='卖出价').default(), long='ask', short='a') PShow = Parameter(P(read_name='显示货币简写列表').default(), long='show', short='s') PSms = Parameter(P(read_name='短信提醒').validate(sms_validator), long='sms') PSmsStop = Parameter(P(read_name='停止短信提醒').default(), long='sms-stop') @classmethod def init(cls): cls.validate(cls.PSpotEx, cls.PBankNo, cls.PBid, cls.PAsk, cls.PShow, cls.PSms, cls.PSmsStop) for k in cls.FX: if cls.FX[k] in cls.FX_REVERSE: cls.FX_REVERSE[cls.FX[k]].append(k) else: cls.FX_REVERSE[cls.FX[k]] = [k] @classmethod def async_user_handler(cls, storage_list: List[ServiceData]): for service_data in storage_list: cls.async_user(service_data) @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): data = storage.classify() if pd.has(cls.PShow): return Lines(*[ '%s:%s' % (k, '或'.join(cls.FX_REVERSE[k])) for k in cls.FX_REVERSE ]) if pd.has(cls.PSmsStop): if data.status == cls.START: data.status = cls.STOP storage.update(data) raise BOCError.STOP raise BOCError.NOT_START if not args: return cls.need_help() currency = args[0].upper() if currency not in cls.FX: raise BOCError.CURRENCY if pd.has(cls.PSms): storage.user.require_phone() if not (pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo)): raise BOCError.SE_BN if not (pd.has(cls.PAsk) ^ pd.has(cls.PBid)): raise BOCError.BID_ASK sort = ('SE' if pd.has(cls.PSpotEx) else 'BN') + ',' sort += 'ASK' if pd.has(cls.PAsk) else 'BID' storage.update( dict( currency=currency, sort=sort, monitor=pd.get(cls.PSms), value=None, status=cls.START, )) raise BOCError.START try: keys, values = bocfx(currency) except Exception as e: raise BOCError.SERVICE_INACCESSIBLE(debug_message=e) lines = [] time = '实时' for i, k in enumerate(keys): if k in cls.KEY_TRANS: if pd.has(cls.PSpotEx) ^ pd.has(cls.PBankNo): if pd.has(cls.PSpotEx) ^ ('SE' in k): continue if pd.has(cls.PAsk) ^ pd.has(cls.PBid): if pd.has(cls.PAsk) ^ ('ASK' in k): continue lines.append('%s:%s' % (cls.KEY_TRANS[k], values[i])) if k == 'Time': time = values[i] lines.insert(0, '中国银行%s牌价(%s)' % (cls.FX[currency], time)) return Lines(*lines) @classmethod def async_user(cls, storage: ServiceData): data = storage.classify() if not data.status: return if not data.error_times: data.error_times = 0 crt_time = datetime.datetime.now().timestamp() if data.last_visit_time and data.last_visit_time + 60 * 60 > crt_time: return data.last_visit_time = crt_time try: value = bocfx(data.currency, data.sort) except E: data.error_times += 1 if data.error_times == 3: Phone.announce(storage.user, cls, '中银%s汇率连续三次无法访问,已停止任务' % cls.FX[data.currency]) storage.update(dict(status=cls.STOP)) return value = float(value[0]) if not data.value or ((data.value > value) ^ (data.monitor == 'max')): data.value = value message = str(value) + '!' + \ '中银%s的%s达到历史新' % (cls.FX[data.currency], cls.KEY_TRANS[data.sort.replace(',', '_')]) + \ cls.M_TRANS[data.monitor] + '。' Phone.announce(storage.user, cls, message) storage.update(data)
def get_url(url): import re pattern = re.compile( r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!#*(),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+' ) # 匹配模式 urls = re.findall(pattern, url) if urls: return urls[0] raise Error.NO_URL param_list = [ P('url').process(parse.unquote), P('v').default(1).process(int), ] def check_support(url, v): web_str = '' new_support_str = '' for web in websites: if web.detect(url): if v < web.SUPPORT_VERSION: raise Error.NEW_VERSION_SUPPORT return web web_str += web.NAME + ' ' if v < web.SUPPORT_VERSION:
class CommentP: content, reply_to = Comment.P('content', 'reply_to') cid_getter = P('cid', yield_name='comment').process(int).process(Comment.get) reply_to_getter = reply_to.process(Comment.get)
class SMSService(Service): name = 'sms' desc = '共享手机短信' long_desc = Lines( '浏览某些不重要的网站且需要手机号注册时,本工具可以提供共享手机号。', '通过sms -g命令获取当前手机号,通过sms -s命令获取接收到的短信(由于手机号共享,收到的短信可能还有其他用户的,您收到的短信也公开),通过sms -r命令获取新手机号' ) async_service_task = True PGet = Parameter(P(read_name='获取当前手机号').default(), long='get', short='g') PShow = Parameter(P(read_name='显示短信').default(), long='show', short='s') PRenew = Parameter(P(read_name='获取新手机号').default(), long='renew', short='r') crawler = FreeReceiveSMS() @classmethod def init(cls): cls.validate(cls.PGet, cls.PShow, cls.PRenew) @classmethod def run(cls, directory: 'Service', storage: ServiceData, pd: ParamDict, *args): data = storage.classify() if pd.has(cls.PRenew): global_storage = cls.get_global_storage() global_data = global_storage.classify() if not global_data.phones: raise SMSMessage.NONE phone_num = len(global_data.phones) phone_index = random.randint(0, phone_num - 1) data.phone = global_data.phones[phone_index] storage.update(data) return data.phone if not data.phone: raise SMSMessage.NO_PHONE if pd.has(cls.PGet): return data.phone if pd.has(cls.PShow): lines = cls.crawler.get_msg(data, service=cls) return Lines(*lines) return cls.need_help() @classmethod def async_service(cls, storage: ServiceData): data = storage.classify() last_time = data.last_update_time or 0 crt_time = datetime.datetime.now().timestamp() if last_time + 60 * 30 > crt_time: return data.last_update_time = crt_time data.error_web_times = data.error_web_times or 0 data.error_re_times = data.error_re_times or 0 data.phones = cls.crawler.get_phone_list(data) or [] storage.update(data)