1- use anyhow:: { Context , Result } ;
1+ use anyhow:: { ensure , Context , Result } ;
22use clap:: Parser ;
33use console:: Term ;
44use tokio:: fs;
@@ -7,131 +7,173 @@ use crate::util::term;
77
88#[ derive( Parser ) ]
99pub enum SubCommand {
10- Init ,
10+ Init ( InitOpts ) ,
11+ }
12+
13+ #[ derive( Parser ) ]
14+ pub struct InitOpts {
15+ #[ clap( long) ]
16+ dev_hostname : Option < String > ,
17+ #[ clap( long) ]
18+ dev_port : Option < Vec < String > > ,
19+ #[ clap( long) ]
20+ dev_env : bool ,
1121}
1222
1323impl SubCommand {
1424 pub async fn execute ( & self , term : & Term , ctx : & cli_core:: Ctx ) -> Result < ( ) > {
1525 match self {
16- SubCommand :: Init => {
17- let game_res = ctx
18- . client ( )
19- . get_game_by_id ( )
20- . game_id ( & ctx. game_id )
21- . send ( )
22- . await
23- . context ( "client.get_game_by_id" ) ?;
24- let game = game_res. game . context ( "game_res.game" ) ?;
25- let game_ns = game. namespaces ( ) . context ( "game.namespaces" ) ?;
26- let prod_namespace_id = game_ns
27- . iter ( )
28- . find ( |x| x. name_id ( ) . map_or ( false , |x| x == "prod" ) )
29- . and_then ( |x| x. namespace_id ( ) )
30- . context ( "game.namespaces.find(\" prod\" ).namespace_id" ) ?;
26+ SubCommand :: Init ( opts) => opts. execute ( term, ctx) . await ,
27+ }
28+ }
29+ }
30+
31+ impl InitOpts {
32+ pub async fn execute ( & self , term : & Term , ctx : & cli_core:: Ctx ) -> Result < ( ) > {
33+ let game_res = ctx
34+ . client ( )
35+ . get_game_by_id ( )
36+ . game_id ( & ctx. game_id )
37+ . send ( )
38+ . await
39+ . context ( "client.get_game_by_id" ) ?;
40+ let game = game_res. game . context ( "game_res.game" ) ?;
41+ let game_ns = game. namespaces ( ) . context ( "game.namespaces" ) ?;
42+ let prod_namespace_id = game_ns
43+ . iter ( )
44+ . find ( |x| x. name_id ( ) . map_or ( false , |x| x == "prod" ) )
45+ . and_then ( |x| x. namespace_id ( ) )
46+ . context ( "game.namespaces.find(\" prod\" ).namespace_id" ) ?;
47+
48+ eprintln ! ( ) ;
49+ let hostname = if let Some ( x) = self . dev_hostname . clone ( ) {
50+ x
51+ } else {
52+ term:: input:: string_with_tip ( term, "Dev hostname?" , "example: 127.0.0.1" ) . await ?
53+ } ;
3154
55+ let mut default_port = Option :: < u16 > :: None ;
56+ let mut lobby_ports = Vec :: new ( ) ;
57+ if let Some ( dev_ports) = & self . dev_port {
58+ for port in dev_ports {
59+ let port_components = port. split ( ":" ) . collect :: < Vec < _ > > ( ) ;
60+ ensure ! (
61+ port_components. len( ) == 3 ,
62+ "port must have 3 components: `{{label}}:{{proto}}:{{port}}`"
63+ ) ;
64+ let label = port_components[ 0 ] ;
65+ let proto =
66+ parse_proxy_proto ( port_components[ 1 ] ) . context ( "inalid proxy protocol" ) ?;
67+ let port = port_components[ 2 ]
68+ . parse :: < u16 > ( )
69+ . context ( "port is not valid number" ) ?;
70+
71+ if default_port. is_none ( ) {
72+ default_port = Some ( port) ;
73+ }
74+ lobby_ports. push (
75+ cli_core:: rivet_cloud:: model:: LobbyGroupRuntimeDockerPort :: builder ( )
76+ . label ( label)
77+ . target_port ( port as i32 )
78+ . proxy_protocol ( proto. clone ( ) )
79+ . build ( ) ,
80+ ) ;
81+ }
82+ } else {
83+ loop {
3284 eprintln ! ( ) ;
33- let hostname =
34- term:: input:: string_with_tip ( term, "Dev hostname?" , "example: 127.0.0.1" )
35- . await ?;
36-
37- let mut default_port = Option :: < u16 > :: None ;
38- let mut lobby_ports = Vec :: new ( ) ;
39- loop {
40- eprintln ! ( ) ;
41-
42- let port = ' port: loop {
43- let port = term:: input:: string_with_tip (
44- term,
45- "Dev port?" ,
46- "0-65535, example: 8080" ,
47- )
48- . await ?;
49- if let Ok ( port) = port. parse :: < u16 > ( ) {
50- break ' port port;
51- } else {
52- term:: status:: error ( "Invalid port number" , "" ) ;
53- eprintln ! ( ) ;
54- }
55- } ;
56- if default_port. is_none ( ) {
57- default_port = Some ( port) ;
85+
86+ let port = ' port: loop {
87+ let port =
88+ term:: input:: string_with_tip ( term, "Dev port?" , "0-65535, example: 8080" )
89+ . await ?;
90+ if let Ok ( port) = port. parse :: < u16 > ( ) {
91+ break ' port port;
92+ } else {
93+ term:: status:: error ( "Invalid port number" , "" ) ;
94+ eprintln ! ( ) ;
5895 }
96+ } ;
97+ if default_port. is_none ( ) {
98+ default_port = Some ( port) ;
99+ }
59100
60- let proto = ' proto: loop {
61- let proto = term:: input:: string_with_tip (
62- term,
63- "Dev port protocol?" ,
64- "http/https, usually: http" ,
65- )
66- . await ?;
67- match proto. to_lowercase ( ) . as_str ( ) {
68- "http" => {
69- break ' proto cli_core:: rivet_cloud:: model:: ProxyProtocol :: Http ;
70- }
71- "https" => {
72- break ' proto cli_core:: rivet_cloud:: model:: ProxyProtocol :: Https ;
73- }
74- _ => {
75- term:: status:: error ( "Invalid protocol" , "" ) ;
76- eprintln ! ( ) ;
77- }
78- }
79- } ;
80-
81- let label = term:: input:: string_with_tip (
101+ let proto = ' proto: loop {
102+ let proto = term:: input:: string_with_tip (
82103 term,
83- "Development port label ?" ,
84- "example: default " ,
104+ "Dev port protocol ?" ,
105+ "http/https, usually: http " ,
85106 )
86107 . await ?;
87-
88- lobby_ports. push (
89- cli_core:: rivet_cloud:: model:: LobbyGroupRuntimeDockerPort :: builder ( )
90- . label ( & label)
91- . target_port ( port as i32 )
92- . proxy_protocol ( proto. clone ( ) )
93- . build ( ) ,
94- ) ;
95-
96- term:: status:: success (
97- format ! ( "Added {label}" ) ,
98- format ! ( "port={port} proto={proto:?}" ) ,
99- ) ;
100-
101- if !term:: input:: bool ( term, "Add another port?" ) . await ? {
102- break ;
108+ if let Some ( proto) = parse_proxy_proto ( & proto) {
109+ break ' proto proto;
110+ } else {
111+ term:: status:: error ( "Invalid protocol" , "" ) ;
112+ eprintln ! ( ) ;
103113 }
104- }
114+ } ;
105115
106- let token_res = ctx
107- . client ( )
108- . create_game_namespace_token_development ( )
109- . game_id ( & ctx. game_id )
110- . namespace_id ( prod_namespace_id)
111- . hostname ( hostname)
112- . set_lobby_ports ( Some ( lobby_ports) )
113- . send ( )
114- . await
115- . context ( "client.create_game_namespace_token_development" ) ?;
116- let token = token_res. token ( ) . context ( "token_res.token" ) ?;
116+ let label = term:: input:: string_with_tip (
117+ term,
118+ "Development port label?" ,
119+ "example: default" ,
120+ )
121+ . await ?;
117122
118- eprintln ! ( ) ;
119- term:: status:: success ( format ! ( "Token created" ) , "" ) ;
123+ lobby_ports. push (
124+ cli_core:: rivet_cloud:: model:: LobbyGroupRuntimeDockerPort :: builder ( )
125+ . label ( & label)
126+ . target_port ( port as i32 )
127+ . proxy_protocol ( proto. clone ( ) )
128+ . build ( ) ,
129+ ) ;
120130
121- eprintln ! ( ) ;
122- if term:: input:: bool ( term, "Write token to .env file?" ) . await ? {
123- let env_file = format ! (
124- "PORT={port}\n RIVET_TOKEN={token}\n " ,
125- port = default_port. unwrap( )
126- ) ;
127- fs:: write ( ".env" , env_file) . await ?;
128- term:: status:: success ( format ! ( "Wrote to .env" ) , "" ) ;
129- } else {
130- println ! ( "{token}" ) ;
131- }
131+ term:: status:: success (
132+ format ! ( "Added {label}" ) ,
133+ format ! ( "port={port} proto={proto:?}" ) ,
134+ ) ;
132135
133- Ok ( ( ) )
136+ if !term:: input:: bool ( term, "Add another port?" ) . await ? {
137+ break ;
138+ }
134139 }
135140 }
141+
142+ let token_res = ctx
143+ . client ( )
144+ . create_game_namespace_token_development ( )
145+ . game_id ( & ctx. game_id )
146+ . namespace_id ( prod_namespace_id)
147+ . hostname ( hostname)
148+ . set_lobby_ports ( Some ( lobby_ports) )
149+ . send ( )
150+ . await
151+ . context ( "client.create_game_namespace_token_development" ) ?;
152+ let token = token_res. token ( ) . context ( "token_res.token" ) ?;
153+
154+ eprintln ! ( ) ;
155+ term:: status:: success ( format ! ( "Token created" ) , "" ) ;
156+
157+ eprintln ! ( ) ;
158+ if self . dev_env || term:: input:: bool ( term, "Write token to .env file?" ) . await ? {
159+ let env_file = format ! (
160+ "PORT={port}\n RIVET_TOKEN={token}\n " ,
161+ port = default_port. unwrap( )
162+ ) ;
163+ fs:: write ( ".env" , env_file) . await ?;
164+ term:: status:: success ( format ! ( "Wrote to .env" ) , "" ) ;
165+ } else {
166+ println ! ( "{token}" ) ;
167+ }
168+
169+ Ok ( ( ) )
170+ }
171+ }
172+
173+ fn parse_proxy_proto ( proto : & str ) -> Option < cli_core:: rivet_cloud:: model:: ProxyProtocol > {
174+ match proto. to_lowercase ( ) . as_str ( ) {
175+ "http" => Some ( cli_core:: rivet_cloud:: model:: ProxyProtocol :: Http ) ,
176+ "https" => Some ( cli_core:: rivet_cloud:: model:: ProxyProtocol :: Https ) ,
177+ _ => None ,
136178 }
137179}
0 commit comments