11use miette:: IntoDiagnostic ;
22use moon_cache:: { CacheEngine , cache_item} ;
3- use moon_common:: { consts:: CONFIG_DIRNAME , is_test_env} ;
3+ use moon_common:: { consts:: CONFIG_DIRNAME , is_ci , is_test_env} ;
44use moon_env:: MoonEnvironment ;
55use moon_env_var:: GlobalEnvBag ;
66use moon_time:: now_millis;
77use semver:: Version ;
88use serde:: { Deserialize , Serialize } ;
99use starbase_utils:: { fs, json} ;
10- use std:: env:: { self , consts} ;
10+ use std:: collections:: BTreeMap ;
11+ use std:: env:: consts;
1112use std:: path:: Path ;
13+ use std:: sync:: { Arc , OnceLock } ;
1214use std:: time:: Duration ;
1315use tracing:: { debug, instrument} ;
1416use uuid:: Uuid ;
1517
18+ static INSTANCE : OnceLock < Arc < Launchpad > > = OnceLock :: new ( ) ;
19+
1620const ALERT_PAUSE_DURATION : Duration = Duration :: from_secs ( 43200 ) ; // 12 hours
1721
1822#[ derive( Debug , Default , Deserialize , Serialize ) ]
@@ -30,6 +34,11 @@ cache_item!(
3034 }
3135) ;
3236
37+ #[ derive( Serialize ) ]
38+ pub struct ToolchainUsage {
39+ pub toolchains : BTreeMap < String , String > ,
40+ }
41+
3342fn load_or_create_anonymous_uid ( id_path : & Path ) -> miette:: Result < String > {
3443 if id_path. exists ( ) {
3544 return Ok ( fs:: read_file ( id_path) ?) ;
@@ -60,13 +69,43 @@ pub struct VersionCheck {
6069 pub update_available : bool ,
6170}
6271
63- pub struct Launchpad ;
72+ pub struct Launchpad {
73+ #[ allow( dead_code) ]
74+ moon_env : Arc < MoonEnvironment > ,
75+ moon_version : String ,
76+ user_id : String ,
77+ repo_id : Option < String > ,
78+ }
6479
6580impl Launchpad {
81+ pub fn register ( moon_env : Arc < MoonEnvironment > ) -> miette:: Result < ( ) > {
82+ let user_id = load_or_create_anonymous_uid ( & moon_env. id_file ) ?;
83+
84+ let repo_id = fs:: find_upwards ( CONFIG_DIRNAME , & moon_env. working_dir )
85+ . map ( |dir| create_anonymous_rid ( dir. parent ( ) . unwrap ( ) ) ) ;
86+
87+ let moon_version = GlobalEnvBag :: instance ( )
88+ . get ( "MOON_VERSION" )
89+ . unwrap_or_default ( ) ;
90+
91+ let _ = INSTANCE . set ( Arc :: new ( Self {
92+ moon_env,
93+ moon_version,
94+ user_id,
95+ repo_id,
96+ } ) ) ;
97+
98+ Ok ( ( ) )
99+ }
100+
101+ pub fn instance ( ) -> Arc < Launchpad > {
102+ Arc :: clone ( INSTANCE . get ( ) . unwrap ( ) )
103+ }
104+
66105 #[ instrument( skip_all) ]
67106 pub async fn check_version (
107+ & self ,
68108 cache_engine : & CacheEngine ,
69- moon_env : & MoonEnvironment ,
70109 bypass_cache : bool ,
71110 manifest_url : & str ,
72111 ) -> miette:: Result < Option < VersionCheck > > {
@@ -81,7 +120,7 @@ impl Launchpad {
81120 }
82121 }
83122
84- if let Some ( result) = Self :: check_version_without_cache ( moon_env , manifest_url) . await ? {
123+ if let Some ( result) = self . check_version_without_cache ( manifest_url) . await ? {
85124 state. data . last_check_time = Some ( now) ;
86125 state. data . local_version = Some ( result. local_version . clone ( ) ) ;
87126 state. data . remote_version = Some ( result. remote_version . clone ( ) ) ;
@@ -94,54 +133,33 @@ impl Launchpad {
94133 }
95134
96135 pub async fn check_version_without_cache (
97- moon_env : & MoonEnvironment ,
136+ & self ,
98137 manifest_url : & str ,
99138 ) -> miette:: Result < Option < VersionCheck > > {
100139 if is_test_env ( ) || proto_core:: is_offline ( ) {
101140 return Ok ( None ) ;
102141 }
103142
104- let version = GlobalEnvBag :: instance ( )
105- . get ( "MOON_VERSION" )
106- . unwrap_or_default ( ) ;
143+ let version = & self . moon_version ;
107144
108145 debug ! (
109146 current_version = & version,
110147 manifest_url = manifest_url,
111148 "Checking for a new version of moon"
112149 ) ;
113150
114- let mut client = reqwest:: Client :: new ( )
115- . get ( manifest_url)
116- . header ( "X-Moon-OS" , consts:: OS . to_owned ( ) )
117- . header ( "X-Moon-Arch" , consts:: ARCH . to_owned ( ) )
118- . header ( "X-Moon-Version" , & version)
119- . header ( "X-Moon-CI" , ci_env:: is_ci ( ) . to_string ( ) )
151+ let request = self
152+ . create_request ( manifest_url) ?
120153 . header (
121154 "X-Moon-CI-Provider" ,
122155 format ! ( "{:?}" , ci_env:: detect_provider( ) ) ,
123156 )
124- . header ( "X-Moon-CD" , cd_env:: is_cd ( ) . to_string ( ) )
125157 . header (
126158 "X-Moon-CD-Provider" ,
127159 format ! ( "{:?}" , cd_env:: detect_provider( ) ) ,
128- )
129- . header (
130- "X-Moon-UID" ,
131- load_or_create_anonymous_uid ( & moon_env. id_file ) ?,
132- ) ;
133-
134- if let Some ( moon_dir) = fs:: find_upwards (
135- CONFIG_DIRNAME ,
136- env:: current_dir ( ) . expect ( "Invalid working directory!" ) ,
137- ) {
138- client = client. header (
139- "X-Moon-RID" ,
140- create_anonymous_rid ( moon_dir. parent ( ) . unwrap ( ) ) ,
141160 ) ;
142- }
143161
144- let Ok ( response) = client . send ( ) . await else {
162+ let Ok ( response) = request . send ( ) . await else {
145163 return Ok ( None ) ;
146164 } ;
147165
@@ -150,7 +168,7 @@ impl Launchpad {
150168 } ;
151169
152170 let data: CurrentVersion = json:: parse ( text) ?;
153- let local_version = Version :: parse ( & version) . into_diagnostic ( ) ?;
171+ let local_version = Version :: parse ( version) . into_diagnostic ( ) ?;
154172 let remote_version = Version :: parse ( & data. current_version ) . into_diagnostic ( ) ?;
155173 let update_available = remote_version > local_version;
156174
@@ -168,4 +186,38 @@ impl Launchpad {
168186 update_available,
169187 } ) )
170188 }
189+
190+ pub async fn track_toolchain_usage (
191+ & self ,
192+ toolchains : BTreeMap < String , String > ,
193+ ) -> miette:: Result < ( ) > {
194+ if !is_ci ( ) || is_test_env ( ) || proto_core:: is_offline ( ) {
195+ return Ok ( ( ) ) ;
196+ }
197+
198+ let request = self
199+ . create_request ( "https://launch.moonrepo.app/moon/toolchain_usage" ) ?
200+ . json ( & ToolchainUsage { toolchains } ) ;
201+
202+ let _response = request. send ( ) . await . into_diagnostic ( ) ?;
203+
204+ Ok ( ( ) )
205+ }
206+
207+ fn create_request ( & self , url : & str ) -> miette:: Result < reqwest:: RequestBuilder > {
208+ let mut client = reqwest:: Client :: new ( )
209+ . post ( url)
210+ . header ( "X-Moon-OS" , consts:: OS . to_owned ( ) )
211+ . header ( "X-Moon-Arch" , consts:: ARCH . to_owned ( ) )
212+ . header ( "X-Moon-Version" , self . moon_version . clone ( ) )
213+ . header ( "X-Moon-CI" , ci_env:: is_ci ( ) . to_string ( ) )
214+ . header ( "X-Moon-CD" , cd_env:: is_cd ( ) . to_string ( ) )
215+ . header ( "X-Moon-UID" , self . user_id . clone ( ) ) ;
216+
217+ if let Some ( repo_id) = & self . repo_id {
218+ client = client. header ( "X-Moon-RID" , repo_id. to_owned ( ) ) ;
219+ }
220+
221+ Ok ( client)
222+ }
171223}
0 commit comments