def close_db_session(exception=None): """Close DB session at request teardown.""" try: dao.remove() except Exception as e: Log.error(str(e))
def _getRequest(region, query_type, query_filter, query, api_key): """ Use URL to send request to API. ARGS: region, query_type, query_filter, query, api_key """ url = _make_url(region, query_type, query_filter, query) headers = {"Authorization": api_key, "Accept": "application/vnd.api+json"} try: Log.info('Sent API request to %s' % url) start_time = time.time() result = requests.get(url, headers=headers) Log.info('Received API request %r: took %f sec' % (result, time.time() - start_time)) result = result.json() except Exception as e: result = None return result
def _processPlayerId(data): """ Find player ID from player data. ARGS: data """ try: player_id = data['data'][0]['id'] except Exception as e: Log.error(str(e)) player_id = None return player_id
def getTelemetry(url): """ Get telemetry data using asset URL. ARGS: url """ headers = {"Accept": "application/vnd.api+json"} result = None try: Log.info('Sent API request to %s' % url) start_time = time.time() result = requests.get(url, headers=headers) Log.info('Received API request %r: took %f sec' % (result, time.time() - start_time)) if result: result = result.json() except Exception as e: raise e return result
def getPlayerStats(region, player, api_key, last_match_id): """ Get a tuple containing player id, match id, match stats. ARGS: region, player, api_key, last_match_id """ player_id = getPlayerId(region, player, api_key) player_data = _getPlayerData(region, player, api_key) match_ids = list(_processMatchIds(player_data)) try: if last_match_id: try: upto = match_ids.index(last_match_id) + 1 except: upto = 0 Log.error('Something went wrong with finding match index.') else: upto = 0 Log.info( 'No recent matches were recorded for player %r [region: %r]' % (player, region)) for match_id in match_ids[upto:]: match_data = _getMatch(region, match_id, api_key) match_info = _processMatchData(match_data) match_stats = _processParticipantData(match_data, player_id) roster_data = _processRosterData(match_data, player_id) telemetry_url = _processTelemetryURL(match_data) yield (match_id, match_stats, match_info, roster_data, telemetry_url) except Exception as e: raise e Log.error('Error finding matches found for player %r [region: %r]' % (player, region)) return False
def show_profile(player_name): """ Show player profile page. ARGS: player_name, region 1. Check whether player name and region are correctly given. i) If not so: abort. 2. Check if player with given name and region exists in DB. i) If not so: (a) Find PUBG player ID using API. If not found, render page for not found. (b) Create new player with stats for each game mode, append them accordingly and commit. (c) Render profile page for player created. ii) If so: render profile page for player found. 3. Check whether stats exist for current season. i) If not so: (a) Create new stats for each game mode, for current season. (b) Add all, append and then commit. """ api_key = current_app.config['API_KEY'] season = current_app.config['CURRENT_SEASON'] region = request.args.get('region', '') if not (player_name or region): abort(404) player = dao.query(Player).filter_by(name=player_name).\ filter_by(region=region).first() if not player: api = PUBG(api_key, shardDict(region)) pubg_player = api.players.filter(player_names=[player_name]) #pubg_id = getPlayerId(region, player_name, api_key[region]) if not pubg_id: return render_template('search.html', results=None, query=player_name) try: player = Player(player_name, pubg_id, region) soloStats = SoloStats(season) duoStats = DuoStats(season) squadStats = SquadStats(season) dao.add_all([player, soloStats, duoStats, squadStats]) player.solo.append(soloStats) player.duo.append(duoStats) player.squad.append(squadStats) dao.commit() Log.info('New player %r added.' % player) except Exception as e: dao.rollback() Log.error(str(e)) raise e else: return render_template('profile_overview.html', player=player) stats_exist = any(x.season == season for x in player.solo) if not stats_exist: try: soloStats = SoloStats(season) duoStats = DuoStats(season) squadStats = SquadStats(season) dao.add_all([soloStats, duoStats, squadStats]) player.solo.append(soloStats) player.duo.append(duoStats) player.squad.append(squadStats) dao.commit() Log.info('New season stats for player %r added.' % player) except Exception as e: dao.rollback() Log.error(str(e)) raise e return render_template('profile_overview.html', player=player)
def update(player_id): """ Update player's matches. ARGS: player_id 1. Check if player with given ID exists. i) If not so, abort. 2. Check if the player has been recently updated. i) If so, redirect to profile page for player with given name and region. 3. Check season. i) If new season, create new player stats for each game mode, append them and commit. 4. Find the PUBG match ID of the latest record and use it to get data from API on matches since. 5. For each match data: i) Check if record with PUBG match ID for player with given ID exists in DB. (a) If so: nothing happens. ii) Check if match with PUBG match ID exists in DB. (a) If not so: create one and its match info and save telemetry data to mongoDB. iii) Check if roster with PUBG roster ID exists in DB. If not so, create one and append to match. iv) Check match season. v) Create record and match stats and append them accordingly. vi) Check game mode and aggregate player stats accordingly. vii) Set player's update time to now and finally commit. 6. Return jsonified signal for success or failure """ api_key = current_app.config['API_KEY'] season = current_app.config['CURRENT_SEASON'] season_update = current_app.config['SEASON_UPDATE'] player = dao.query(Player).get(player_id) if not player: abort(404) diff = datetime.utcnow() - player.updateTime if diff.seconds < current_app.config['UPDATE_WAIT_TIME']: return redirect( url_for('.show_profile', player_name=player.name, region=player.region)) stats_exist = any(x.season == season for x in player.solo) if not stats_exist: try: new_soloStats = SoloStats(season) new_duoStats = DuoStats(season) new_squadStats = SquadStats(season) dao.add_all([new_soloStats, new_duoStats, new_squadStats]) player.solo.append(new_soloStats) player.duo.append(new_duoStats) player.squad.append(new_squadStats) dao.commit() Log.info('New season stats for player %r added.' % player) except Exception as e: dao.rollback() Log.error(str(e) + " in check1") raise e last_match_id = None if player.records: last_match_id = player.records[-1].pubgMatchID player_stats = getPlayerStats(player.region, player.name, api_key, last_match_id) # player_stats = (match_id, match_stats, match_info, roster_data, telemetry_url) for data in player_stats: pubg_match_id = data[0] record_exist = dao.query(Record).filter_by(playerID=player.id).\ filter_by(pubgMatchID=pubg_match_id).first() try: if not record_exist: match_exist = dao.query(Match).filter_by( pubgID=pubg_match_id).first() if not match_exist: match_exist = Match(pubg_match_id) match_info = MatchInfo(data[2]) dao.add_all([match_exist, match_info]) match_exist.info = match_info """ telemetry_data = getTelemetry(data[4]) tele_exist = mongo.db.matches.find_one({'matchID' : pubg_match_id}) if not tele_exist: filter_tele = filterTelemetry(telemetry_data, ["LogItemPickup", "LogPlayerPosition", "LogGameStatePeriodic", "LogPlayerKill"]) mongo.db.matches.insert({'matchID' : pubg_match_id, 'map' : match_info.mapName, 'data' : telemetry_data}) Log.info('Telemetry data added for match %r' % match_exist) """ roster = dao.query(Roster).filter_by( pubgRosterID=data[3]).first() if not roster: roster = Roster(data[3]) dao.add(roster) match_exist.rosters.append(roster) timestamp = match_exist.info.createdAt createdAt = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%SZ') match_season = season if createdAt < season_update: match_season = season - 1 record = Record(pubg_match_id, match_season) match_stats = MatchStats(data[1]) dao.add_all([match_stats, record]) roster.participants.append(record) record.stats = match_stats player.records.append(record) info = roster.match.info if info.gameMode == 'solo': next(stats for stats in player.solo if stats.season == match_season).aggregate(data[1]) elif info.gameMode == 'duo': next(stats for stats in player.duo if stats.season == match_season).aggregate(data[1]) elif info.gameMode == 'squad': next(stats for stats in player.squad if stats.season == match_season).aggregate(data[1]) else: player.event_games += 1 dao.commit() Log.info('%r with %r added to %r' % (record, match_stats, player)) except Exception as e: dao.rollback() Log.error(str(e)) return jsonify(result=False) player.updateTime = datetime.utcnow() dao.commit() return jsonify(result=True)
def update_winner(): """ Update winner average statistics. """ api_key = current_app.config['API_KEY'] regions = current_app.config['REGIONS'] modes = current_app.config['MODES'] mapNames = current_app.config['MAP_NAMES'] random_pick = dao.query(WinnerAverage).first() if not random_pick: new_average = [ WinnerAverage(region, mode, mapName) for region in regions for mode in modes for mapName in mapNames ] try: dao.add_all(new_average) dao.commit() Log.info('New winner average stats added to DB!') except Exception as e: dao.rollback() Log.error(str(e)) return jsonify(result=False) else: diff = datetime.utcnow() - random_pick.updateTime if diff.seconds < 82800: pass #return jsonify(result=False) averages = dao.query(WinnerAverage).all() winner_data = [(region, getWinnerData(region, api_key)) for region in regions] final_data = [{ 'region': data1[0], 'mode': data2['gameMode'], 'mapName': data2['mapName'], 'kills': data2['kills'], 'damage': data2['damageDealt'], 'distance': data2['walkDistance'] + data2['rideDistance'] } for data1 in winner_data for data2 in data1[1]] map_keys = [('Erangel_Main', 'erangel'), ('Desert_Main', 'miramar'), ('Savage_Main', 'sanhok')] df = pd.DataFrame(final_data) print(df) """ for region_winners in winner_data: for winner in region_winners: for mode in modes: for map_key in map_keys: if winner[1]['gameMode']==mode and winner[1]['mapName']==map_key[0]: average = dao.query(WinnerAverage).\ filter_by(mode=mode).\ filter_by(mapName=map_key[1]).first() """ return jsonify(result=True)
# -*- coding: utf-8 -*- """ pubgi.pubgi_blueprint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Module for pubgi Flask blueprint. :copyright: (c) 2018 by rico0821. """ from flask import Blueprint from pubgi.pubgi_logger import Log pubgi = Blueprint('pubgi', __name__, template_folder='../templates', static_folder='../static') Log.info('static folder: %s' % pubgi.static_folder) Log.info('template folder: %s' % pubgi.template_folder)
def create_app(config_filepath='resource/config.cfg'): """ Create Flask application for pubgi. ARGS: config_filepath """ app = Flask(__name__) # CONFIG from pubgi.pubgi_config import pubgiConfig app.config.from_object(pubgiConfig) app.config.from_pyfile(config_filepath, silent=True) print_settings(app.config.items()) # Initialise Log from pubgi.pubgi_logger import Log log_filepath = os.path.join(app.root_path, app.config['LOG_FILE_PATH']) Log.init(log_filepath=log_filepath) # Load SQLAlchemy DB, Migrate from flask_migrate import Migrate from pubgi.database import DBManager, dao db_filepath = os.path.join(app.root_path, app.config['DB_FILE_PATH']) db_url = app.config['DB_URL'] + db_filepath DBManager.init(db_url, eval(app.config['DB_LOG_FLAG'])) DBManager.init_db() migrate = Migrate(app, dao) # Load MongoDB from pubgi.database import mongo mongo.init_app(app) # Load view functions from pubgi.controller import general from pubgi.controller import map_analysis from pubgi.controller import profile from pubgi.controller import search from pubgi.controller import statistics from pubgi.controller import update # Register blueprint from pubgi.pubgi_blueprint import pubgi app.register_blueprint(pubgi) # Register SessionInterface from pubgi.cache_session import SimpleCacheSessionInterface app.session_interface = SimpleCacheSessionInterface() # Common error handlers app.register_error_handler(404, not_found) app.register_error_handler(500, server_error) # Jinja methods and filters import pubgi.pubgi_jinja as pj app.jinja_env.globals['url_for_other_page'] = pj.url_for_other_page app.jinja_env.filters['translate_mode'] = pj.translate_mode app.jinja_env.filters['translate_map'] = pj.translate_map app.jinja_env.filters['datetimeformat'] = pj.format_datetime app.jinja_env.filters['timesince'] = pj.timesince app.jinja_env.filters['numberformat'] = pj.format_number app.jinja_env.filters['recently_updated'] = pj.recently_updated app.jinja_env.filters['grade'] = pj.grade return app
def search(): """ Search for a player. FORM: search_word, region 1. For each region: i) Check whether PUBG player ID for player with given name and region exists: (a) If so: check whether the player exists in DB. ii) If player is not found in DB: (a) Create new player and stats, append accordingly. (b) Commit. 2. Search DB for players with given name, ignoring case sensitivity. i) If length = 1, return redirect to profile page for that player. 3. Render template for search page, passing in results. """ api_key = current_app.config['API_KEY'] regions = current_app.config['REGIONS'] season = current_app.config['CURRENT_SEASON'] query = request.form['search_word'] region = request.form['region'] query_lower = query.lower() exist = False player_id = getPlayerId(region, query, api_key) if player_id: exist = dao.query(Player).filter_by(pubgID=player_id).\ filter_by(region=region).first() if player_id and not exist: try: new_player = Player(query, player_id, region) new_soloStats = SoloStats(season) new_duoStats = DuoStats(season) new_squadStats = SquadStats(season) dao.add_all( [new_player, new_soloStats, new_duoStats, new_squadStats]) new_player.solo.append(new_soloStats) new_player.duo.append(new_duoStats) new_player.squad.append(new_squadStats) dao.commit() Log.info('New player %r added.' % new_player) except Exception as e: dao.rollback() Log.error(str(e)) raise e results = dao.query(Player).filter(func.lower(Player.name)==query_lower).\ filter_by(region=region).all() if len(results) == 1: player = results[0] return redirect( url_for('.show_profile', player_name=player.name, region=player.region)) return render_template('search.html', results=results, query=query)