(config: Config, args: &ArgMatches)
| 149 | } |
| 150 | |
| 151 | pub async fn exec(config: Config, args: &ArgMatches) -> Result<(), anyhow::Error> { |
| 152 | eprintln!("{UNSTABLE_WARNING}\n"); |
| 153 | |
| 154 | let server = args.get_one::<String>("server").map(|s| s.as_ref()); |
| 155 | let force = args.get_flag("force"); |
| 156 | let anon_identity = args.get_flag("anon_identity"); |
| 157 | let no_config = args.get_flag("no_config"); |
| 158 | |
| 159 | let raw_parts: Vec<String> = args |
| 160 | .get_many::<String>("subscribe_parts") |
| 161 | .map(|vals| vals.cloned().collect()) |
| 162 | .unwrap_or_default(); |
| 163 | let config_targets = load_config_db_targets(no_config)?; |
| 164 | let resolved = resolve_optional_database_parts( |
| 165 | &raw_parts, |
| 166 | config_targets.as_deref(), |
| 167 | "query", |
| 168 | "spacetime subscribe [database] <query> [query...] (or --no-config for legacy behavior)", |
| 169 | )?; |
| 170 | let queries: Vec<String> = resolved.remaining_args; |
| 171 | |
| 172 | let num = args.get_one::<u32>("num-updates").copied(); |
| 173 | let timeout = args.get_one::<u32>("timeout").copied(); |
| 174 | let print_initial_update = args.get_flag("print_initial_update"); |
| 175 | let confirmed = args.get_one::<bool>("confirmed").copied(); |
| 176 | let resolved_server = server.or(resolved.server.as_deref()); |
| 177 | |
| 178 | let mut config = config; |
| 179 | let conn = crate::api::Connection { |
| 180 | host: config.get_host_url(resolved_server)?, |
| 181 | auth_header: get_auth_header(&mut config, anon_identity, resolved_server, !force).await?, |
| 182 | database_identity: database_identity(&config, &resolved.database, resolved_server).await?, |
| 183 | database: resolved.database.clone(), |
| 184 | }; |
| 185 | let api = ClientApi::new(conn); |
| 186 | let module_def = api.module_def().await?; |
| 187 | let mut conn = connect_with_fallback(&api, confirmed).await?; |
| 188 | let num_received = UpdateCounter::new(); |
| 189 | |
| 190 | let task = async { |
| 191 | conn.subscribe(queries.iter().cloned().map(Into::into).collect()) |
| 192 | .await?; |
| 193 | conn.await_initial_update(print_initial_update.then_some(&module_def)) |
| 194 | .await?; |
| 195 | conn.consume_transaction_updates(num, &module_def, &num_received).await |
| 196 | }; |
| 197 | |
| 198 | let res = if let Some(timeout) = timeout { |
| 199 | let timeout = Duration::from_secs(timeout.into()); |
| 200 | match tokio::time::timeout(timeout, task).await { |
| 201 | Ok(res) => res, |
| 202 | Err(_elapsed) => { |
| 203 | let received = num_received.get(); |
| 204 | eprintln!("timed out after {}s", timeout.as_secs()); |
| 205 | match num { |
| 206 | Some(expected) if received < expected => Err(Error::UpdateLimitTimedOut { |
| 207 | expected, |
| 208 | received, |
nothing calls this directly
no test coverage detected
searching dependent graphs…