Skip to content

Commit 3d52c07

Browse files
authored
Merge pull request #1840 from tursodatabase/opsqlite_offline
Make it possible to use offline writes in C bindings
2 parents a77f422 + 7e6d74f commit 3d52c07

File tree

4 files changed

+79
-11
lines changed

4 files changed

+79
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindings/c/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ tokio = { version = "1.29.1", features = [ "rt-multi-thread" ] }
1717
hyper-rustls = { version = "0.25", features = ["webpki-roots"]}
1818
tracing = "0.1.40"
1919
tracing-subscriber = "0.3.18"
20+
http = "1.1.0"
2021

2122
[target.'cfg(not(any(target_os = "ios", target_os = "android")))'.dependencies]
2223
libsql = { path = "../../libsql", features = ["encryption"] }

bindings/c/src/lib.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate lazy_static;
66
mod types;
77

88
use crate::types::libsql_config;
9-
use libsql::{errors, LoadExtensionGuard};
9+
use libsql::{errors, Builder, LoadExtensionGuard};
1010
use tokio::runtime::Runtime;
1111
use types::{
1212
blob, libsql_connection, libsql_connection_t, libsql_database, libsql_database_t, libsql_row,
@@ -152,6 +152,44 @@ pub unsafe extern "C" fn libsql_open_sync_with_config(
152152
return 3;
153153
}
154154
};
155+
let uri: http::Uri = match primary_url.try_into() {
156+
Ok(uri) => uri,
157+
Err(e) => {
158+
set_err_msg(format!("Wrong primary URL: {e}"), out_err_msg);
159+
return 100;
160+
}
161+
};
162+
if let Some(query) = uri.query() {
163+
if query.contains("offline") {
164+
let mut builder = Builder::new_synced_database(
165+
db_path,
166+
primary_url.to_owned(),
167+
auth_token.to_owned(),
168+
);
169+
if config.with_webpki != 0 {
170+
let https = hyper_rustls::HttpsConnectorBuilder::new()
171+
.with_webpki_roots()
172+
.https_or_http()
173+
.enable_http1()
174+
.build();
175+
builder = builder.connector(https);
176+
}
177+
match RT.block_on(builder.build()) {
178+
Ok(db) => {
179+
let db = Box::leak(Box::new(libsql_database { db }));
180+
*out_db = libsql_database_t::from(db);
181+
return 0;
182+
}
183+
Err(e) => {
184+
set_err_msg(
185+
format!("Error opening offline db path {db_path}, primary url {primary_url}: {e}"),
186+
out_err_msg,
187+
);
188+
return 101;
189+
}
190+
}
191+
}
192+
}
155193
let mut builder = libsql::Builder::new_remote_replica(
156194
db_path,
157195
primary_url.to_string(),

libsql/src/database/builder.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
cfg_core! {
22
use crate::EncryptionConfig;
33
}
4+
45
use crate::{Database, Result};
56

67
use super::DbType;
@@ -99,6 +100,7 @@ impl Builder<()> {
99100
connector: None,
100101
version: None,
101102
},
103+
connector:None,
102104
},
103105
}
104106
}
@@ -399,6 +401,7 @@ cfg_sync! {
399401
path: std::path::PathBuf,
400402
flags: crate::OpenFlags,
401403
remote: Remote,
404+
connector: Option<crate::util::ConnectorService>,
402405
}
403406

404407
impl Builder<SyncedDatabase> {
@@ -408,6 +411,18 @@ cfg_sync! {
408411
self
409412
}
410413

414+
/// Provide a custom http connector that will be used to create http connections.
415+
pub fn connector<C>(mut self, connector: C) -> Builder<SyncedDatabase>
416+
where
417+
C: tower::Service<http::Uri> + Send + Clone + Sync + 'static,
418+
C::Response: crate::util::Socket,
419+
C::Future: Send + 'static,
420+
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
421+
{
422+
self.inner.connector = Some(wrap_connector(connector));
423+
self
424+
}
425+
411426
/// Build a connection to a local database that can be synced to remote server.
412427
pub async fn build(self) -> Result<Database> {
413428
let SyncedDatabase {
@@ -420,11 +435,16 @@ cfg_sync! {
420435
connector: _,
421436
version: _,
422437
},
438+
connector,
423439
} = self.inner;
424440

425441
let path = path.to_str().ok_or(crate::Error::InvalidUTF8Path)?.to_owned();
426442

427-
let https = super::connector()?;
443+
let https = if let Some(connector) = connector {
444+
connector
445+
} else {
446+
wrap_connector(super::connector()?)
447+
};
428448
use tower::ServiceExt;
429449

430450
let svc = https
@@ -506,6 +526,22 @@ cfg_remote! {
506526
}
507527

508528
cfg_replication_or_remote_or_sync! {
529+
fn wrap_connector<C>(connector: C) -> crate::util::ConnectorService
530+
where
531+
C: tower::Service<http::Uri> + Send + Clone + Sync + 'static,
532+
C::Response: crate::util::Socket,
533+
C::Future: Send + 'static,
534+
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
535+
{
536+
use tower::ServiceExt;
537+
538+
let svc = connector
539+
.map_err(|e| e.into())
540+
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
541+
542+
crate::util::ConnectorService::new(svc)
543+
}
544+
509545
impl Remote {
510546
fn connector<C>(mut self, connector: C) -> Remote
511547
where
@@ -514,15 +550,7 @@ cfg_replication_or_remote_or_sync! {
514550
C::Future: Send + 'static,
515551
C::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
516552
{
517-
use tower::ServiceExt;
518-
519-
let svc = connector
520-
.map_err(|e| e.into())
521-
.map_response(|s| Box::new(s) as Box<dyn crate::util::Socket>);
522-
523-
let svc = crate::util::ConnectorService::new(svc);
524-
525-
self.connector = Some(svc);
553+
self.connector = Some(wrap_connector(connector));
526554
self
527555
}
528556

0 commit comments

Comments
 (0)