def get_wetter(parsed_query): location = parsed_query['location'] html = parsed_query['html_output'] lang = parsed_query['lang'] location_not_found = False if location == NOT_FOUND_LOCATION: location_not_found = True stderr = "" returncode = 0 if not location_not_found: stdout, stderr, returncode = _wego_wrapper(location, parsed_query) first_line, stdout = _wego_postprocessing(location, parsed_query, stdout) if location_not_found or \ (returncode != 0 \ and ('Unable to find any matching weather' ' location to the parsed_query submitted') in stderr): stdout, stderr, returncode = _wego_wrapper(DEFAULT_LOCATION, parsed_query) location_not_found = True not_found_header = """ >>> _ _ ___ _ _ >>> | || | / _ \| || | >>> | || |_| | | | || |_ >>> |__ _| |_| |__ _| >>> |_| \___/ |_| >>> >>> 404 %s: %s >>> """ % (get_message("UNKNOWN_LOCATION", lang).upper(), parsed_query['override_location_name']) not_found_header = "\n".join( "\033[48;5;91m" + x + " \033[0m" for x in not_found_header.splitlines()[1:]) not_found_footer = get_message('NOT_FOUND_MESSAGE', lang) not_found_footer = "\n".join("\033[48;5;91m " + x + " \033[0m" for x in not_found_footer.splitlines() if x) + "\n" first_line, stdout = _wego_postprocessing(location, parsed_query, stdout) stdout = not_found_header + "\n----\n" + stdout + not_found_footer if html: return _htmlize(stdout, first_line, parsed_query) return stdout
def milestone_handler_func(intent): milestones = load_current_milestones_with_locale(intent.request.locale) if intent.request.intent.has_slot("activityname"): slot_value = intent.request.intent.get_slot("activityname") milestone_key = slot_value_to_data_key(slot_value) if milestone_key == "XUR": if milestones.has_milestone(milestone_key): phrase = get_message("xur-phrase", locale=intent.request.locale) else: phrase = get_message("no-xur-phrase", locale=intent.request.locale) return build_response({}, build_speechlet_response( "Xur", phrase, phrase, True)) if milestones.has_milestone(milestone_key): milestone = milestones.get_milestone(milestone_key) print milestone_key phrase = "" if milestone_key in [ "CallToArms", "Meditations", "ClanObjectives" ]: phrase = milestone.description else: phrase = get_message("milestone-phrase", locale=intent.request.locale).replace( "#caption#", slot_value).replace( "#name#", milestone.name).replace( "#description#", milestone.description) return build_response({}, build_speechlet_response( milestone_key, phrase, phrase, True)) else: phrase = get_error_message("unknown-milestone", locale=intent.request.locale).replace( "#caption#", slot_value) return build_response({}, build_speechlet_response( milestone_key, phrase, phrase, True)) else: phrase = get_error_message("no-milestone", locale=intent.request.locale) return build_response({}, build_speechlet_response(":(", phrase, phrase, True))
def get_wetter(parsed_query): location = parsed_query['location'] html = parsed_query['html_output'] lang = parsed_query['lang'] location_not_found = False if location == NOT_FOUND_LOCATION: location_not_found = True stderr = "" returncode = 0 if not location_not_found: stdout, stderr, returncode = _wego_wrapper(location, parsed_query) if location_not_found or \ (returncode != 0 \ and ('Unable to find any matching weather' ' location to the parsed_query submitted') in stderr): stdout, stderr, returncode = _wego_wrapper(NOT_FOUND_LOCATION, parsed_query) location_not_found = True stdout += get_message('NOT_FOUND_MESSAGE', lang) if "\n" in stdout: first_line, stdout = _wego_postprocessing(location, parsed_query, stdout) else: first_line = "" if html: return _htmlize(stdout, first_line, parsed_query) return stdout
def _response(parsed_query, query, fast_mode=False): """Create response text based on `parsed_query` and `query` data. If `fast_mode` is True, process only requests that can be handled very fast (cached and static files). """ answer = None cache_signature = cache.get_signature(parsed_query["user_agent"], parsed_query["request_url"], parsed_query["ip_addr"], parsed_query["lang"]) answer = cache.get(cache_signature) if parsed_query['orig_location'] in PLAIN_TEXT_PAGES: answer = show_text_file(parsed_query['orig_location'], parsed_query['lang']) if parsed_query['html_output']: answer = render_template('index.html', body=answer) if answer or fast_mode: return answer # at this point, we could not handle the query fast, # so we handle it with all available logic loc = (parsed_query['orig_location'] or "").lower() if parsed_query.get("view"): if not parsed_query.get("location"): parsed_query["location"] = loc output = wttr_line(query, parsed_query) elif loc == 'moon' or loc.startswith('moon@'): output = get_moon(parsed_query) else: output = get_wetter(parsed_query) if parsed_query.get('png_filename'): if parsed_query.get("view") != "v3": # originally it was just a usual function call, # but it was a blocking call, so it was moved # to separate threads: # # output = fmt.png.render_ansi( # output, options=parsed_query) result = TASKS.spawn(fmt.png.render_ansi, cache._update_answer(output), options=parsed_query) output = result.get() else: if query.get('days', '3') != '0' \ and not query.get('no-follow-line') \ and ((parsed_query.get("view") or "v2")[:2] in ["v2", "v3"]): if parsed_query['html_output']: output = add_buttons(output) else: message = get_message('FOLLOW_ME', parsed_query['lang']) if parsed_query.get('no-terminal', False): message = remove_ansi(message) output += '\n' + message + '\n' return cache.store(cache_signature, output)
def _wego_postprocessing(location, parsed_query, stdout): full_address = parsed_query['full_address'] lang = parsed_query['lang'] if 'days' in parsed_query: if parsed_query['days'] == '0': stdout = "\n".join(stdout.splitlines()[:7]) + "\n" if parsed_query['days'] == '1': stdout = "\n".join(stdout.splitlines()[:17]) + "\n" if parsed_query['days'] == '2': stdout = "\n".join(stdout.splitlines()[:27]) + "\n" first = stdout.splitlines()[0] rest = stdout.splitlines()[1:] if parsed_query.get('no-caption', False): if ':' in first: first = first.split(":", 1)[1] stdout = "\n".join([first.strip()] + rest) + "\n" if parsed_query.get('no-terminal', False): stdout = remove_ansi(stdout) if parsed_query.get('no-city', False): stdout = "\n".join(stdout.splitlines()[2:]) + "\n" if full_address \ and parsed_query.get('format', 'txt') != 'png' \ and (not parsed_query.get('no-city') and not parsed_query.get('no-caption') and not parsed_query.get('days') == '0'): line = "%s: %s [%s]\n" % ( get_message('LOCATION', lang), full_address, location) stdout += line if parsed_query.get('padding', False): lines = [x.rstrip() for x in stdout.splitlines()] max_l = max(len(remove_ansi(x)) for x in lines) last_line = " "*max_l + " .\n" stdout = " \n" + "\n".join(" %s " %x for x in lines) + "\n" + last_line return first, stdout
def briefing_handler_func(intent): milestones = load_current_milestones_with_locale(intent.request.locale) phrase = get_message("briefing-phrase", locale=intent.request.locale) if milestones.has_milestone("Trials"): phrase = phrase + get_message("trials-phrase", locale=intent.request.locale) if milestones.has_milestone("XUR"): phrase = phrase + get_message( "xur-phrase", locale=intent.request.locale ) + milestones.get_milestone("XUR").description + " " if milestones.has_milestone("Nightfall"): phrase = phrase + get_message( "nightfall-phrase", locale=intent.request.locale).replace( "#name#", milestones.get_milestone("Nightfall").name) if milestones.has_milestone("Hotspot"): phrase = phrase + milestones.get_milestone("Hotspot").description + " " if milestones.has_milestone("Raid"): phrase = phrase + get_message( "raid-phrase", locale=intent.request.locale).replace( "#name#", milestones.get_milestone("Raid").name) if milestones.has_milestone("CallToArms"): phrase = phrase + milestones.get_milestone( "CallToArms").description + " " if milestones.has_milestone("ClanObjectives"): phrase = phrase + milestones.get_milestone( "ClanObjectives").description + " " if milestones.has_milestone("Meditations"): phrase = phrase + milestones.get_milestone( "Meditations").description + " " phrase = phrase + get_message("exit-phrase", locale=intent.request.locale) return build_response({}, build_speechlet_response("Destiny 2 Briefing", phrase, phrase, True))
output = get_moon(location, html=html_output, lang=lang) else: output = get_wetter( location, ip_addr, html=html_output, lang=lang, query=query, location_name=override_location_name, full_address=full_address, url=request.url, ) if html_output: output = add_buttons(output) else: if query.get('days', '3') != '0': #output += '\n' + get_message('NEW_FEATURE', lang).encode('utf-8') output += '\n' + get_message('FOLLOW_ME', lang).encode('utf-8') + '\n' return output except RuntimeError, exception: if 'Malformed response' in str(exception) \ or 'API key has reached calls per day allowed limit' in str(exception): if html_output: return MALFORMED_RESPONSE_HTML_PAGE return get_message('CAPACITY_LIMIT_REACHED', lang).encode('utf-8') logging.error("Exception has occured", exc_info=1) return "ERROR"
def wttr(location, request): """ Main rendering function, it processes incoming weather queries. Depending on user agent it returns output in HTML or ANSI format. Incoming data: request.args request.headers request.remote_addr request.referrer request.query_string """ def _wrap_response(response_text, html_output): response = make_response(response_text) response.mimetype = 'text/html' if html_output else 'text/plain' return response if is_location_blocked(location): return "" ip_addr = client_ip_address(request) try: LIMITS.check_ip(ip_addr) except RuntimeError as exception: return str(exception) png_filename = None if location is not None and location.lower().endswith(".png"): png_filename = location location = location[:-4] lang = get_answer_language(request) query = parse_query.parse_query(request.args) html_output = get_output_format(request, query) user_agent = request.headers.get('User-Agent', '').lower() if location in PLAIN_TEXT_PAGES: help_ = show_text_file(location, lang) if html_output: return _wrap_response(render_template('index.html', body=help_), html_output) return _wrap_response(help_, html_output) if location and ':' in location: location = cyclic_location_selection(location, query.get('period', 1)) orig_location = location if not png_filename: location, override_location_name, full_address, country, query_source_location = \ location_processing(location, ip_addr) us_ip = query_source_location[ 1] == 'United States' and 'slack' not in user_agent query = parse_query.metric_or_imperial(query, lang, us_ip=us_ip) # logging query orig_location_utf8 = (orig_location or "").encode('utf-8') location_utf8 = location.encode('utf-8') use_imperial = query.get('use_imperial', False) log(" ".join( map(str, [ ip_addr, user_agent, orig_location_utf8, location_utf8, use_imperial, lang ]))) if country and location != NOT_FOUND_LOCATION: location = "%s,%s" % (location, country) # We are ready to return the answer try: if 'format' in query: return _wrap_response( wttr_line(location, override_location_name, query, lang), html_output) if png_filename: options = {'lang': lang, 'location': location} options.update(query) cached_png_file = wttrin_png.make_wttr_in_png(png_filename, options=options) response = make_response( send_file(cached_png_file, attachment_filename=png_filename, mimetype='image/png')) for key, value in { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', }.items(): response.headers[key] = value # Trying to disable github caching return response if location.lower() == 'moon' or location.lower().startswith('moon@'): output = get_moon(location, html=html_output, lang=lang, query=query) else: output = get_wetter( location, ip_addr, html=html_output, lang=lang, query=query, location_name=override_location_name, full_address=full_address, url=request.url, ) if query.get('days', '3') != '0' and not query.get('no-follow-line'): if html_output: output = add_buttons(output) else: #output += '\n' + get_message('NEW_FEATURE', lang).encode('utf-8') output += '\n' + get_message('FOLLOW_ME', lang).encode('utf-8') + '\n' return _wrap_response(output, html_output) except RuntimeError as exception: if 'Malformed response' in str(exception) \ or 'API key has reached calls per day allowed limit' in str(exception): if html_output: return _wrap_response(MALFORMED_RESPONSE_HTML_PAGE, html_output) return _wrap_response( get_message('CAPACITY_LIMIT_REACHED', lang).encode('utf-8'), html_output) logging.error("Exception has occured", exc_info=1) return "ERROR"
def save_weather_data(location, filename, lang=None, query=None, location_name=None, full_address=None): ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]') def remove_ansi(sometext): return ansi_escape.sub('', sometext) if _is_invalid_location(location): error("Invalid location: %s" % location) NOT_FOUND_MESSAGE_HEADER = "" while True: location_not_found = False if location in ["test-thunder"]: test_name = location[5:] test_file = TEST_FILE.replace('NAME', test_name) stdout = open(test_file, 'r').read() stderr = "" break print "LOCATION = ", location if location == NOT_FOUND_LOCATION: location_not_found = True location = DEFAULT_LOCATION cmd = [WEGO, '--city=%s' % location] if query.get('inverted_colors'): cmd += ['-inverse'] if query.get('use_ms_for_wind'): cmd += ['-wind_in_ms'] if query.get('narrow'): cmd += ['-narrow'] if lang and lang in SUPPORTED_LANGS: cmd += ['-lang=%s' % lang] if query.get('use_imperial', False): cmd += ['-imperial'] if location_name: cmd += ['-location_name', location_name] p = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate() if p.returncode != 0: print "ERROR: location not found: %s" % location if 'Unable to find any matching weather location to the query submitted' in stderr: if location != NOT_FOUND_LOCATION: NOT_FOUND_MESSAGE_HEADER = u"ERROR: %s: %s\n---\n\n" % ( get_message('UNKNOWN_LOCATION', lang), location) location = NOT_FOUND_LOCATION continue error(stdout + stderr) break dirname = os.path.dirname(filename) if not os.path.exists(dirname): os.makedirs(dirname) if location_not_found: stdout += get_message('NOT_FOUND_MESSAGE', lang).encode('utf-8') stdout = NOT_FOUND_MESSAGE_HEADER.encode('utf-8') + stdout if 'days' in query: if query['days'] == '0': stdout = "\n".join(stdout.splitlines()[:7]) + "\n" if query['days'] == '1': stdout = "\n".join(stdout.splitlines()[:17]) + "\n" if query['days'] == '2': stdout = "\n".join(stdout.splitlines()[:27]) + "\n" first = stdout.splitlines()[0].decode('utf-8') rest = stdout.splitlines()[1:] if query.get('no-caption', False): separator = None if ':' in first: separator = ':' if u':' in first: separator = u':' if separator: first = first.split(separator, 1)[1] stdout = "\n".join([first.strip().encode('utf-8')] + rest) + "\n" if query.get('no-terminal', False): stdout = remove_ansi(stdout) if query.get('no-city', False): stdout = "\n".join(stdout.splitlines()[2:]) + "\n" if full_address and query.get('format', 'txt') != 'png': line = "%s: %s [%s]\n" % (get_message( 'LOCATION', lang).encode('utf-8'), full_address.encode('utf-8'), location) stdout += line if query.get('padding', False): lines = [x.rstrip() for x in stdout.splitlines()] max_l = max(len(remove_ansi(x).decode('utf8')) for x in lines) last_line = " " * max_l + " .\n" stdout = " \n" + "\n".join(" %s " % x for x in lines) + "\n" + last_line open(filename, 'w').write(stdout) cmd = ["bash", ANSI2HTML, "--palette=solarized"] if not query.get('inverted_colors'): cmd += ["--bg=dark"] p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) stdout, stderr = p.communicate(stdout) if p.returncode != 0: error(stdout + stderr) if query.get('inverted_colors'): stdout = stdout.replace( '<body class="">', '<body class="" style="background:white;color:#777777">') title = "<title>%s</title>" % first.encode('utf-8') opengraph = get_opengraph() stdout = re.sub("<head>", "<head>" + title + opengraph, stdout) open(filename + '.html', 'w').write(stdout)
def wttr(location, request): """Main rendering function, it processes incoming weather queries, and depending on the User-Agent string and other paramters of the query it returns output in HTML, ANSI or other format. """ def _wrap_response(response_text, html_output, png_filename=None): if not isinstance(response_text, str) and \ not isinstance(response_text, bytes): return response_text if png_filename: response = make_response( send_file(io.BytesIO(response_text), attachment_filename=png_filename, mimetype='image/png')) for key, value in { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', }.items(): response.headers[key] = value else: response = make_response(response_text) response.mimetype = 'text/html' if html_output else 'text/plain' return response if is_location_blocked(location): return ("", 403) # Forbidden try: LIMITS.check_ip(_client_ip_address(request)) except RuntimeError as exception: return (str(exception), 429) # Too many requests query = parse_query.parse_query(request.args) # first, we try to process the query as fast as possible # (using the cache and static files), # and only if "fast_mode" was unsuccessful, # use the full track parsed_query = parse_request(location, request, query, fast_mode=True) response = _response(parsed_query, query, fast_mode=True) http_code = 200 try: if not response: parsed_query = parse_request(location, request, query) response = _response(parsed_query, query) # pylint: disable=broad-except except Exception as exception: logging.error("Exception has occured", exc_info=1) if parsed_query['html_output']: response = MALFORMED_RESPONSE_HTML_PAGE http_code = 500 # Internal Server Error else: response = get_message('CAPACITY_LIMIT_REACHED', parsed_query['lang']) http_code = 503 # Service Unavailable # if exception is occured, we return not a png file but text if "png_filename" in parsed_query: del parsed_query["png_filename"] return (_wrap_response(response, parsed_query['html_output'], png_filename=parsed_query.get('png_filename')), http_code)
def help_handler_func(intent): phrase = get_message("help-phrase", locale=intent.request.locale) return build_response({}, build_speechlet_response("Warmind (Destiny 2)", phrase, phrase, True))
def cancel_handler_func(intent): phrase = get_message("exit-phrase", locale=intent.request.locale) return build_response({}, build_speechlet_response("Destiny 2 Briefing", phrase, phrase, True))