mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-09-14 22:01:57 +02:00
Route all database writes through one connection (#642)
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
ff7eebf3cd
commit
90cb578e26
@@ -330,18 +330,20 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let settings = app_handle.db().get_settings();
|
||||
let client_cert = find_client_certificate(&request.url, &settings.client_certificates);
|
||||
|
||||
let conn = app_handle.db().upsert_grpc_connection(
|
||||
&GrpcConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
status: -1,
|
||||
elapsed: 0,
|
||||
state: GrpcConnectionState::Initialized,
|
||||
url: request.url.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
let conn = app_handle.with_tx(|tx| {
|
||||
tx.upsert_grpc_connection(
|
||||
&GrpcConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
status: -1,
|
||||
elapsed: 0,
|
||||
state: GrpcConnectionState::Initialized,
|
||||
url: request.url.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
let conn_id = conn.id.clone();
|
||||
|
||||
@@ -386,15 +388,17 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let connection = match connection {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
app_handle.db().upsert_grpc_connection(
|
||||
&GrpcConnection {
|
||||
elapsed: start.elapsed().as_millis() as i32,
|
||||
error: Some(err.to_string()),
|
||||
state: GrpcConnectionState::Closed,
|
||||
..conn.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_grpc_connection(
|
||||
&GrpcConnection {
|
||||
elapsed: start.elapsed().as_millis() as i32,
|
||||
error: Some(err.to_string()),
|
||||
state: GrpcConnectionState::Closed,
|
||||
..conn.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
return Ok(conn_id);
|
||||
}
|
||||
};
|
||||
@@ -495,15 +499,17 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
.await?;
|
||||
let msg = strip_json_comments(&msg);
|
||||
|
||||
app_handle.db().upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: format!("Connecting to {}", req.url),
|
||||
event_type: GrpcEventType::ConnectionStart,
|
||||
metadata: metadata.clone(),
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: format!("Connecting to {}", req.url),
|
||||
event_type: GrpcEventType::ConnectionStart,
|
||||
metadata: metadata.clone(),
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
async move {
|
||||
// Create callback for streaming methods that handles both success and error
|
||||
@@ -513,24 +519,28 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let window_label = window.label().to_string();
|
||||
move |result: std::result::Result<String, String>| match result {
|
||||
Ok(msg) => {
|
||||
let _ = app_handle.db().upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: msg,
|
||||
event_type: GrpcEventType::ClientMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
);
|
||||
let _ = app_handle.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: msg,
|
||||
event_type: GrpcEventType::ClientMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
});
|
||||
}
|
||||
Err(error) => {
|
||||
let _ = app_handle.db().upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: format!("Failed to send message: {}", error),
|
||||
event_type: GrpcEventType::Error,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
);
|
||||
let _ = app_handle.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: format!("Failed to send message: {}", error),
|
||||
event_type: GrpcEventType::Error,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -583,36 +593,38 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
|
||||
if !method_desc.is_client_streaming() {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
event_type: GrpcEventType::ClientMessage,
|
||||
content: msg,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
event_type: GrpcEventType::ClientMessage,
|
||||
content: msg,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
match maybe_msg {
|
||||
Some(Ok(msg)) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
metadata: metadata_to_map(msg.metadata().clone()),
|
||||
content: if msg.metadata().len() == 0 {
|
||||
"Received response"
|
||||
} else {
|
||||
"Received response with metadata"
|
||||
}
|
||||
.to_string(),
|
||||
event_type: GrpcEventType::Info,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
metadata: metadata_to_map(msg.metadata().clone()),
|
||||
content: if msg.metadata().len() == 0 {
|
||||
"Received response"
|
||||
} else {
|
||||
"Received response with metadata"
|
||||
}
|
||||
.to_string(),
|
||||
event_type: GrpcEventType::Info,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
let response_message = msg.into_inner();
|
||||
let content = match connection
|
||||
@@ -622,83 +634,88 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
Ok(content) => content,
|
||||
Err(err) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Failed to read response".to_string(),
|
||||
error: Some(err.to_string()),
|
||||
status: Some(Code::Internal as i32),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Failed to read response".to_string(),
|
||||
error: Some(err.to_string()),
|
||||
status: Some(Code::Internal as i32),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
};
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content,
|
||||
event_type: GrpcEventType::ServerMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content,
|
||||
event_type: GrpcEventType::ServerMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Connection complete".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
status: Some(Code::Ok as i32),
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Connection complete".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
status: Some(Code::Ok as i32),
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
Some(Err(yaak_grpc::error::Error::GrpcStreamError(e))) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&(match e.status {
|
||||
Some(s) => GrpcEvent {
|
||||
error: Some(s.message().to_string()),
|
||||
status: Some(s.code() as i32),
|
||||
content: "Request failed".to_string(),
|
||||
metadata: metadata_to_map(s.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
None => GrpcEvent {
|
||||
error: Some(e.message),
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&(match e.status {
|
||||
Some(s) => GrpcEvent {
|
||||
error: Some(s.message().to_string()),
|
||||
status: Some(s.code() as i32),
|
||||
content: "Request failed".to_string(),
|
||||
metadata: metadata_to_map(s.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
None => GrpcEvent {
|
||||
error: Some(e.message),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Request failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
}),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
app_handle
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
error: Some(e.to_string()),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Request failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
}),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
error: Some(e.to_string()),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Request failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
None => {
|
||||
@@ -709,64 +726,67 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
let mut stream = match maybe_stream {
|
||||
Some(Ok(stream)) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
metadata: metadata_to_map(stream.metadata().clone()),
|
||||
content: if stream.metadata().len() == 0 {
|
||||
"Received response"
|
||||
} else {
|
||||
"Received response with metadata"
|
||||
}
|
||||
.to_string(),
|
||||
event_type: GrpcEventType::Info,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
metadata: metadata_to_map(stream.metadata().clone()),
|
||||
content: if stream.metadata().len() == 0 {
|
||||
"Received response"
|
||||
} else {
|
||||
"Received response with metadata"
|
||||
}
|
||||
.to_string(),
|
||||
event_type: GrpcEventType::Info,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
stream.into_inner()
|
||||
}
|
||||
Some(Err(yaak_grpc::error::Error::GrpcStreamError(e))) => {
|
||||
warn!("GRPC stream error {e:?}");
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&(match e.status {
|
||||
Some(s) => GrpcEvent {
|
||||
error: Some(s.message().to_string()),
|
||||
status: Some(s.code() as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
metadata: metadata_to_map(s.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
None => GrpcEvent {
|
||||
error: Some(e.message),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
}),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&(match e.status {
|
||||
Some(s) => GrpcEvent {
|
||||
error: Some(s.message().to_string()),
|
||||
status: Some(s.code() as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
metadata: metadata_to_map(s.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
None => GrpcEvent {
|
||||
error: Some(e.message),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
}),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
Some(Err(e)) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
error: Some(e.to_string()),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
error: Some(e.to_string()),
|
||||
status: Some(Code::Unknown as i32),
|
||||
content: "Stream failed".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
return;
|
||||
}
|
||||
@@ -783,65 +803,69 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
Ok(message) => message,
|
||||
Err(err) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Failed to read response".to_string(),
|
||||
error: Some(err.to_string()),
|
||||
status: Some(Code::Internal as i32),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Failed to read response".to_string(),
|
||||
error: Some(err.to_string()),
|
||||
status: Some(Code::Internal as i32),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
};
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: message,
|
||||
event_type: GrpcEventType::ServerMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: message,
|
||||
event_type: GrpcEventType::ServerMessage,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
Ok(None) => {
|
||||
let trailers =
|
||||
stream.trailers().await.unwrap_or_default().unwrap_or_default();
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Connection complete".to_string(),
|
||||
status: Some(Code::Ok as i32),
|
||||
metadata: metadata_to_map(trailers),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Connection complete".to_string(),
|
||||
status: Some(Code::Ok as i32),
|
||||
metadata: metadata_to_map(trailers),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
Err(status) => {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Stream failed".to_string(),
|
||||
error: Some(status.message().to_string()),
|
||||
status: Some(status.code() as i32),
|
||||
metadata: metadata_to_map(status.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Stream failed".to_string(),
|
||||
error: Some(status.message().to_string()),
|
||||
status: Some(status.code() as i32),
|
||||
metadata: metadata_to_map(status.metadata().clone()),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
..base_event.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
@@ -874,21 +898,24 @@ async fn cmd_grpc_go<R: Runtime>(
|
||||
}).unwrap();
|
||||
},
|
||||
_ = cancelled_rx.changed() => {
|
||||
w.db().upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Cancelled".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
status: Some(Code::Cancelled as i32),
|
||||
..base_msg.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
).unwrap();
|
||||
w.with_tx(|tx| {
|
||||
tx.upsert_grpc_event(
|
||||
&GrpcEvent {
|
||||
content: "Cancelled".to_string(),
|
||||
event_type: GrpcEventType::ConnectionEnd,
|
||||
status: Some(Code::Cancelled as i32),
|
||||
..base_msg.clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
w.with_tx(|c| {
|
||||
c.upsert_grpc_connection(
|
||||
&GrpcConnection{
|
||||
elapsed: start.elapsed().as_millis() as i32,
|
||||
status: Code::Cancelled as i32,
|
||||
state: GrpcConnectionState::Closed,
|
||||
elapsed: start.elapsed().as_millis() as i32,
|
||||
status: Code::Cancelled as i32,
|
||||
state: GrpcConnectionState::Closed,
|
||||
..c.get_grpc_connection( &conn_id).unwrap().clone()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
@@ -1066,15 +1093,17 @@ async fn cmd_send_http_request<R: Runtime>(
|
||||
let request = app_handle.db().get_http_request(&request_id)?;
|
||||
|
||||
let blobs = app_handle.blob_manager();
|
||||
let response = app_handle.db().upsert_http_response(
|
||||
&HttpResponse {
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)?;
|
||||
let response = app_handle.with_tx(|tx| {
|
||||
tx.upsert_http_response(
|
||||
&HttpResponse {
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)
|
||||
})?;
|
||||
|
||||
let (cancel_tx, mut cancel_rx) = tokio::sync::watch::channel(false);
|
||||
app_handle.listen_any(format!("cancel_http_response_{}", response.id), move |_event| {
|
||||
@@ -1112,15 +1141,17 @@ async fn cmd_send_http_request<R: Runtime>(
|
||||
Ok(sent) => sent.response,
|
||||
Err(e) => {
|
||||
let resp = app_handle.db().get_http_response(&response.id)?;
|
||||
app_handle.db().upsert_http_response(
|
||||
&HttpResponse {
|
||||
state: HttpResponseState::Closed,
|
||||
error: Some(e.to_string()),
|
||||
..resp
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)?
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_http_response(
|
||||
&HttpResponse {
|
||||
state: HttpResponseState::Closed,
|
||||
error: Some(e.to_string()),
|
||||
..resp
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1254,8 +1285,8 @@ pub fn run() {
|
||||
.setup(|app| {
|
||||
let lifecycle_host = yaak_lifecycle::Host::owner()
|
||||
.with_responses_dir(app.path().app_data_dir()?.join("responses"));
|
||||
if let Err(e) =
|
||||
yaak_lifecycle::on_launch(&lifecycle_host, &app.db(), &app.blob_manager())
|
||||
if let Err(e) = app
|
||||
.with_tx(|tx| yaak_lifecycle::on_launch(&lifecycle_host, tx, &app.blob_manager()))
|
||||
{
|
||||
error!("on_launch hook failed: {e:?}");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use tauri::plugin::TauriPlugin;
|
||||
use tauri::{Emitter, Manager, Runtime, State};
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogKind};
|
||||
use yaak_models::blob_manager::BlobManager;
|
||||
use yaak_models::client_db::ClientDb;
|
||||
use yaak_models::client_db::{ClientDb, WriteDb};
|
||||
use yaak_models::error::Result;
|
||||
use yaak_models::query_manager::QueryManager;
|
||||
use yaak_models::util::{ModelPayload, UpdateSource};
|
||||
@@ -95,7 +95,7 @@ pub trait QueryManagerExt<'a, R> {
|
||||
fn db(&'a self) -> ClientDb<'a>;
|
||||
fn with_tx<F, T>(&'a self, func: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&ClientDb) -> Result<T>;
|
||||
F: FnOnce(&WriteDb) -> Result<T>;
|
||||
}
|
||||
|
||||
impl<'a, R: Runtime, M: Manager<R>> QueryManagerExt<'a, R> for M {
|
||||
@@ -110,7 +110,7 @@ impl<'a, R: Runtime, M: Manager<R>> QueryManagerExt<'a, R> for M {
|
||||
|
||||
fn with_tx<F, T>(&'a self, func: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(&ClientDb) -> Result<T>,
|
||||
F: FnOnce(&WriteDb) -> Result<T>,
|
||||
{
|
||||
let qm = self.state::<QueryManager>();
|
||||
qm.inner().with_tx(func)
|
||||
|
||||
@@ -55,12 +55,15 @@ impl YaakNotifier {
|
||||
seen.push(id.to_string());
|
||||
debug!("Marked notification as seen {}", id);
|
||||
let seen_json = serde_json::to_string(&seen)?;
|
||||
window.db().set_key_value_raw(
|
||||
KV_NAMESPACE,
|
||||
KV_KEY,
|
||||
seen_json.as_str(),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
);
|
||||
window.with_tx(|tx| {
|
||||
tx.set_key_value_raw(
|
||||
KV_NAMESPACE,
|
||||
KV_KEY,
|
||||
seen_json.as_str(),
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
);
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ async fn handle_host_plugin_request<R: Runtime>(
|
||||
}
|
||||
|
||||
let new_plugin = Plugin { updated_at: Utc::now().naive_utc(), ..plugin };
|
||||
app_handle.db().upsert_plugin(&new_plugin, &UpdateSource::Plugin)?;
|
||||
app_handle.with_tx(|tx| tx.upsert_plugin(&new_plugin, &UpdateSource::Plugin))?;
|
||||
}
|
||||
|
||||
if !req.silent {
|
||||
@@ -294,15 +294,17 @@ async fn handle_host_plugin_request<R: Runtime>(
|
||||
HttpResponse::default()
|
||||
} else {
|
||||
let blobs = window.blob_manager();
|
||||
window.db().upsert_http_response(
|
||||
&HttpResponse {
|
||||
request_id: http_request.id.clone(),
|
||||
workspace_id: http_request.workspace_id.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)?
|
||||
window.with_tx(|tx| {
|
||||
tx.upsert_http_response(
|
||||
&HttpResponse {
|
||||
request_id: http_request.id.clone(),
|
||||
workspace_id: http_request.workspace_id.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
&blobs,
|
||||
)
|
||||
})?
|
||||
};
|
||||
|
||||
let http_response = send_http_request_with_context(
|
||||
|
||||
@@ -202,16 +202,18 @@ pub async fn cmd_plugins_install_from_directory<R: Runtime>(
|
||||
// Resolve the manager before writing the row so startup's plugin snapshot
|
||||
// can't include it and boot it a second time
|
||||
let plugin_manager = Arc::new(plugin_manager(&window).await?);
|
||||
let plugin = window.db().upsert_plugin(
|
||||
&Plugin {
|
||||
directory: directory.into(),
|
||||
url: None,
|
||||
enabled: true,
|
||||
source: PluginSource::Filesystem,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
let plugin = window.with_tx(|tx| {
|
||||
tx.upsert_plugin(
|
||||
&Plugin {
|
||||
directory: directory.into(),
|
||||
url: None,
|
||||
enabled: true,
|
||||
source: PluginSource::Filesystem,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
plugin_manager.add_plugin(&window.plugin_context(), &plugin).await?;
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ use tokio::sync::watch;
|
||||
use yaak_rpc_schema::WatchResult;
|
||||
use yaak_sync::error::Error::InvalidSyncDirectory;
|
||||
use yaak_sync::sync::{
|
||||
FsCandidate, SyncOp, apply_sync_ops, apply_sync_state_ops, compute_sync_ops, get_db_candidates,
|
||||
get_fs_candidates,
|
||||
FsCandidate, SyncOp, apply_db_sync_ops, apply_fs_sync_ops, apply_sync_state_ops,
|
||||
compute_sync_ops, get_db_candidates, get_fs_candidates,
|
||||
};
|
||||
use yaak_sync::watch::{WatchEvent, watch_directory};
|
||||
|
||||
@@ -49,11 +49,14 @@ pub(crate) async fn cmd_sync_apply<R: Runtime>(
|
||||
sync_dir: &Path,
|
||||
workspace_id: &str,
|
||||
) -> Result<()> {
|
||||
let db = app_handle.db();
|
||||
// Files first, so the write transaction never waits on the filesystem
|
||||
let pending = apply_fs_sync_ops(workspace_id, sync_dir, sync_ops)?;
|
||||
let blobs = app_handle.blob_manager();
|
||||
let sync_state_ops = apply_sync_ops(&db, &blobs, workspace_id, sync_dir, sync_ops)?;
|
||||
apply_sync_state_ops(&db, workspace_id, sync_dir, sync_state_ops)?;
|
||||
Ok(())
|
||||
app_handle.db_manager().with_tx(|tx| {
|
||||
let sync_state_ops = apply_db_sync_ops(tx, &blobs, workspace_id, sync_dir, pending)?;
|
||||
apply_sync_state_ops(tx, workspace_id, sync_dir, sync_state_ops)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn sync_watch<R, F>(
|
||||
|
||||
@@ -43,18 +43,20 @@ pub async fn cmd_ws_send<R: Runtime>(
|
||||
{
|
||||
Ok(connection) => Ok(connection),
|
||||
Err(e) => {
|
||||
app_handle.db().upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: connection.request_id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Error,
|
||||
message: e.to_string().into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: connection.request_id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Error,
|
||||
message: e.to_string().into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(connection)
|
||||
}
|
||||
@@ -96,18 +98,20 @@ async fn send_websocket_message<R: Runtime>(
|
||||
let mut ws_manager = ws_manager.lock().await;
|
||||
ws_manager.send(&connection.id, Message::Text(message.clone().into())).await?;
|
||||
|
||||
app_handle.db().upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Text,
|
||||
message: message.into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Text,
|
||||
message: message.into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(connection.clone())
|
||||
}
|
||||
@@ -118,14 +122,13 @@ pub async fn cmd_ws_close<R: Runtime>(
|
||||
window: WebviewWindow<R>,
|
||||
ws_manager: State<'_, Mutex<WebsocketManager>>,
|
||||
) -> Result<WebsocketConnection> {
|
||||
let connection = {
|
||||
let db = app_handle.db();
|
||||
let connection = db.get_websocket_connection(connection_id)?;
|
||||
db.upsert_websocket_connection(
|
||||
let connection = app_handle.with_tx(|tx| {
|
||||
let connection = tx.get_websocket_connection(connection_id)?;
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection { state: WebsocketConnectionState::Closing, ..connection },
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?
|
||||
};
|
||||
)
|
||||
})?;
|
||||
|
||||
let mut ws_manager = ws_manager.lock().await;
|
||||
if let Err(e) = ws_manager.close(&connection.id).await {
|
||||
@@ -169,14 +172,16 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let connection = app_handle.db().upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
let connection = app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
let (mut url, url_parameters) = apply_path_placeholders(&request.url, &request.url_parameters);
|
||||
if !url.starts_with("ws://") && !url.starts_with("wss://") {
|
||||
@@ -187,14 +192,16 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
let mut url = match Url::parse(&url) {
|
||||
Ok(url) => url,
|
||||
Err(e) => {
|
||||
return Ok(app_handle.db().upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
error: Some(format!("Failed to parse URL {}", e.to_string())),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?);
|
||||
return Ok(app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
error: Some(format!("Failed to parse URL {}", e.to_string())),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -321,28 +328,32 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
{
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Ok(app_handle.db().upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
error: Some(e.to_string()),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?);
|
||||
return Ok(app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
error: Some(e.to_string()),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?);
|
||||
}
|
||||
};
|
||||
|
||||
app_handle.db().upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Open,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection.id.clone(),
|
||||
request_id: request.id.clone(),
|
||||
workspace_id: connection.workspace_id.clone(),
|
||||
is_server: false,
|
||||
message_type: WebsocketEventType::Open,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
let response_headers = response
|
||||
.headers()
|
||||
@@ -366,20 +377,22 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
if !set_cookie_headers.is_empty() {
|
||||
store.store_cookies_from_response(&convert_ws_url_to_http(&url), &set_cookie_headers);
|
||||
cookie_jar.cookies = store.get_all_cookies();
|
||||
app_handle.db().upsert_cookie_jar(cookie_jar, &UpdateSource::Background)?;
|
||||
app_handle.with_tx(|tx| tx.upsert_cookie_jar(cookie_jar, &UpdateSource::Background))?;
|
||||
}
|
||||
}
|
||||
|
||||
let connection = app_handle.db().upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
state: WebsocketConnectionState::Connected,
|
||||
headers: response_headers,
|
||||
status: response.status().as_u16() as i32,
|
||||
url: request.url.clone(),
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)?;
|
||||
let connection = app_handle.with_tx(|tx| {
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
state: WebsocketConnectionState::Connected,
|
||||
headers: response_headers,
|
||||
status: response.status().as_u16() as i32,
|
||||
url: request.url.clone(),
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(window.label()),
|
||||
)
|
||||
})?;
|
||||
|
||||
{
|
||||
let connection_id = connection.id.clone();
|
||||
@@ -395,57 +408,60 @@ pub async fn cmd_ws_connect<R: Runtime>(
|
||||
}
|
||||
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: match message {
|
||||
Message::Text(_) => WebsocketEventType::Text,
|
||||
Message::Binary(_) => WebsocketEventType::Binary,
|
||||
Message::Ping(_) => WebsocketEventType::Ping,
|
||||
Message::Pong(_) => WebsocketEventType::Pong,
|
||||
Message::Close(_) => WebsocketEventType::Close,
|
||||
// Raw frame will never happen during a read
|
||||
Message::Frame(_) => WebsocketEventType::Frame,
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: match message {
|
||||
Message::Text(_) => WebsocketEventType::Text,
|
||||
Message::Binary(_) => WebsocketEventType::Binary,
|
||||
Message::Ping(_) => WebsocketEventType::Ping,
|
||||
Message::Pong(_) => WebsocketEventType::Pong,
|
||||
Message::Close(_) => WebsocketEventType::Close,
|
||||
// Raw frame will never happen during a read
|
||||
Message::Frame(_) => WebsocketEventType::Frame,
|
||||
},
|
||||
message: message.into_data().into(),
|
||||
..Default::default()
|
||||
},
|
||||
message: message.into_data().into(),
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
info!("Websocket connection closed");
|
||||
if !has_written_close {
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: WebsocketEventType::Close,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_websocket_event(
|
||||
&WebsocketEvent {
|
||||
connection_id: connection_id.clone(),
|
||||
request_id: request_id.clone(),
|
||||
workspace_id: workspace_id.clone(),
|
||||
is_server: true,
|
||||
message_type: WebsocketEventType::Close,
|
||||
..Default::default()
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
app_handle
|
||||
.db()
|
||||
.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
.with_tx(|tx| {
|
||||
tx.upsert_websocket_connection(
|
||||
&WebsocketConnection {
|
||||
workspace_id: request.workspace_id.clone(),
|
||||
request_id: request_id.to_string(),
|
||||
state: WebsocketConnectionState::Closed,
|
||||
..connection
|
||||
},
|
||||
&UpdateSource::from_window_label(&window_label),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user