mirror of
https://github.com/MCMi460/3DS-RPC.git
synced 2025-06-18 13:35:34 -04:00
backend: Attempt at reformatting main loop
This reduces complexity in some areas, but heightens it in others.
This commit is contained in:
parent
48d3d212ff
commit
9851c74c26
@ -27,6 +27,23 @@ scrape_only = False
|
||||
|
||||
network: NetworkType = NetworkType.NINTENDO
|
||||
|
||||
class QueriedFriend:
|
||||
""" A QueriedFriend holds the friend code, PID, and last access time for a given Friend. """
|
||||
|
||||
# The friend code of this user, as a string.
|
||||
friend_code: str
|
||||
|
||||
# The principal ID (a.k.a. PID) of this user.
|
||||
pid: int
|
||||
|
||||
# The last access date of this user, per database.
|
||||
last_accessed: int
|
||||
|
||||
def __init__(self, given_friend: Friend):
|
||||
self.friend_code = given_friend.friend_code
|
||||
self.pid = friend_code_to_principal_id(given_friend.friend_code)
|
||||
self.last_accessed = given_friend.last_accessed
|
||||
|
||||
|
||||
async def main():
|
||||
engine = create_engine(get_db_url())
|
||||
@ -40,11 +57,10 @@ async def main():
|
||||
if not queried_friends:
|
||||
continue
|
||||
|
||||
all_friends = [(friend_code_to_principal_id(f.friend_code), f.last_accessed) for f in queried_friends]
|
||||
friend_codes = [ f[0] for f in all_friends ]
|
||||
all_friends: [QueriedFriend] = list(map(QueriedFriend, queried_friends))
|
||||
|
||||
for i in range(0, len(friend_codes), 100):
|
||||
rotation = friend_codes[i:i+100]
|
||||
for i in range(0, len(all_friends), 100):
|
||||
current_rotation = all_friends[i:i+100]
|
||||
|
||||
try:
|
||||
client = nasc.NASCClient()
|
||||
@ -83,9 +99,10 @@ async def main():
|
||||
|
||||
async with backend.connect(s, response.host, response.port) as be:
|
||||
async with be.login(str(PID), NEX_PASSWORD) as client:
|
||||
# Begin!
|
||||
friends_client = friends.FriendsClientV1(client)
|
||||
await main_friends_loop(friends_client, session, all_friends, rotation)
|
||||
|
||||
# Begin our main loop!
|
||||
await main_friends_loop(friends_client, session, current_rotation)
|
||||
|
||||
except Exception as e:
|
||||
print('An error occurred!\n%s' % e)
|
||||
@ -97,163 +114,169 @@ async def main():
|
||||
break
|
||||
|
||||
|
||||
async def main_friends_loop(friends_client: friends.FriendsClientV1, session: Session, all_friends, rotation: [str]):
|
||||
async def main_friends_loop(friends_client: friends.FriendsClientV1, session: Session, current_rotation: list[QueriedFriend]):
|
||||
# If we recently started, update our comment, and remove existing friends.
|
||||
if time.time() - backend_start_time < 30:
|
||||
time.sleep(delay)
|
||||
await friends_client.update_comment('3dsrpc.com')
|
||||
|
||||
time.sleep(delay)
|
||||
print('Cleaning out to zero')
|
||||
print('Cleaning friends list out from previous runs...')
|
||||
removables = await friends_client.get_all_friends()
|
||||
for friend in removables:
|
||||
time.sleep(delay / quicker)
|
||||
await friends_client.remove_friend_by_principal_id(friend.pid)
|
||||
print('Removed %s friends' % str(len(removables)))
|
||||
|
||||
removal_list = []
|
||||
cleanUp = []
|
||||
|
||||
# Add our current roster of friends.
|
||||
#
|
||||
# The add_friend_by_principal_ids method is not yet
|
||||
# implemented on Pretendo, so this is a fix for now.
|
||||
# implemented on Pretendo, so this is a hotfix for now.
|
||||
all_friend_pids: list[int] = [ f.pid for f in current_rotation ]
|
||||
if network == NetworkType.PRETENDO:
|
||||
for friend_pid in rotation:
|
||||
for friend_pid in all_friend_pids:
|
||||
time.sleep(delay / quicker)
|
||||
await friends_client.add_friend_by_principal_id(0, friend_pid)
|
||||
else:
|
||||
time.sleep(delay)
|
||||
await friends_client.add_friend_by_principal_ids(0, rotation)
|
||||
await friends_client.add_friend_by_principal_ids(0, all_friend_pids)
|
||||
|
||||
time.sleep(delay)
|
||||
# Query all successful friends.
|
||||
current_friends_list: [friends.FriendRelationship] = await friends_client.get_all_friends()
|
||||
current_friend_pids: [int] = [ f.pid for f in current_friends_list ]
|
||||
|
||||
# Determine which remote friends failed to add, and thus have unfriended us.
|
||||
network_friends = await friends_client.get_all_friends()
|
||||
if len(network_friends) < len(rotation):
|
||||
for current_pid in rotation:
|
||||
if current_pid not in [ f.pid for f in network_friends ]:
|
||||
removal_list.append(current_pid)
|
||||
added_friends: [QueriedFriend] = []
|
||||
for current_friend in current_rotation:
|
||||
current_pid = current_friend.pid
|
||||
|
||||
# Keep track of which current friends are within our current rotation.
|
||||
# We'll remove them once game presences are updated.
|
||||
x = network_friends
|
||||
network_friends = []
|
||||
for t1 in x:
|
||||
if t1.pid in rotation:
|
||||
network_friends.append(t1)
|
||||
else:
|
||||
cleanUp.append(t1.pid)
|
||||
|
||||
for removed_friend in removal_list:
|
||||
removed_friend_code = str(principal_id_to_friend_code(removed_friend)).zfill(12)
|
||||
if current_pid in current_friend_pids:
|
||||
added_friends.append(current_friend)
|
||||
continue
|
||||
|
||||
# This user must have removed us.
|
||||
# Remove this friend code from both our tracked network friends and Discord friend codes.
|
||||
session.execute(delete(Friend).where(Friend.friend_code == removed_friend_code).where(Friend.network == network))
|
||||
session.execute(delete(Friend).where(Friend.friend_code == current_friend.friend_code).where(Friend.network == network))
|
||||
session.execute(delete(DiscordFriends).where(
|
||||
DiscordFriends.friend_code == removed_friend_code,
|
||||
DiscordFriends.friend_code == current_friend.friend_code,
|
||||
DiscordFriends.network == network)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
if len(network_friends) > 0:
|
||||
if len(added_friends) == 0:
|
||||
# All of our friends removed us, so there's no more work to be done.
|
||||
return
|
||||
|
||||
time.sleep(delay)
|
||||
|
||||
# Query the presences of all of our added friends.
|
||||
# Only online users will have their presence returned.
|
||||
tracked_presences: [friends.FriendPresence] = await friends_client.get_friend_presence(current_friend_pids)
|
||||
online_user_pids: [int] = []
|
||||
|
||||
for game in tracked_presences:
|
||||
# Set all to offline if scraping
|
||||
if scrape_only:
|
||||
break
|
||||
|
||||
online_user_pids.append(game.pid)
|
||||
game_description = game.presence.game_mode_description
|
||||
if not game_description:
|
||||
game_description = ''
|
||||
joinable = bool(game.presence.join_availability_flag)
|
||||
|
||||
friend_code = str(principal_id_to_friend_code(game.pid)).zfill(12)
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
online=True,
|
||||
title_id=game.presence.game_key.title_id,
|
||||
upd_id=game.presence.game_key.title_version,
|
||||
joinable=joinable,
|
||||
game_description=game_description,
|
||||
last_online=time.time()
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
# Otherwise, if we have no presence data, this user must be offline.
|
||||
for offline_user in [ h for h in current_friend_pids if not h in online_user_pids ]:
|
||||
friend_code = str(principal_id_to_friend_code(offline_user)).zfill(12)
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
online=False,
|
||||
title_id=0,
|
||||
upd_id=0
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
# Lastly, update all added friend comments, usernames, etc.
|
||||
for current_friend in added_friends:
|
||||
# As this is a time-heavy task, only update if necessary.
|
||||
work = False
|
||||
if time.time() - current_friend.last_accessed <= 600000 or scrape_only:
|
||||
work = True
|
||||
|
||||
if not work:
|
||||
continue
|
||||
|
||||
time.sleep(delay)
|
||||
tracked_presences = await friends_client.get_friend_presence([ e.pid for e in network_friends ])
|
||||
online_users = []
|
||||
for game in tracked_presences:
|
||||
# Set all to offline if scraping
|
||||
if scrape_only:
|
||||
break
|
||||
|
||||
online_users.append(game.pid)
|
||||
game_description = game.presence.game_mode_description
|
||||
if not game_description:
|
||||
game_description = ''
|
||||
joinable = bool(game.presence.join_availability_flag)
|
||||
try:
|
||||
current_info = await friends_client.get_friend_persistent_info([current_friend.pid,])
|
||||
except:
|
||||
continue
|
||||
comment = current_info[0].message
|
||||
favorite_game = 0
|
||||
username = ''
|
||||
face = ''
|
||||
if not comment.endswith(' '):
|
||||
# TODO(MCMi460): I just do not understand what I'm doing wrong with get_friend_mii_list.
|
||||
# The docs do not specify much about usage or parameters.
|
||||
# And no matter how many trials I do with varying inputs, nothing works - they all return Core::BufferOverflow.
|
||||
# I will not give up, but until I figure it out, the slower method (get_friend_mii)
|
||||
# will have to do.
|
||||
#
|
||||
# Get user's mii + username from mii
|
||||
|
||||
friend_code = str(principal_id_to_friend_code(game.pid)).zfill(12)
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
online=True,
|
||||
title_id=game.presence.game_key.title_id,
|
||||
upd_id=game.presence.game_key.title_version,
|
||||
joinable=joinable,
|
||||
game_description=game_description,
|
||||
last_online=time.time()
|
||||
)
|
||||
# TODO(spotlightishere): This is a mess. Why does `friend_code = 0` prevent a conversion error?
|
||||
queried_relationship = [r for r in current_friends_list if r.pid == current_friend.pid][0]
|
||||
queried_relationship.friend_code = 0
|
||||
|
||||
user_mii: [friends.FriendMii] = await friends_client.get_friend_mii([queried_relationship,])
|
||||
username = user_mii[0].mii.name
|
||||
mii_data = user_mii[0].mii.mii_data
|
||||
obj = MiiData()
|
||||
obj.decode(obj.convert(io.BytesIO(mii_data)))
|
||||
face = obj.mii_studio()['data']
|
||||
|
||||
# Get user's favorite game
|
||||
favorite_game = current_info[0].game_key.title_id
|
||||
else:
|
||||
comment = ''
|
||||
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == current_friend.friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
username=username,
|
||||
message=comment,
|
||||
mii=face,
|
||||
favorite_game=favorite_game
|
||||
)
|
||||
session.commit()
|
||||
)
|
||||
session.commit()
|
||||
|
||||
for offline_user in [ h for h in rotation if not h in online_users ]:
|
||||
friend_code = str(principal_id_to_friend_code(offline_user)).zfill(12)
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
online=False,
|
||||
title_id=0,
|
||||
upd_id=0
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
# I just do not understand what I'm doing wrong with get_friend_mii_list
|
||||
# The docs do not specify much
|
||||
# And no matter how many trials I do with varying inputs, nothing works
|
||||
# I do not give up, but until I figure it out, the slower method (get_friend_mii)
|
||||
# will have to do.
|
||||
|
||||
for current_friend in network_friends:
|
||||
work = False
|
||||
for l in all_friends:
|
||||
if (l[0] == current_friend.pid and time.time() - l[1] <= 600000) or scrape_only:
|
||||
work = True
|
||||
if not work:
|
||||
continue
|
||||
|
||||
time.sleep(delay)
|
||||
|
||||
current_friend.friend_code = 0 # A cursed (but operable) 'hack'
|
||||
try:
|
||||
current_info = await friends_client.get_friend_persistent_info([current_friend.pid,])
|
||||
except:
|
||||
continue
|
||||
comment = current_info[0].message
|
||||
favorite_game = 0
|
||||
username = ''
|
||||
face = ''
|
||||
if not comment.endswith(' '):
|
||||
# Get user's mii + username from mii
|
||||
m = await friends_client.get_friend_mii([current_friend,])
|
||||
username = m[0].mii.name
|
||||
mii_data = m[0].mii.mii_data
|
||||
obj = MiiData()
|
||||
obj.decode(obj.convert(io.BytesIO(mii_data)))
|
||||
face = obj.mii_studio()['data']
|
||||
|
||||
# Get user's favorite game
|
||||
favorite_game = current_info[0].game_key.title_id
|
||||
else:
|
||||
comment = ''
|
||||
|
||||
friend_code = str(principal_id_to_friend_code(current_friend.pid)).zfill(12)
|
||||
session.execute(
|
||||
update(Friend)
|
||||
.where(Friend.friend_code == friend_code)
|
||||
.where(Friend.network == network)
|
||||
.values(
|
||||
username=username,
|
||||
message=comment,
|
||||
mii=face,
|
||||
favorite_game=favorite_game
|
||||
)
|
||||
)
|
||||
session.commit()
|
||||
|
||||
for friend in rotation + cleanUp:
|
||||
# Lastly, remove all of our added friends.
|
||||
for friend in added_friends:
|
||||
time.sleep(delay / quicker)
|
||||
await friends_client.remove_friend_by_principal_id(friend)
|
||||
await friends_client.remove_friend_by_principal_id(friend.pid)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Loading…
Reference in New Issue
Block a user