Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
**/.claude/

CLAUDE.md
**/CLAUDE.md
**/CLAUDE.md

tmp/
4 changes: 3 additions & 1 deletion bridge/cgo_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ func go_local_read_callback(userData unsafe.Pointer, buffer *C.uint8_t, size C.i
if err.Error() != "connection lost" && err.Error() != "sync completed" {
client.Logger.Error("Connection to server had a failure. Are you online? Read callback error", zap.Error(err))
}
return -1
// For sync completion errors, return 0 to signal EOF gracefully
// This allows sqlite_rsync to finish processing any buffered data
return 0
}

client.Logger.Debug("Read callback", zap.Int("bytesRead", bytesRead))
Expand Down
5 changes: 3 additions & 2 deletions bridge/sqlite_rsync_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,13 @@ static void *websocket_read_thread(void *arg)
}
else if (bytes_read == 0)
{
// No more data, close write end to signal EOF
// 0 bytes indicates EOF from the Go callback (sync completed)
// Close write end to signal EOF to sqlite_rsync
break;
}
else
{
// Error occurred
// Negative value indicates a real error
break;
}
}
Expand Down
63 changes: 35 additions & 28 deletions client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,35 @@ import (
"github.com/BurntSushi/toml"
)

// .config/sqlrsync/defaults.toml
type DefaultsConfig struct {
Defaults struct {
Server string `toml:"server"`
} `toml:"defaults"`
}

// .config/sqlrsync/local-secrets.toml
type LocalSecretsConfig struct {
Local struct {
Hostname string `toml:"hostname"`
DefaultClientSideEncryptionKey string `toml:"defaultClientSideEncryptionKey"`
} `toml:"local"`
SQLRsyncDatabases []SQLRsyncDatabase `toml:"sqlrsync-databases"`
}

type SQLRsyncDatabase struct {
Path string `toml:"path"`
ReplicaID string `toml:"replicaID,omitempty"`
ClientSideEncryptionKey string `toml:"clientSideEncryptionKey,omitempty"`
LastUpdated time.Time `toml:"lastUpdated,omitempty"`
Server string `toml:"server,omitempty"`
LocalPath string `toml:"path,omitempty"`
Server string `toml:"server"`
CustomerSuppliedEncryptionKey string `toml:"customerSuppliedEncryptionKey,omitempty"`
ReplicaID string `toml:"replicaID"`
RemotePath string `toml:"remotePath,omitempty"`
PushKey string `toml:"pushKey,omitempty"`
LastPush time.Time `toml:"lastPush,omitempty"`
}

// DashSQLRsync manages the -sqlrsync file for a database
type DashSQLRsync struct {
DatabasePath string
RemotePath string
PullKey string
Server string
ReplicaID string
}

func GetConfigDir() (string, error) {
Expand Down Expand Up @@ -176,7 +178,7 @@ func SaveLocalSecretsConfig(config *LocalSecretsConfig) error {

func (c *LocalSecretsConfig) FindDatabaseByPath(path string) *SQLRsyncDatabase {
for i := range c.SQLRsyncDatabases {
if c.SQLRsyncDatabases[i].Path == path {
if c.SQLRsyncDatabases[i].LocalPath == path {
return &c.SQLRsyncDatabases[i]
}
}
Expand All @@ -185,7 +187,7 @@ func (c *LocalSecretsConfig) FindDatabaseByPath(path string) *SQLRsyncDatabase {

func (c *LocalSecretsConfig) UpdateOrAddDatabase(db SQLRsyncDatabase) {
for i := range c.SQLRsyncDatabases {
if c.SQLRsyncDatabases[i].Path == db.Path {
if c.SQLRsyncDatabases[i].LocalPath == db.LocalPath {
// Update existing database
c.SQLRsyncDatabases[i] = db
return
Expand All @@ -197,24 +199,20 @@ func (c *LocalSecretsConfig) UpdateOrAddDatabase(db SQLRsyncDatabase) {

func (c *LocalSecretsConfig) RemoveDatabase(path string) {
for i, db := range c.SQLRsyncDatabases {
if db.Path == path {
if db.LocalPath == path {
// Remove database from slice
c.SQLRsyncDatabases = append(c.SQLRsyncDatabases[:i], c.SQLRsyncDatabases[i+1:]...)
return
}
}
}

func (c *LocalSecretsConfig) SetHostname(hostname string) {
c.Local.Hostname = hostname
}

func (c *LocalSecretsConfig) SetDefaultEncryptionKey(key string) {
c.Local.DefaultClientSideEncryptionKey = key
}

// NewDashSQLRsync creates a new DashSQLRsync instance for the given database path
func NewDashSQLRsync(databasePath string) *DashSQLRsync {
if(strings.Contains(databasePath, "@")) {
databasePath = strings.Split(databasePath, "@")[0]
}

return &DashSQLRsync{
DatabasePath: databasePath,
}
Expand Down Expand Up @@ -246,21 +244,27 @@ func (d *DashSQLRsync) Read() error {
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())

if strings.HasPrefix(line, "#") || line == "" {
continue
}

if strings.HasPrefix(line, "sqlrsync ") {
parts := strings.Fields(line)
if len(parts) >= 2 {
d.RemotePath = parts[1]
}

for _, part := range parts {
if strings.HasPrefix(part, "--pullKey=") {
d.PullKey = strings.TrimPrefix(part, "--pullKey=")
}
if strings.HasPrefix(part, "--replicaID=") {
d.ReplicaID = strings.TrimPrefix(part, "--replicaID=")
}
if strings.HasPrefix(part, "--server=") {
d.Server = strings.TrimPrefix(part, "--server=")
}
}
break
}
Expand All @@ -270,14 +274,17 @@ func (d *DashSQLRsync) Read() error {
}

// Write writes the -sqlrsync file with the given remote path and pull key
func (d *DashSQLRsync) Write(remotePath string, pullKey string) error {
func (d *DashSQLRsync) Write(remotePath string, localName string, replicaID string, pullKey string, serverURL string) error {
d.RemotePath = remotePath
d.PullKey = pullKey

localNameTree := strings.Split(localName, "/")
localName = localNameTree[len(localNameTree)-1]

content := fmt.Sprintf(`#!/bin/bash
# https://sqlrsync.com/docs/pullfile
sqlrsync %s --pullKey=%s
`, remotePath, pullKey)
# https://sqlrsync.com/docs/-sqlrsync
sqlrsync %s %s --replicaID=%s --pullKey=%s --server=%s
`, remotePath, localName, replicaID, pullKey, serverURL)

if err := os.WriteFile(d.FilePath(), []byte(content), 0755); err != nil {
return fmt.Errorf("failed to write -sqlrsync file: %w", err)
Expand All @@ -292,4 +299,4 @@ func (d *DashSQLRsync) Remove() error {
return nil
}
return os.Remove(d.FilePath())
}
}
Loading
Loading