Merge branch 'main' into request-to-join-project
This commit is contained in:
commit
225536accc
59 changed files with 3330 additions and 7719 deletions
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
|||
|
||||
use super::db::{self, UserId};
|
||||
use crate::{AppState, Error};
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use axum::{
|
||||
http::{self, Request, StatusCode},
|
||||
middleware::Next,
|
||||
|
@ -51,7 +51,12 @@ pub async fn validate_header<B>(mut req: Request<B>, next: Next<B>) -> impl Into
|
|||
}
|
||||
|
||||
if credentials_valid {
|
||||
req.extensions_mut().insert(user_id);
|
||||
let user = state
|
||||
.db
|
||||
.get_user_by_id(user_id)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("user {} not found", user_id))?;
|
||||
req.extensions_mut().insert(user);
|
||||
Ok::<_, Error>(next.run(req).await)
|
||||
} else {
|
||||
Err(Error::Http(
|
||||
|
|
|
@ -11,7 +11,9 @@ use std::{
|
|||
net::{SocketAddr, TcpListener},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::metadata::LevelFilter;
|
||||
use tracing_log::LogTracer;
|
||||
use tracing_subscriber::filter::EnvFilter;
|
||||
use util::ResultExt;
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
pub struct Config {
|
||||
|
@ -20,7 +22,7 @@ pub struct Config {
|
|||
pub api_token: String,
|
||||
pub honeycomb_api_key: Option<String>,
|
||||
pub honeycomb_dataset: Option<String>,
|
||||
pub trace_level: Option<String>,
|
||||
pub rust_log: Option<String>,
|
||||
}
|
||||
|
||||
pub struct AppState {
|
||||
|
@ -41,10 +43,8 @@ impl AppState {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
if let Err(error) = env::load_dotenv() {
|
||||
log::error!(
|
||||
eprintln!(
|
||||
"error loading .env.toml (this is expected in production): {}",
|
||||
error
|
||||
);
|
||||
|
@ -119,42 +119,44 @@ pub fn init_tracing(config: &Config) -> Option<()> {
|
|||
use std::str::FromStr;
|
||||
use tracing_opentelemetry::OpenTelemetryLayer;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
let rust_log = config.rust_log.clone()?;
|
||||
|
||||
let (honeycomb_api_key, honeycomb_dataset) = config
|
||||
LogTracer::init().log_err()?;
|
||||
|
||||
let open_telemetry_layer = config
|
||||
.honeycomb_api_key
|
||||
.clone()
|
||||
.zip(config.honeycomb_dataset.clone())?;
|
||||
.zip(config.honeycomb_dataset.clone())
|
||||
.map(|(honeycomb_api_key, honeycomb_dataset)| {
|
||||
let mut metadata = tonic::metadata::MetadataMap::new();
|
||||
metadata.insert("x-honeycomb-team", honeycomb_api_key.parse().unwrap());
|
||||
let tracer = opentelemetry_otlp::new_pipeline()
|
||||
.tracing()
|
||||
.with_exporter(
|
||||
opentelemetry_otlp::new_exporter()
|
||||
.tonic()
|
||||
.with_endpoint("https://api.honeycomb.io")
|
||||
.with_metadata(metadata),
|
||||
)
|
||||
.with_trace_config(opentelemetry::sdk::trace::config().with_resource(
|
||||
opentelemetry::sdk::Resource::new(vec![KeyValue::new(
|
||||
"service.name",
|
||||
honeycomb_dataset,
|
||||
)]),
|
||||
))
|
||||
.install_batch(opentelemetry::runtime::Tokio)
|
||||
.expect("failed to initialize tracing");
|
||||
|
||||
let mut metadata = tonic::metadata::MetadataMap::new();
|
||||
metadata.insert("x-honeycomb-team", honeycomb_api_key.parse().unwrap());
|
||||
let tracer = opentelemetry_otlp::new_pipeline()
|
||||
.tracing()
|
||||
.with_exporter(
|
||||
opentelemetry_otlp::new_exporter()
|
||||
.tonic()
|
||||
.with_endpoint("https://api.honeycomb.io")
|
||||
.with_metadata(metadata),
|
||||
)
|
||||
.with_trace_config(opentelemetry::sdk::trace::config().with_resource(
|
||||
opentelemetry::sdk::Resource::new(vec![KeyValue::new(
|
||||
"service.name",
|
||||
honeycomb_dataset,
|
||||
)]),
|
||||
))
|
||||
.install_batch(opentelemetry::runtime::Tokio)
|
||||
.expect("failed to initialize tracing");
|
||||
OpenTelemetryLayer::new(tracer)
|
||||
});
|
||||
|
||||
let subscriber = tracing_subscriber::Registry::default()
|
||||
.with(OpenTelemetryLayer::new(tracer))
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.with(open_telemetry_layer)
|
||||
.with(
|
||||
config
|
||||
.trace_level
|
||||
.as_ref()
|
||||
.map_or(LevelFilter::INFO, |level| {
|
||||
LevelFilter::from_str(level).unwrap()
|
||||
}),
|
||||
);
|
||||
tracing_subscriber::fmt::layer()
|
||||
.event_format(tracing_subscriber::fmt::format().pretty()),
|
||||
)
|
||||
.with(EnvFilter::from_str(rust_log.as_str()).log_err()?);
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ mod store;
|
|||
|
||||
use crate::{
|
||||
auth,
|
||||
db::{self, ChannelId, MessageId, UserId},
|
||||
db::{self, ChannelId, MessageId, User, UserId},
|
||||
AppState, Result,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
|
@ -49,7 +49,7 @@ use tokio::{
|
|||
time::Sleep,
|
||||
};
|
||||
use tower::ServiceBuilder;
|
||||
use tracing::{info_span, Instrument};
|
||||
use tracing::{info_span, instrument, Instrument};
|
||||
|
||||
type MessageHandler =
|
||||
Box<dyn Send + Sync + Fn(Arc<Server>, Box<dyn AnyTypedEnvelope>) -> BoxFuture<'static, ()>>;
|
||||
|
@ -248,12 +248,14 @@ impl Server {
|
|||
self: &Arc<Self>,
|
||||
connection: Connection,
|
||||
address: String,
|
||||
user_id: UserId,
|
||||
user: User,
|
||||
mut send_connection_id: Option<mpsc::Sender<ConnectionId>>,
|
||||
executor: E,
|
||||
) -> impl Future<Output = Result<()>> {
|
||||
let mut this = self.clone();
|
||||
let span = info_span!("handle connection", %user_id, %address);
|
||||
let user_id = user.id;
|
||||
let login = user.github_login;
|
||||
let span = info_span!("handle connection", %user_id, %login, %address);
|
||||
async move {
|
||||
let (connection_id, handle_io, mut incoming_rx) = this
|
||||
.peer
|
||||
|
@ -268,7 +270,7 @@ impl Server {
|
|||
})
|
||||
.await;
|
||||
|
||||
tracing::info!(%user_id, %connection_id, %address, "connection opened");
|
||||
tracing::info!(%user_id, %login, %connection_id, %address, "connection opened");
|
||||
|
||||
if let Some(send_connection_id) = send_connection_id.as_mut() {
|
||||
let _ = send_connection_id.send(connection_id).await;
|
||||
|
@ -291,14 +293,14 @@ impl Server {
|
|||
futures::select_biased! {
|
||||
result = handle_io => {
|
||||
if let Err(error) = result {
|
||||
tracing::error!(%error, "error handling I/O");
|
||||
tracing::error!(?error, %user_id, %login, %connection_id, %address, "error handling I/O");
|
||||
}
|
||||
break;
|
||||
}
|
||||
message = next_message => {
|
||||
if let Some(message) = message {
|
||||
let type_name = message.payload_type_name();
|
||||
let span = tracing::info_span!("receive message", %user_id, %connection_id, %address, type_name);
|
||||
let span = tracing::info_span!("receive message", %user_id, %login, %connection_id, %address, type_name);
|
||||
async {
|
||||
if let Some(handler) = this.handlers.get(&message.payload_type_id()) {
|
||||
let notifications = this.notifications.clone();
|
||||
|
@ -316,25 +318,27 @@ impl Server {
|
|||
handle_message.await;
|
||||
}
|
||||
} else {
|
||||
tracing::error!("no message handler");
|
||||
tracing::error!(%user_id, %login, %connection_id, %address, "no message handler");
|
||||
}
|
||||
}.instrument(span).await;
|
||||
} else {
|
||||
tracing::info!(%user_id, %connection_id, %address, "connection closed");
|
||||
tracing::info!(%user_id, %login, %connection_id, %address, "connection closed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!(%user_id, %login, %connection_id, %address, "signing out");
|
||||
if let Err(error) = this.sign_out(connection_id).await {
|
||||
tracing::error!(%error, "error signing out");
|
||||
tracing::error!(%user_id, %login, %connection_id, %address, ?error, "error signing out");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}.instrument(span)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), err)]
|
||||
async fn sign_out(self: &mut Arc<Self>, connection_id: ConnectionId) -> Result<()> {
|
||||
self.peer.disconnect(connection_id);
|
||||
|
||||
|
@ -1528,7 +1532,7 @@ pub async fn handle_websocket_request(
|
|||
TypedHeader(ProtocolVersion(protocol_version)): TypedHeader<ProtocolVersion>,
|
||||
ConnectInfo(socket_address): ConnectInfo<SocketAddr>,
|
||||
Extension(server): Extension<Arc<Server>>,
|
||||
Extension(user_id): Extension<UserId>,
|
||||
Extension(user): Extension<User>,
|
||||
ws: WebSocketUpgrade,
|
||||
) -> axum::response::Response {
|
||||
if protocol_version != rpc::PROTOCOL_VERSION {
|
||||
|
@ -1548,7 +1552,7 @@ pub async fn handle_websocket_request(
|
|||
let connection = Connection::new(Box::pin(socket));
|
||||
async move {
|
||||
server
|
||||
.handle_connection(connection, socket_address, user_id, None, RealExecutor)
|
||||
.handle_connection(connection, socket_address, user, None, RealExecutor)
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
|
@ -3239,7 +3243,7 @@ mod tests {
|
|||
|
||||
// Type a completion trigger character as the guest.
|
||||
editor_b.update(cx_b, |editor, cx| {
|
||||
editor.select_ranges([13..13], None, cx);
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
|
||||
editor.handle_input(&Input(".".into()), cx);
|
||||
cx.focus(&editor_b);
|
||||
});
|
||||
|
@ -4350,7 +4354,9 @@ mod tests {
|
|||
|
||||
// Move cursor to a location that contains code actions.
|
||||
editor_b.update(cx_b, |editor, cx| {
|
||||
editor.select_ranges([Point::new(1, 31)..Point::new(1, 31)], None, cx);
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.select_ranges([Point::new(1, 31)..Point::new(1, 31)])
|
||||
});
|
||||
cx.focus(&editor_b);
|
||||
});
|
||||
|
||||
|
@ -4576,7 +4582,7 @@ mod tests {
|
|||
|
||||
// Move cursor to a location that can be renamed.
|
||||
let prepare_rename = editor_b.update(cx_b, |editor, cx| {
|
||||
editor.select_ranges([7..7], None, cx);
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([7..7]));
|
||||
editor.rename(&Rename, cx).unwrap()
|
||||
});
|
||||
|
||||
|
@ -5564,8 +5570,12 @@ mod tests {
|
|||
});
|
||||
|
||||
// When client B starts following client A, all visible view states are replicated to client B.
|
||||
editor_a1.update(cx_a, |editor, cx| editor.select_ranges([0..1], None, cx));
|
||||
editor_a2.update(cx_a, |editor, cx| editor.select_ranges([2..3], None, cx));
|
||||
editor_a1.update(cx_a, |editor, cx| {
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([0..1]))
|
||||
});
|
||||
editor_a2.update(cx_a, |editor, cx| {
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([2..3]))
|
||||
});
|
||||
workspace_b
|
||||
.update(cx_b, |workspace, cx| {
|
||||
workspace
|
||||
|
@ -5588,11 +5598,11 @@ mod tests {
|
|||
Some((worktree_id, "2.txt").into())
|
||||
);
|
||||
assert_eq!(
|
||||
editor_b2.read_with(cx_b, |editor, cx| editor.selected_ranges(cx)),
|
||||
editor_b2.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
|
||||
vec![2..3]
|
||||
);
|
||||
assert_eq!(
|
||||
editor_b1.read_with(cx_b, |editor, cx| editor.selected_ranges(cx)),
|
||||
editor_b1.read_with(cx_b, |editor, cx| editor.selections.ranges(cx)),
|
||||
vec![0..1]
|
||||
);
|
||||
|
||||
|
@ -5631,11 +5641,11 @@ mod tests {
|
|||
|
||||
// Changes to client A's editor are reflected on client B.
|
||||
editor_a1.update(cx_a, |editor, cx| {
|
||||
editor.select_ranges([1..1, 2..2], None, cx);
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([1..1, 2..2]));
|
||||
});
|
||||
editor_b1
|
||||
.condition(cx_b, |editor, cx| {
|
||||
editor.selected_ranges(cx) == vec![1..1, 2..2]
|
||||
editor.selections.ranges(cx) == vec![1..1, 2..2]
|
||||
})
|
||||
.await;
|
||||
|
||||
|
@ -5645,11 +5655,13 @@ mod tests {
|
|||
.await;
|
||||
|
||||
editor_a1.update(cx_a, |editor, cx| {
|
||||
editor.select_ranges([3..3], None, cx);
|
||||
editor.change_selections(None, cx, |s| s.select_ranges([3..3]));
|
||||
editor.set_scroll_position(vec2f(0., 100.), cx);
|
||||
});
|
||||
editor_b1
|
||||
.condition(cx_b, |editor, cx| editor.selected_ranges(cx) == vec![3..3])
|
||||
.condition(cx_b, |editor, cx| {
|
||||
editor.selections.ranges(cx) == vec![3..3]
|
||||
})
|
||||
.await;
|
||||
|
||||
// After unfollowing, client B stops receiving updates from client A.
|
||||
|
@ -6540,6 +6552,7 @@ mod tests {
|
|||
let client_name = name.to_string();
|
||||
let mut client = Client::new(http.clone());
|
||||
let server = self.server.clone();
|
||||
let db = self.app_state.db.clone();
|
||||
let connection_killers = self.connection_killers.clone();
|
||||
let forbid_connections = self.forbid_connections.clone();
|
||||
let (connection_id_tx, mut connection_id_rx) = mpsc::channel(16);
|
||||
|
@ -6560,6 +6573,7 @@ mod tests {
|
|||
assert_eq!(credentials.access_token, "the-token");
|
||||
|
||||
let server = server.clone();
|
||||
let db = db.clone();
|
||||
let connection_killers = connection_killers.clone();
|
||||
let forbid_connections = forbid_connections.clone();
|
||||
let client_name = client_name.clone();
|
||||
|
@ -6573,11 +6587,12 @@ mod tests {
|
|||
let (client_conn, server_conn, killed) =
|
||||
Connection::in_memory(cx.background());
|
||||
connection_killers.lock().insert(user_id, killed);
|
||||
let user = db.get_user_by_id(user_id).await.unwrap().unwrap();
|
||||
cx.background()
|
||||
.spawn(server.handle_connection(
|
||||
server_conn,
|
||||
client_name,
|
||||
user_id,
|
||||
user,
|
||||
Some(connection_id_tx),
|
||||
cx.background(),
|
||||
))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue