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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ By default, the client picks up all file formats the device supports. Use `--dev
| `/health` | GET | No | Liveness check |
| `/upload` | POST | Bearer token | Upload a track file (multipart, field `file`) |

The `/upload` endpoint requires `X-Device-ID` and `X-Source-Format` headers, and optionally `X-Client-Host`.
The `/upload` endpoint requires `X-Device-ID` and `X-Source-Format` headers.

## NixOS module

Expand Down
7 changes: 3 additions & 4 deletions tracksync/internal/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const (
StatusDuplicate // server already had this file
)

func Upload(client *http.Client, serverURL, token, deviceID, hostname, sourceFormat, filename string, data []byte) (UploadStatus, error) {
func Upload(client *http.Client, serverURL, token, deviceID, sourceFormat, filename string, data []byte) (UploadStatus, error) {
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
part, err := writer.CreateFormFile("file", filename)
Expand All @@ -102,7 +102,6 @@ func Upload(client *http.Client, serverURL, token, deviceID, hostname, sourceFor
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("X-Device-ID", deviceID)
req.Header.Set("X-Client-Host", hostname)
req.Header.Set("X-Source-Format", sourceFormat)

resp, err := client.Do(req)
Expand Down Expand Up @@ -134,7 +133,7 @@ type Summary struct {
}

// SyncFiles syncs a list of found files to the server.
func SyncFiles(db *sql.DB, client *http.Client, serverURL, token, deviceID, hostname string, files []device.FoundFile) Summary {
func SyncFiles(db *sql.DB, client *http.Client, serverURL, token, deviceID string, files []device.FoundFile) Summary {
var summary Summary

for _, ff := range files {
Expand All @@ -161,7 +160,7 @@ func SyncFiles(db *sql.DB, client *http.Client, serverURL, token, deviceID, host
continue
}

status, err := Upload(client, serverURL, token, deviceID, hostname, ff.Format, name, data)
status, err := Upload(client, serverURL, token, deviceID, ff.Format, name, data)
if err != nil {
slog.Error("upload failed", "file", name, "error", err)
summary.Errors++
Expand Down
17 changes: 8 additions & 9 deletions tracksync/internal/sync/sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,14 @@ func TestUpload_Created(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "Bearer tok", r.Header.Get("Authorization"))
assert.Equal(t, "dev-1", r.Header.Get("X-Device-ID"))
assert.Equal(t, "myhost", r.Header.Get("X-Client-Host"))
assert.Equal(t, "gpx_1.1", r.Header.Get("X-Source-Format"))
w.WriteHeader(http.StatusCreated)
_, _ = fmt.Fprintln(w, "uploaded")
}))
defer ts.Close()

client := &http.Client{Timeout: 5 * time.Second}
status, err := Upload(client, ts.URL, "tok", "dev-1", "myhost", "gpx_1.1", "track.gpx", []byte("<gpx/>"))
status, err := Upload(client, ts.URL, "tok", "dev-1", "gpx_1.1", "track.gpx", []byte("<gpx/>"))
require.NoError(t, err)
assert.Equal(t, StatusUploaded, status)
}
Expand All @@ -121,7 +120,7 @@ func TestUpload_Duplicate(t *testing.T) {
defer ts.Close()

client := &http.Client{Timeout: 5 * time.Second}
status, err := Upload(client, ts.URL, "tok", "dev", "host", "gpx_1.1", "f.gpx", []byte("data"))
status, err := Upload(client, ts.URL, "tok", "dev", "gpx_1.1", "f.gpx", []byte("data"))
require.NoError(t, err)
assert.Equal(t, StatusDuplicate, status)
}
Expand All @@ -134,7 +133,7 @@ func TestUpload_ServerError(t *testing.T) {
defer ts.Close()

client := &http.Client{Timeout: 5 * time.Second}
_, err := Upload(client, ts.URL, "tok", "dev", "host", "gpx_1.1", "f.gpx", []byte("data"))
_, err := Upload(client, ts.URL, "tok", "dev", "gpx_1.1", "f.gpx", []byte("data"))
assert.Error(t, err)
}

Expand All @@ -150,7 +149,7 @@ func TestSyncFiles_Uploaded(t *testing.T) {
require.NoError(t, os.WriteFile(filepath.Join(dir, "track.gpx"), []byte("<gpx/>"), 0644))

files := []device.FoundFile{{Path: filepath.Join(dir, "track.gpx"), Format: "gpx_1.1"}}
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", "host", files)
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", files)

assert.Equal(t, 1, summary.Uploaded)
assert.Equal(t, 0, summary.Duplicate)
Expand All @@ -171,7 +170,7 @@ func TestSyncFiles_Duplicate(t *testing.T) {
require.NoError(t, os.WriteFile(filepath.Join(dir, "track.gpx"), []byte("<gpx/>"), 0644))

files := []device.FoundFile{{Path: filepath.Join(dir, "track.gpx"), Format: "gpx_1.1"}}
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", "host", files)
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", files)

assert.Equal(t, 0, summary.Uploaded)
assert.Equal(t, 1, summary.Duplicate)
Expand All @@ -195,7 +194,7 @@ func TestSyncFiles_SkippedClientSide(t *testing.T) {
require.NoError(t, RecordUpload(db, SHA256Hex(data), "track.gpx", "dev"))

files := []device.FoundFile{{Path: filepath.Join(dir, "track.gpx"), Format: "gpx_1.1"}}
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", "host", files)
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", files)

assert.Equal(t, 0, summary.Uploaded)
assert.Equal(t, 0, summary.Duplicate)
Expand All @@ -215,7 +214,7 @@ func TestSyncFiles_UploadError(t *testing.T) {
require.NoError(t, os.WriteFile(filepath.Join(dir, "track.gpx"), []byte("<gpx/>"), 0644))

files := []device.FoundFile{{Path: filepath.Join(dir, "track.gpx"), Format: "gpx_1.1"}}
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", "host", files)
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", files)

assert.Equal(t, 0, summary.Uploaded)
assert.Equal(t, 0, summary.Duplicate)
Expand Down Expand Up @@ -252,7 +251,7 @@ func TestSyncFiles_MixedResults(t *testing.T) {
{Path: filepath.Join(dir, "dup.gpx"), Format: "gpx_1.1"},
{Path: filepath.Join(dir, "skip.gpx"), Format: "gpx_1.1"},
}
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", "host", files)
summary := SyncFiles(db, &http.Client{Timeout: 5 * time.Second}, ts.URL, "tok", "dev", files)

assert.Equal(t, 1, summary.Uploaded)
assert.Equal(t, 1, summary.Duplicate)
Expand Down
3 changes: 1 addition & 2 deletions tracksync/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,14 @@ func main() {
return
}

hostname, _ := os.Hostname()
httpClient := &http.Client{Timeout: *timeout}
slog.Info("starting sync",
"device", *deviceID,
"type", dev.Type(),
"files", len(files),
)

summary := sync.SyncFiles(db, httpClient, *serverURL, token, *deviceID, hostname, files)
summary := sync.SyncFiles(db, httpClient, *serverURL, token, *deviceID, files)

slog.Info("sync complete",
"uploaded", summary.Uploaded,
Expand Down
Loading