From 7765675559e1553667a5d955cd7716f1c9fe0434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= Date: Mon, 17 Mar 2025 15:53:36 +0100 Subject: [PATCH 01/10] First draft --- examples/README.md | 22 ++++ .../couchbase-server-dev/Dockerfile | 5 + .../couchbase-server-dev/configure-server.sh | 121 ++++++++++++++++++ examples/docker-conf/db-config.json | 8 ++ examples/docker-conf/docker-compose.yml | 48 +++++++ examples/docker-conf/sync-function.js | 17 +++ examples/docker-conf/syncgw-config.json | 43 +++++++ examples/docker-conf/update.sh | 20 +++ .../docker-conf/wait-for-couchbase-server.sh | 19 +++ examples/sgw_1_cblite.rs | 4 + 10 files changed, 307 insertions(+) create mode 100644 examples/README.md create mode 100644 examples/docker-conf/couchbase-server-dev/Dockerfile create mode 100755 examples/docker-conf/couchbase-server-dev/configure-server.sh create mode 100644 examples/docker-conf/db-config.json create mode 100644 examples/docker-conf/docker-compose.yml create mode 100644 examples/docker-conf/sync-function.js create mode 100644 examples/docker-conf/syncgw-config.json create mode 100755 examples/docker-conf/update.sh create mode 100755 examples/docker-conf/wait-for-couchbase-server.sh create mode 100644 examples/sgw_1_cblite.rs diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..ed3971d --- /dev/null +++ b/examples/README.md @@ -0,0 +1,22 @@ +# Running examples with Couchbase Sync Gateway & Server + +Couchbase Lite is often used with replication to a central server, so it can be useful to test the full stack. +The examples in this directory aim at covering these use cases. + +## Setup the Couchbase Sync Gateway & Server + +This process is handled through docker images, with as an entry point the file `docker-conf/docker-compose.yml`. + +The configuration files that might interest are: +- `docker-conf/couchbase-server-dev/configure-server.sh` -> sets up the cluster, bucket and SG user +- `docker-conf/db-config.json` -> contains the database configuration +- `docker-conf/sync-function.js` -> contains the sync function used by the Sync Gateway + +To start both the Sync Gatewawy and Couchbase Server, move to `docker-conf` through a terminal and use: + +```shell +$ docker-compose up +``` + +## + diff --git a/examples/docker-conf/couchbase-server-dev/Dockerfile b/examples/docker-conf/couchbase-server-dev/Dockerfile new file mode 100644 index 0000000..209bf4c --- /dev/null +++ b/examples/docker-conf/couchbase-server-dev/Dockerfile @@ -0,0 +1,5 @@ +# hadolint ignore=DL3007 +FROM couchbase/server:enterprise +COPY configure-server.sh /configure-server.sh + +ENTRYPOINT ["/configure-server.sh"] diff --git a/examples/docker-conf/couchbase-server-dev/configure-server.sh b/examples/docker-conf/couchbase-server-dev/configure-server.sh new file mode 100755 index 0000000..a951963 --- /dev/null +++ b/examples/docker-conf/couchbase-server-dev/configure-server.sh @@ -0,0 +1,121 @@ +#!/usr/bin/env bash + +export COUCHBASE_ADMINISTRATOR_USERNAME="cb_admin" +export COUCHBASE_ADMINISTRATOR_PASSWORD="cb_admin_pwd" + +export COUCHBASE_BUCKET="my-bucket" + +export COUCHBASE_SG_USERNAME="syncgw" +export COUCHBASE_SG_PASSWORD="syncgw-pwd" +export COUCHBASE_SG_NAME="sg-service-user" + +function retry() { + for i in $(seq 1 10); do + $1 + if [[ $? == 0 ]]; then + return 0 + fi + sleep 1 + done + return 1 +} + +function clusterInit() { + couchbase-cli cluster-init \ + -c 127.0.0.1:8091 \ + --cluster-username $COUCHBASE_ADMINISTRATOR_USERNAME \ + --cluster-password $COUCHBASE_ADMINISTRATOR_PASSWORD \ + --services data,index,query \ + --cluster-ramsize 256 \ + --cluster-index-ramsize 256 \ + --index-storage-setting default + if [[ $? != 0 ]]; then + return 1 + fi +} + +function bucketCreate() { + couchbase-cli bucket-create \ + -c 127.0.0.1:8091 \ + --username $COUCHBASE_ADMINISTRATOR_USERNAME \ + --password $COUCHBASE_ADMINISTRATOR_PASSWORD \ + --bucket-type=couchbase \ + --bucket-ramsize=100 \ + --bucket-replica=0 \ + --bucket $COUCHBASE_BUCKET \ + --wait + if [[ $? != 0 ]]; then + return 1 + fi +} + +function userSgCreate() { + couchbase-cli user-manage \ + -c 127.0.0.1:8091 \ + --username $COUCHBASE_ADMINISTRATOR_USERNAME \ + --password $COUCHBASE_ADMINISTRATOR_PASSWORD \ + --set \ + --rbac-username $COUCHBASE_SG_USERNAME \ + --rbac-password $COUCHBASE_SG_PASSWORD \ + --rbac-name $COUCHBASE_SG_NAME \ + --roles bucket_full_access[*],bucket_admin[*] \ + --auth-domain local + if [[ $? != 0 ]]; then + return 1 + fi +} + +function main() { + /entrypoint.sh couchbase-server & + if [[ $? != 0 ]]; then + echo "Couchbase startup failed. Exiting." >&2 + exit 1 + fi + + # wait for service to come up + until $(curl --output /dev/null --silent --head --fail http://localhost:8091); do + sleep 5 + done + + if couchbase-cli server-list -c 127.0.0.1:8091 --username $COUCHBASE_ADMINISTRATOR_USERNAME --password $COUCHBASE_ADMINISTRATOR_PASSWORD ; then + echo "Couchbase already initialized, skipping initialization" + else + echo "Couchbase is not configured." + echo + + echo "Initializing the cluster...." + retry clusterInit + if [[ $? != 0 ]]; then + echo "Cluster init failed. Exiting." >&2 + exit 1 + fi + echo "Initializing the cluster [OK]" + echo + + echo "Creating the bucket...." + retry bucketCreate + if [[ $? != 0 ]]; then + echo "Bucket create failed. Exiting." >&2 + exit 1 + fi + echo "Creating the bucket [OK]" + echo + + echo "Creating Sync Gateway user...." + retry userSgCreate + if [[ $? != 0 ]]; then + echo "User create failed. Exiting." >&2 + exit 1 + fi + echo "Creating Sync Gateway user [OK]" + echo + + sleep 10 + + fi + + wait +} + +main + diff --git a/examples/docker-conf/db-config.json b/examples/docker-conf/db-config.json new file mode 100644 index 0000000..3f589c7 --- /dev/null +++ b/examples/docker-conf/db-config.json @@ -0,0 +1,8 @@ +{ + "import_docs": true, + "enable_shared_bucket_access": true, + "bucket": "my-bucket", + "num_index_replicas": 0, + "revs_limit": 20, + "allow_conflicts": false +} \ No newline at end of file diff --git a/examples/docker-conf/docker-compose.yml b/examples/docker-conf/docker-compose.yml new file mode 100644 index 0000000..ddc34cf --- /dev/null +++ b/examples/docker-conf/docker-compose.yml @@ -0,0 +1,48 @@ +services: + couchbase-server: + image: couchbase-server:dev + ports: + - "8091:8091" # REST(admin), Web console + - "8093:8093" # Query service REST/HTTP traffic + - "11207:11207" # memcached port (TLS) + - "11210:11210" # memcached port + build: + context: ${PWD}/couchbase-server-dev + deploy: + resources: + limits: + memory: 2048M + restart: on-failure + sync-gateway: + image: couchbase/sync-gateway:enterprise + ports: + - "4984:4984" + - "4985:4985" + deploy: + resources: + limits: + memory: 512M + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:4985"] + interval: 30s + timeout: 10s + retries: 5 + volumes: + - ${PWD}/syncgw-config.json:/etc/sync_gateway/config.json:ro + - ${PWD}/wait-for-couchbase-server.sh:/wait-for-couchbase-server.sh + depends_on: + - couchbase-server + entrypoint: ["/wait-for-couchbase-server.sh"] + restart: on-failure + sync-gateway-setup: + image: alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c + depends_on: + sync-gateway: + condition: service_healthy + volumes: + - ${PWD}/sync-function.js:/sync-function.js + - ${PWD}/db-config.json:/db-config.json + - ${PWD}/update.sh:/update.sh + links: + - "sync-gateway:sg" + entrypoint: /update.sh diff --git a/examples/docker-conf/sync-function.js b/examples/docker-conf/sync-function.js new file mode 100644 index 0000000..3be6124 --- /dev/null +++ b/examples/docker-conf/sync-function.js @@ -0,0 +1,17 @@ + +function sync(doc, oldDoc, meta) { + console.log("=== New document revision ==="); + console.log("New doc: ", doc); + console.log("Old doc: ", oldDoc); + console.log("Metadata: ", meta); + + if(doc.channels) { + channel(doc.channels); + } + if(doc.expiry) { + // Format: "2022-06-23T05:00:00+01:00" + expiry(doc.expiry); + } + + console.log("=== Document processed ==="); +} diff --git a/examples/docker-conf/syncgw-config.json b/examples/docker-conf/syncgw-config.json new file mode 100644 index 0000000..7841445 --- /dev/null +++ b/examples/docker-conf/syncgw-config.json @@ -0,0 +1,43 @@ +{ + "bootstrap": { + "server": "couchbase://couchbase-server", + "username": "syncgw", + "password": "syncgw-pwd" + }, + "api": { + "public_interface": ":4984", + "admin_interface": ":4985", + "admin_interface_authentication": false, + "https": {} + }, + "logging": { + "console": { + "rotation": {}, + "log_level": "debug", + "log_keys": [ + "*" + ] + }, + "error": { + "rotation": {} + }, + "warn": { + "rotation": {} + }, + "info": { + "rotation": {} + }, + "debug": { + "rotation": {} + }, + "trace": { + "rotation": {} + }, + "stats": { + "rotation": {} + } + }, + "auth": {}, + "replicator": {}, + "unsupported": {} +} diff --git a/examples/docker-conf/update.sh b/examples/docker-conf/update.sh new file mode 100755 index 0000000..1563376 --- /dev/null +++ b/examples/docker-conf/update.sh @@ -0,0 +1,20 @@ +#!/bin/sh -x + +apk add curl + +export DB_NAME="my-db" + +echo 'START SG Update' +echo + +# Setting up database API: https://docs.couchbase.com/sync-gateway/current/rest_api_admin.html#tag/Database-Management/operation/put_db- +echo 'Setting up the database...' +curl -XPUT -v "http://sg:4985/${DB_NAME}/" -H 'Content-Type: application/json' --data-binary @db-config.json +echo + +# Updating sync function API: https://docs.couchbase.com/sync-gateway/current/rest_api_admin.html#tag/Database-Configuration/operation/put_keyspace-_config-sync +# Sync function doc: https://docs.couchbase.com/sync-gateway/current/sync-function.html +echo 'Updating sync function...' +curl -XPUT -v "http://sg:4985/${DB_NAME}/_config/sync" -H 'Content-Type: application/javascript' --data-binary @sync-function.js + +echo 'END SG Update' \ No newline at end of file diff --git a/examples/docker-conf/wait-for-couchbase-server.sh b/examples/docker-conf/wait-for-couchbase-server.sh new file mode 100755 index 0000000..052b9ca --- /dev/null +++ b/examples/docker-conf/wait-for-couchbase-server.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +echo "Launch SG" +SG_CONFIG_PATH=/etc/sync_gateway/config.json + +COUCHBASE_SERVER_URL="http://couchbase-server:8091" +SG_AUTH_ARG="syncgw:syncgw-pwd" + +while ! { curl -X GET -u $SG_AUTH_ARG $COUCHBASE_SERVER_URL/pools/default/buckets -H "accept: application/json" -s | grep -q '"status":"healthy"'; }; do + echo "Wait 🕑" + sleep 1 +done +echo "CB ready, starting SG" + +sleep 5 + +/entrypoint.sh -bootstrap.use_tls_server=false $SG_CONFIG_PATH + + diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs new file mode 100644 index 0000000..8b406fb --- /dev/null +++ b/examples/sgw_1_cblite.rs @@ -0,0 +1,4 @@ +use couchbase_lite::*; + +/// +fn main() {} From 53b8656f0f50860fdf746c205e5f59e0e047f1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= Date: Mon, 17 Mar 2025 23:57:48 +0100 Subject: [PATCH 02/10] Fix docker conf --- examples/docker-conf/docker-compose.yml | 1 - examples/docker-conf/update.sh | 2 +- examples/docker-conf/wait-for-couchbase-server.sh | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/docker-conf/docker-compose.yml b/examples/docker-conf/docker-compose.yml index ddc34cf..f4463c8 100644 --- a/examples/docker-conf/docker-compose.yml +++ b/examples/docker-conf/docker-compose.yml @@ -1,6 +1,5 @@ services: couchbase-server: - image: couchbase-server:dev ports: - "8091:8091" # REST(admin), Web console - "8093:8093" # Query service REST/HTTP traffic diff --git a/examples/docker-conf/update.sh b/examples/docker-conf/update.sh index 1563376..fae92ac 100755 --- a/examples/docker-conf/update.sh +++ b/examples/docker-conf/update.sh @@ -17,4 +17,4 @@ echo echo 'Updating sync function...' curl -XPUT -v "http://sg:4985/${DB_NAME}/_config/sync" -H 'Content-Type: application/javascript' --data-binary @sync-function.js -echo 'END SG Update' \ No newline at end of file +echo 'END SG Update' diff --git a/examples/docker-conf/wait-for-couchbase-server.sh b/examples/docker-conf/wait-for-couchbase-server.sh index 052b9ca..97d57fd 100755 --- a/examples/docker-conf/wait-for-couchbase-server.sh +++ b/examples/docker-conf/wait-for-couchbase-server.sh @@ -15,5 +15,3 @@ echo "CB ready, starting SG" sleep 5 /entrypoint.sh -bootstrap.use_tls_server=false $SG_CONFIG_PATH - - From 19945d9dee6e0ca89dc3880d99a5ceb7e410b44d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Tue, 18 Mar 2025 23:49:06 +0100 Subject: [PATCH 03/10] The simplest of replications is working --- Cargo.toml | 8 ++ examples/README.md | 20 +++- examples/docker-conf/docker-compose.yml | 12 +- examples/docker-conf/sync-function.js | 10 +- examples/docker-conf/syncgw-config.json | 2 +- .../docker-conf/wait-for-couchbase-server.sh | 2 +- examples/sgw_1_cblite.rs | 110 +++++++++++++++++- 7 files changed, 149 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ffcd1cd..f2910d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,14 @@ tempdir = "*" lazy_static = "1.4.0" regex = "1.10.4" +[dev-dependencies] +serde_json = "1" + +[dev-dependencies.reqwest] +version = "0.12.15" +default-features = false +features = ["blocking", "json"] + [dev-dependencies.cargo-husky] version = "1" default-features = false # Disable features which are enabled by default diff --git a/examples/README.md b/examples/README.md index ed3971d..e681a1a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -18,5 +18,23 @@ To start both the Sync Gatewawy and Couchbase Server, move to `docker-conf` thro $ docker-compose up ``` -## +The first time, it's very long. +## Update the config after startup + +You can change a few things through the `curl` command. + +#### Sync function + +Update the file `docker-conf/sync-function.js` and run +```shell +$ curl -XPUT -v "http://localhost:4985/my-db/_config/sync" -H 'Content-Type: application/javascript' --data-binary @docker-conf/sync-function.js +``` + +#### Database config + +Update the file `docker-conf/db-config.json` and run + +```shell +$ curl -XPUT -v "http://localhost:4985/my-db/" -H 'Content-Type: application/json' --data-binary @docker-conf/db-config.json +``` diff --git a/examples/docker-conf/docker-compose.yml b/examples/docker-conf/docker-compose.yml index f4463c8..202a386 100644 --- a/examples/docker-conf/docker-compose.yml +++ b/examples/docker-conf/docker-compose.yml @@ -1,5 +1,5 @@ services: - couchbase-server: + cblr-couchbase-server: ports: - "8091:8091" # REST(admin), Web console - "8093:8093" # Query service REST/HTTP traffic @@ -12,7 +12,7 @@ services: limits: memory: 2048M restart: on-failure - sync-gateway: + cblr-sync-gateway: image: couchbase/sync-gateway:enterprise ports: - "4984:4984" @@ -30,18 +30,18 @@ services: - ${PWD}/syncgw-config.json:/etc/sync_gateway/config.json:ro - ${PWD}/wait-for-couchbase-server.sh:/wait-for-couchbase-server.sh depends_on: - - couchbase-server + - cblr-couchbase-server entrypoint: ["/wait-for-couchbase-server.sh"] restart: on-failure - sync-gateway-setup: + cblr-sync-gateway-setup: image: alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c depends_on: - sync-gateway: + cblr-sync-gateway: condition: service_healthy volumes: - ${PWD}/sync-function.js:/sync-function.js - ${PWD}/db-config.json:/db-config.json - ${PWD}/update.sh:/update.sh links: - - "sync-gateway:sg" + - "cblr-sync-gateway:sg" entrypoint: /update.sh diff --git a/examples/docker-conf/sync-function.js b/examples/docker-conf/sync-function.js index 3be6124..ec263c4 100644 --- a/examples/docker-conf/sync-function.js +++ b/examples/docker-conf/sync-function.js @@ -1,9 +1,11 @@ - function sync(doc, oldDoc, meta) { console.log("=== New document revision ==="); - console.log("New doc: ", doc); - console.log("Old doc: ", oldDoc); - console.log("Metadata: ", meta); + console.log("New doc:"); + console.log(doc); + console.log("Old doc:"); + console.log(oldDoc); + console.log("Metadata:"); + console.log(meta); if(doc.channels) { channel(doc.channels); diff --git a/examples/docker-conf/syncgw-config.json b/examples/docker-conf/syncgw-config.json index 7841445..8451747 100644 --- a/examples/docker-conf/syncgw-config.json +++ b/examples/docker-conf/syncgw-config.json @@ -1,6 +1,6 @@ { "bootstrap": { - "server": "couchbase://couchbase-server", + "server": "couchbase://cblr-couchbase-server", "username": "syncgw", "password": "syncgw-pwd" }, diff --git a/examples/docker-conf/wait-for-couchbase-server.sh b/examples/docker-conf/wait-for-couchbase-server.sh index 97d57fd..76590da 100755 --- a/examples/docker-conf/wait-for-couchbase-server.sh +++ b/examples/docker-conf/wait-for-couchbase-server.sh @@ -3,7 +3,7 @@ echo "Launch SG" SG_CONFIG_PATH=/etc/sync_gateway/config.json -COUCHBASE_SERVER_URL="http://couchbase-server:8091" +COUCHBASE_SERVER_URL="http://cblr-couchbase-server:8091" SG_AUTH_ARG="syncgw:syncgw-pwd" while ! { curl -X GET -u $SG_AUTH_ARG $COUCHBASE_SERVER_URL/pools/default/buckets -H "accept: application/json" -s | grep -q '"status":"healthy"'; }; do diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs index 8b406fb..2801ecc 100644 --- a/examples/sgw_1_cblite.rs +++ b/examples/sgw_1_cblite.rs @@ -1,4 +1,110 @@ +use std::{collections::HashMap, path::Path}; + use couchbase_lite::*; -/// -fn main() {} +pub const SYNC_GW_URL_ADMIN: &str = "http://localhost:4985/my-db"; +pub const SYNC_GW_URL: &str = "ws://localhost:4984/my-db"; + +fn main() { + let mut db = Database::open( + "test1", + Some(DatabaseConfiguration { + directory: Path::new( + "/Users/antoinemenciere/Projects/couchbase-lite-rust-docto/examples", + ), + encryption_key: None, + }), + ) + .unwrap(); + + add_or_update_user("great_name", vec!["channel1".into()]); + let session_token = Some(get_session("great_name")).unwrap(); + print!("Sync gateway session token: {session_token}"); + + let repl_conf = ReplicatorConfiguration { + database: Some(db.clone()), + endpoint: Endpoint::new_with_url(SYNC_GW_URL).unwrap(), + replicator_type: ReplicatorType::PushAndPull, + continuous: true, + disable_auto_purge: true, // false if we want auto purge when the user loses access to a document + max_attempts: 3, + max_attempt_wait_time: 1, + heartbeat: 60, + authenticator: None, + proxy: None, + headers: vec![( + "Cookie".to_string(), + format!("SyncGatewaySession={session_token}"), + )] + .into_iter() + .collect(), + pinned_server_certificate: None, + trusted_root_certificates: None, + channels: MutableArray::default(), + document_ids: MutableArray::default(), + collections: None, + accept_parent_domain_cookies: false, + }; + let repl_context = ReplicationConfigurationContext::default(); + let mut repl = Replicator::new(repl_conf, Box::new(repl_context)).unwrap(); + + repl.start(false); + + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + + let mut doc = Document::new_with_id("id1"); + doc.set_properties_as_json(r#"{"name": "allo"}"#).unwrap(); + db.save_document(&mut doc).unwrap(); + + assert!(db.get_document("id1").is_ok()); + print!("Doc content: {}", doc.properties_as_json()); + + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(1)); + println!("Replicator state: {:?}", repl.status()); + + repl.stop(None); + + // Create new user session: https://docs.couchbase.com/sync-gateway/current/rest_api_admin.html#tag/Session/operation/post_db-_session +} + +fn add_or_update_user(name: &str, channels: Vec) { + let url_admin_sg = format!("{SYNC_GW_URL_ADMIN}/_user/"); + let user_to_post = serde_json::json!({ + "name": name, + "password": "very_secure", + "admin_channels": channels + }); + let result = reqwest::blocking::Client::new() + .post(url_admin_sg) + .json(&user_to_post) + .send(); + println!("{result:?}"); +} + +fn get_session(name: &str) -> String { + let url_admin_sg = format!("{SYNC_GW_URL_ADMIN}/_session"); + let to_post = serde_json::json!({ + "name": name, + }); + let result: serde_json::Value = reqwest::blocking::Client::new() + .post(url_admin_sg) + .json(&to_post) + .send() + .unwrap() + .json() + .unwrap(); + result["session_id"].as_str().unwrap().to_string() +} From 9dc8b754170b89025bf727845cf04347aae6c950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Tue, 18 Mar 2025 23:52:12 +0100 Subject: [PATCH 04/10] Add .gitignore in examples folder --- examples/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/.gitignore diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..780655c --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +*.cblite2/ \ No newline at end of file From f4965467ae73eb6b16faf43e341307dbb9e1a0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Tue, 18 Mar 2025 23:53:47 +0100 Subject: [PATCH 05/10] Fix example for community edition --- examples/sgw_1_cblite.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs index 2801ecc..7192b27 100644 --- a/examples/sgw_1_cblite.rs +++ b/examples/sgw_1_cblite.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, path::Path}; +use std::path::Path; use couchbase_lite::*; @@ -12,6 +12,7 @@ fn main() { directory: Path::new( "/Users/antoinemenciere/Projects/couchbase-lite-rust-docto/examples", ), + #[cfg(feature = "enterprise")] encryption_key: None, }), ) From f62a40665f1e061a026b651be8e2f6ecb565d099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Wed, 19 Mar 2025 00:02:08 +0100 Subject: [PATCH 06/10] Add info about example in README --- examples/README.md | 20 ++++++++++++++++++-- examples/sgw_1_cblite.rs | 18 ++---------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/README.md b/examples/README.md index e681a1a..a4a54f8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,7 +7,7 @@ The examples in this directory aim at covering these use cases. This process is handled through docker images, with as an entry point the file `docker-conf/docker-compose.yml`. -The configuration files that might interest are: +The configuration files that might interest you are: - `docker-conf/couchbase-server-dev/configure-server.sh` -> sets up the cluster, bucket and SG user - `docker-conf/db-config.json` -> contains the database configuration - `docker-conf/sync-function.js` -> contains the sync function used by the Sync Gateway @@ -18,7 +18,7 @@ To start both the Sync Gatewawy and Couchbase Server, move to `docker-conf` thro $ docker-compose up ``` -The first time, it's very long. +It's very long the first time... ## Update the config after startup @@ -38,3 +38,19 @@ Update the file `docker-conf/db-config.json` and run ```shell $ curl -XPUT -v "http://localhost:4985/my-db/" -H 'Content-Type: application/json' --data-binary @docker-conf/db-config.json ``` + +## Running an example + +As of now, there is only one example: `sgw_1_cblite`. + +It can be run with the following command: +```shell +$ cargo run --features=enterprise --example sgw_1_cblite +``` + +What it does: +- Create a cblite database `test1` +- Add a user `great_name` to the Sync Gateway +- Retrieve a session token for the user `great_name` from the Sync Gateway +- Start a continuous push & pull replicator +- Create a document, then wait for 5 seconds for the replication to finish diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs index 7192b27..50d7f35 100644 --- a/examples/sgw_1_cblite.rs +++ b/examples/sgw_1_cblite.rs @@ -51,15 +51,7 @@ fn main() { repl.start(false); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(3)); let mut doc = Document::new_with_id("id1"); doc.set_properties_as_json(r#"{"name": "allo"}"#).unwrap(); @@ -68,13 +60,7 @@ fn main() { assert!(db.get_document("id1").is_ok()); print!("Doc content: {}", doc.properties_as_json()); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); - std::thread::sleep(std::time::Duration::from_secs(1)); - println!("Replicator state: {:?}", repl.status()); + std::thread::sleep(std::time::Duration::from_secs(3)); repl.stop(None); From f110353edf810ea4d3e2e2c4af45f9790837d2e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Wed, 19 Mar 2025 09:33:37 +0100 Subject: [PATCH 07/10] Add link to server web ui in README --- examples/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/README.md b/examples/README.md index a4a54f8..1fadb2d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,6 +20,9 @@ $ docker-compose up It's very long the first time... +You can then access the Couchbase Server web ui through [http://localhost:8091](http://localhost:8091) (Chrome might not work, Firefox has better support). +Make sure to not have another instance running. + ## Update the config after startup You can change a few things through the `curl` command. From 2930e29de4e57ba03a9c2d6fe4738b9be8befaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Wed, 19 Mar 2025 09:37:57 +0100 Subject: [PATCH 08/10] Use serde_json to fill document in example --- examples/sgw_1_cblite.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs index 50d7f35..61df491 100644 --- a/examples/sgw_1_cblite.rs +++ b/examples/sgw_1_cblite.rs @@ -54,11 +54,17 @@ fn main() { std::thread::sleep(std::time::Duration::from_secs(3)); let mut doc = Document::new_with_id("id1"); - doc.set_properties_as_json(r#"{"name": "allo"}"#).unwrap(); + doc.set_properties_as_json( + &serde_json::json!({ + "name": "allo2" + }) + .to_string(), + ) + .unwrap(); db.save_document(&mut doc).unwrap(); assert!(db.get_document("id1").is_ok()); - print!("Doc content: {}", doc.properties_as_json()); + println!("Doc content: {}", doc.properties_as_json()); std::thread::sleep(std::time::Duration::from_secs(3)); From b314abb5db2ee501443e7a3c7d890f71cb120c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Wed, 19 Mar 2025 09:40:17 +0100 Subject: [PATCH 09/10] Better database path --- .gitignore | 2 ++ examples/.gitignore | 1 - examples/sgw_1_cblite.rs | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 examples/.gitignore diff --git a/.gitignore b/.gitignore index 77340e7..4b3c13d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ Cargo.lock # MacOS directory conf .DS_Store + +*.cblite2/ diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 780655c..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.cblite2/ \ No newline at end of file diff --git a/examples/sgw_1_cblite.rs b/examples/sgw_1_cblite.rs index 61df491..9498cef 100644 --- a/examples/sgw_1_cblite.rs +++ b/examples/sgw_1_cblite.rs @@ -9,9 +9,7 @@ fn main() { let mut db = Database::open( "test1", Some(DatabaseConfiguration { - directory: Path::new( - "/Users/antoinemenciere/Projects/couchbase-lite-rust-docto/examples", - ), + directory: Path::new("./"), #[cfg(feature = "enterprise")] encryption_key: None, }), From c79048349d594daddccb9d4eeaefca6d469190a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antoine=20Menci=C3=A8re?= <95620255+Nao-ris@users.noreply.github.com> Date: Tue, 25 Mar 2025 16:42:10 +0100 Subject: [PATCH 10/10] Nothing --- examples/docker-conf/update.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/docker-conf/update.sh b/examples/docker-conf/update.sh index fae92ac..34de32f 100755 --- a/examples/docker-conf/update.sh +++ b/examples/docker-conf/update.sh @@ -7,6 +7,9 @@ export DB_NAME="my-db" echo 'START SG Update' echo +#Can I bypass the config if it's already done? This command does not work: +#curl -I "http://localhost:4985/my-db/" -w "%{http_code}"` --output >(cat >&3) + # Setting up database API: https://docs.couchbase.com/sync-gateway/current/rest_api_admin.html#tag/Database-Management/operation/put_db- echo 'Setting up the database...' curl -XPUT -v "http://sg:4985/${DB_NAME}/" -H 'Content-Type: application/json' --data-binary @db-config.json