@@ -7,6 +7,7 @@ use serde::de::value::StrDeserializer;
77use serde:: { Deserialize , Serialize } ;
88use std:: collections:: BTreeSet ;
99use std:: future:: Future ;
10+ use tokio:: sync:: OnceCell ;
1011use uuid:: Uuid ;
1112
1213pub ( crate ) async fn run (
@@ -27,8 +28,18 @@ pub(crate) async fn run(
2728 print_usage ( ) ;
2829 return Ok ( ( ) ) ;
2930 } ;
30- whitelist_across_categories ( category, |category| whitelist_add ( data, player, category) )
31- . await ?;
31+ let uuid = args. next ( ) . map ( Uuid :: parse_str) . transpose ( ) ?;
32+ whitelist_across_categories ( category, |category| {
33+ whitelist_add (
34+ data,
35+ player,
36+ category,
37+ uuid. map_or_else ( OnceCell :: new, |uuid| {
38+ OnceCell :: new_with ( Some ( ( player. to_owned ( ) , uuid) ) )
39+ } ) ,
40+ )
41+ } )
42+ . await ?;
3243 }
3344 "remove" => {
3445 let Some ( player) = args. next ( ) else {
@@ -104,6 +115,7 @@ async fn whitelist_add(
104115 data : & ProtobotData ,
105116 player_name : & str ,
106117 category : PterodactylServerCategory ,
118+ name_and_uuid : OnceCell < ( String , Uuid ) > ,
107119) -> Result < ( ) , crate :: Error > {
108120 let Some ( mut whitelist) = get_whitelist ( data, category) . await ? else {
109121 return Ok ( ( ) ) ;
@@ -117,44 +129,54 @@ async fn whitelist_add(
117129 return Ok ( ( ) ) ;
118130 }
119131
120- let client = reqwest:: Client :: builder ( )
121- . user_agent ( format ! ( "protobot {}" , git_version!( ) ) )
122- . build ( ) ?;
123- let response = client
124- . post ( "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname" )
125- . header ( "Accept" , "application/json" )
126- . header ( "Content-Type" , "application/json" )
127- . json ( & vec ! [ player_name] )
128- . send ( )
129- . await ?;
130- if !response. status ( ) . is_success ( ) {
131- let status = response. status ( ) ;
132- error ! (
133- "Failed to request UUID: {}, {}" ,
134- status,
135- response. text( ) . await ?
136- ) ;
137- return Ok ( ( ) ) ;
138- }
132+ let ( player_name, player_uuid) = name_and_uuid
133+ . get_or_try_init ( || async {
134+ let client = reqwest:: Client :: builder ( )
135+ . user_agent ( format ! ( "protobot {}" , git_version!( ) ) )
136+ . build ( ) ;
137+ let client = match client {
138+ Ok ( client) => client,
139+ Err ( err) => return Err :: < ( String , Uuid ) , crate :: Error > ( err. into ( ) ) ,
140+ } ;
141+ let response = client
142+ . post ( "https://api.minecraftservices.com/minecraft/profile/lookup/bulk/byname" )
143+ . header ( "Accept" , "application/json" )
144+ . header ( "Content-Type" , "application/json" )
145+ . json ( & vec ! [ player_name] )
146+ . send ( )
147+ . await ?;
139148
140- #[ derive( Deserialize ) ]
141- struct MojangPlayer {
142- id : Uuid ,
143- name : String ,
144- }
149+ if !response. status ( ) . is_success ( ) {
150+ let status = response. status ( ) ;
151+ error ! (
152+ "Failed to request UUID: {}, {}" ,
153+ status,
154+ response. text( ) . await ?
155+ ) ;
156+ return Err ( crate :: Error :: Other ( "failed to request UUID" . into ( ) ) ) ;
157+ }
145158
146- let mojang_players = response. json :: < Vec < MojangPlayer > > ( ) . await ?;
147- if mojang_players. len ( ) != 1 {
148- return Err ( crate :: Error :: Other (
149- "Mojang server didn't return 1 player when requested" . to_owned ( ) ,
150- ) ) ;
151- }
152- let player_uuid = mojang_players[ 0 ] . id ;
153- let player_name: & str = & mojang_players[ 0 ] . name ;
159+ #[ derive( Deserialize ) ]
160+ struct MojangPlayer {
161+ id : Uuid ,
162+ name : String ,
163+ }
164+
165+ let mojang_players = response. json :: < Vec < MojangPlayer > > ( ) . await ?;
166+ if mojang_players. len ( ) != 1 {
167+ return Err ( crate :: Error :: Other (
168+ "Mojang server didn't return 1 player when requested" . to_owned ( ) ,
169+ ) ) ;
170+ }
171+
172+ let player = mojang_players. into_iter ( ) . next ( ) . unwrap ( ) ;
173+ Ok :: < ( String , Uuid ) , crate :: Error > ( ( player. name , player. id ) )
174+ } )
175+ . await ?;
154176
155177 whitelist. push ( Player {
156178 name : player_name. to_owned ( ) ,
157- uuid : player_uuid,
179+ uuid : * player_uuid,
158180 } ) ;
159181 whitelist. sort_by_key ( |player| player. name . to_ascii_lowercase ( ) ) ;
160182
@@ -295,7 +317,7 @@ async fn run_command(
295317}
296318
297319fn print_usage ( ) {
298- info ! ( "(whitelist < add|remove> <player> <category|all>) | (whitelist list <category>)" ) ;
320+ info ! ( "(whitelist add <player> <category|all> [uuid]) | (whitelist remove <player> <category|all>) | (whitelist list <category>)" ) ;
299321}
300322
301323#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Deserialize , Serialize ) ]
0 commit comments