Compare commits
3 Commits
create-lib
...
2ed2177577
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ed2177577 | |||
| 092b823959 | |||
| 3d6c8fa97b |
@@ -1,749 +0,0 @@
|
|||||||
# libnextcloud Shared Library Plan
|
|
||||||
|
|
||||||
**Created**: 2026-01-27
|
|
||||||
**Status**: 📋 Planning
|
|
||||||
**Target**: Cross-platform C++17 shared library for Nextcloud connectivity
|
|
||||||
**Branch**: `create-libnextcloud`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Create `libnextcloud` - a cross-platform C++17 shared library that provides Nextcloud connectivity for embedded devices and homebrew platforms. The library will handle all Nextcloud communication, authentication, file operations, and settings management through a clean, platform-agnostic API.
|
|
||||||
|
|
||||||
**Design Philosophy**:
|
|
||||||
- **Platform-agnostic**: Works on 3DS, Switch, Wii U, Vita, PC, etc.
|
|
||||||
- **Minimal dependencies**: Only libcurl, mbedTLS, and tinyxml2
|
|
||||||
- **Header-only where possible**: nlohmann/json for configuration
|
|
||||||
- **Modern C++17**: Using standard library features
|
|
||||||
- **Testable**: Mock-friendly design with dependency injection
|
|
||||||
- **Documented**: Doxygen API documentation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
shared/
|
|
||||||
├── include/
|
|
||||||
│ └── nextcloud/
|
|
||||||
│ ├── client.hpp # Main client interface
|
|
||||||
│ ├── webdav_client.hpp # WebDAV protocol implementation
|
|
||||||
│ ├── auth.hpp # Authentication manager
|
|
||||||
│ ├── upload_manager.hpp # File upload with chunking
|
|
||||||
│ ├── folder_manager.hpp # Remote folder operations
|
|
||||||
│ ├── config.hpp # Configuration management
|
|
||||||
│ ├── types.hpp # Common types and enums
|
|
||||||
│ └── version.hpp # Library version info
|
|
||||||
├── src/
|
|
||||||
│ ├── webdav_client.cpp
|
|
||||||
│ ├── auth.cpp
|
|
||||||
│ ├── upload_manager.cpp
|
|
||||||
│ ├── folder_manager.cpp
|
|
||||||
│ └── config.cpp
|
|
||||||
├── tests/
|
|
||||||
│ ├── webdav_client_test.cpp
|
|
||||||
│ ├── auth_test.cpp
|
|
||||||
│ ├── upload_manager_test.cpp
|
|
||||||
│ ├── folder_manager_test.cpp
|
|
||||||
│ ├── config_test.cpp
|
|
||||||
│ └── mocks/
|
|
||||||
│ ├── mock_http_client.hpp
|
|
||||||
│ └── mock_xml_parser.hpp
|
|
||||||
├── examples/
|
|
||||||
│ ├── simple_upload.cpp
|
|
||||||
│ ├── folder_listing.cpp
|
|
||||||
│ └── authentication.cpp
|
|
||||||
├── docs/
|
|
||||||
│ ├── api.md # API documentation
|
|
||||||
│ ├── architecture.md # Design overview
|
|
||||||
│ └── Doxyfile # Doxygen configuration
|
|
||||||
├── CMakeLists.txt
|
|
||||||
└── README.md
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
### Required
|
|
||||||
- **libcurl** (7.68+): HTTP/HTTPS client
|
|
||||||
- **mbedTLS** (2.16+): SSL/TLS support (works on embedded)
|
|
||||||
- **tinyxml2** (9.0+): Lightweight XML parsing
|
|
||||||
|
|
||||||
### Header-Only
|
|
||||||
- **nlohmann/json** (3.10+): JSON parsing/serialization
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- **Google Test** (1.11+): Unit testing framework
|
|
||||||
- **Google Mock** (1.11+): Mocking framework
|
|
||||||
|
|
||||||
### Build Tools
|
|
||||||
- **CMake** (3.15+): Build system
|
|
||||||
- **C++17 compiler**: GCC 7+, Clang 5+, MSVC 2017+
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation Phases
|
|
||||||
|
|
||||||
## Phase 1: Project Scaffolding (Issue #??)
|
|
||||||
|
|
||||||
**Goal**: Set up the library project structure and build system.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `shared/` directory structure
|
|
||||||
- [ ] Set up CMakeLists.txt with:
|
|
||||||
- Library target (static/shared)
|
|
||||||
- C++17 standard
|
|
||||||
- Include directories
|
|
||||||
- Dependency linking (curl, mbedtls, tinyxml2)
|
|
||||||
- Install rules
|
|
||||||
- Export config for downstream projects
|
|
||||||
- [ ] Create version.hpp with semantic versioning
|
|
||||||
- [ ] Create types.hpp with common enums and structures:
|
|
||||||
- `NextcloudError` enum
|
|
||||||
- `UploadProgress` struct
|
|
||||||
- `FileInfo` struct
|
|
||||||
- `FolderInfo` struct
|
|
||||||
- [ ] Set up Google Test framework
|
|
||||||
- [ ] Create basic README for the library
|
|
||||||
- [ ] Add pkg-config file generation
|
|
||||||
- [ ] Verify library compiles as standalone project
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] CMake builds library successfully
|
|
||||||
- [ ] Can link against library from test project
|
|
||||||
- [ ] Version info accessible at runtime
|
|
||||||
- [ ] Ready for component implementation
|
|
||||||
|
|
||||||
**Estimated Time**: 4-6 hours
|
|
||||||
**Priority**: Critical (blocks all other work)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 2: WebDAV Client (Issue #8)
|
|
||||||
|
|
||||||
**Goal**: Implement HTTP/WebDAV communication layer.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `webdav_client.hpp` interface
|
|
||||||
- [ ] Implement HTTP wrapper around libcurl:
|
|
||||||
- GET, PUT, POST, DELETE, custom methods
|
|
||||||
- Request/response headers
|
|
||||||
- Request body (string, stream)
|
|
||||||
- Response body handling
|
|
||||||
- Timeout configuration
|
|
||||||
- User-Agent setting
|
|
||||||
- [ ] Add SSL/TLS support with mbedTLS
|
|
||||||
- [ ] Implement WebDAV methods:
|
|
||||||
- PROPFIND (list files/folders)
|
|
||||||
- MKCOL (create folder)
|
|
||||||
- PUT (upload file)
|
|
||||||
- DELETE (remove file/folder)
|
|
||||||
- MOVE (rename/move)
|
|
||||||
- COPY (duplicate)
|
|
||||||
- [ ] Parse WebDAV XML responses (using tinyxml2):
|
|
||||||
- Multi-status responses
|
|
||||||
- File properties (size, mtime, type)
|
|
||||||
- Error responses
|
|
||||||
- [ ] Implement error handling:
|
|
||||||
- HTTP status codes
|
|
||||||
- Network errors
|
|
||||||
- XML parsing errors
|
|
||||||
- Error code mapping
|
|
||||||
- [ ] Add timeout and retry logic
|
|
||||||
- [ ] Write unit tests with mocked HTTP
|
|
||||||
- [ ] Document API in Doxygen format
|
|
||||||
|
|
||||||
### API Design
|
|
||||||
```cpp
|
|
||||||
class WebDAVClient {
|
|
||||||
public:
|
|
||||||
WebDAVClient(const std::string& baseUrl);
|
|
||||||
|
|
||||||
// Core HTTP
|
|
||||||
Response get(const std::string& path);
|
|
||||||
Response put(const std::string& path, const std::vector<uint8_t>& data);
|
|
||||||
Response delete_(const std::string& path);
|
|
||||||
|
|
||||||
// WebDAV operations
|
|
||||||
std::vector<FileInfo> propfind(const std::string& path, int depth = 1);
|
|
||||||
bool mkcol(const std::string& path);
|
|
||||||
bool move(const std::string& from, const std::string& to);
|
|
||||||
bool copy(const std::string& from, const std::string& to);
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
void setTimeout(int seconds);
|
|
||||||
void setAuthHeader(const std::string& header);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] All WebDAV methods implemented
|
|
||||||
- [ ] SSL/TLS connections working
|
|
||||||
- [ ] XML responses correctly parsed
|
|
||||||
- [ ] Error handling comprehensive
|
|
||||||
- [ ] Unit tests with >80% coverage
|
|
||||||
- [ ] API documented
|
|
||||||
- [ ] Works with test Nextcloud servers
|
|
||||||
|
|
||||||
**Estimated Time**: 12-16 hours
|
|
||||||
**Priority**: Critical (foundation for all features)
|
|
||||||
**Dependencies**: Phase 1 complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 3: Authentication System (Issue #9)
|
|
||||||
|
|
||||||
**Goal**: Handle authentication with Nextcloud servers.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `auth.hpp` interface
|
|
||||||
- [ ] Implement HTTP Basic Authentication:
|
|
||||||
- Base64 encoding
|
|
||||||
- Authorization header generation
|
|
||||||
- Credential storage
|
|
||||||
- [ ] Add authentication verification:
|
|
||||||
- Test connection to server
|
|
||||||
- Validate credentials
|
|
||||||
- Return meaningful error codes
|
|
||||||
- [ ] Secure credential handling:
|
|
||||||
- In-memory only (no disk storage by default)
|
|
||||||
- Platform-specific secure storage hooks
|
|
||||||
- [ ] Session management:
|
|
||||||
- Keep-alive connections
|
|
||||||
- Connection pooling
|
|
||||||
- Timeout handling
|
|
||||||
- [ ] Future: OAuth2 support (stubbed for now)
|
|
||||||
- [ ] Write unit tests for auth flows
|
|
||||||
- [ ] Document security considerations
|
|
||||||
|
|
||||||
### API Design
|
|
||||||
```cpp
|
|
||||||
class AuthManager {
|
|
||||||
public:
|
|
||||||
// Basic Auth
|
|
||||||
void setBasicAuth(const std::string& username, const std::string& password);
|
|
||||||
std::string getAuthHeader() const;
|
|
||||||
|
|
||||||
// Verification
|
|
||||||
bool verifyConnection(WebDAVClient& client);
|
|
||||||
|
|
||||||
// Session management
|
|
||||||
void clearCredentials();
|
|
||||||
bool hasCredentials() const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] Basic auth working with real Nextcloud
|
|
||||||
- [ ] Credentials never logged or leaked
|
|
||||||
- [ ] Connection verification works
|
|
||||||
- [ ] Error messages helpful
|
|
||||||
- [ ] Unit tests cover edge cases
|
|
||||||
- [ ] API documented
|
|
||||||
|
|
||||||
**Estimated Time**: 6-8 hours
|
|
||||||
**Priority**: High
|
|
||||||
**Dependencies**: Phase 2 complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 4: Upload Manager (Issue #10)
|
|
||||||
|
|
||||||
**Goal**: Implement file upload with chunking and progress tracking.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `upload_manager.hpp` interface
|
|
||||||
- [ ] Implement streaming upload:
|
|
||||||
- Read file in chunks
|
|
||||||
- Send via PUT requests
|
|
||||||
- Handle large files (>1GB)
|
|
||||||
- [ ] Add chunking support:
|
|
||||||
- Configurable chunk size (default: 10MB)
|
|
||||||
- Resume capability (future)
|
|
||||||
- Parallel chunks (future)
|
|
||||||
- [ ] Progress tracking:
|
|
||||||
- Callback interface
|
|
||||||
- Bytes uploaded / total
|
|
||||||
- Transfer speed
|
|
||||||
- Time remaining estimate
|
|
||||||
- [ ] Error handling and retry:
|
|
||||||
- Network failures
|
|
||||||
- Server errors (503, 507)
|
|
||||||
- Automatic retry with backoff
|
|
||||||
- Partial upload cleanup
|
|
||||||
- [ ] Path handling:
|
|
||||||
- URL encoding
|
|
||||||
- Special characters
|
|
||||||
- Nested folders
|
|
||||||
- [ ] Write unit tests with mock uploads
|
|
||||||
- [ ] Document upload best practices
|
|
||||||
|
|
||||||
### API Design
|
|
||||||
```cpp
|
|
||||||
class UploadManager {
|
|
||||||
public:
|
|
||||||
using ProgressCallback = std::function<void(const UploadProgress&)>;
|
|
||||||
|
|
||||||
UploadManager(WebDAVClient& client, AuthManager& auth);
|
|
||||||
|
|
||||||
// Upload operations
|
|
||||||
bool uploadFile(
|
|
||||||
const std::string& localPath,
|
|
||||||
const std::string& remotePath,
|
|
||||||
ProgressCallback callback = nullptr
|
|
||||||
);
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
void setChunkSize(size_t bytes);
|
|
||||||
void setRetryCount(int count);
|
|
||||||
void setTimeout(int seconds);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UploadProgress {
|
|
||||||
std::string filename;
|
|
||||||
size_t bytesUploaded;
|
|
||||||
size_t totalBytes;
|
|
||||||
float percentComplete;
|
|
||||||
float bytesPerSecond;
|
|
||||||
int secondsRemaining;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] Uploads files successfully
|
|
||||||
- [ ] Chunking works for large files
|
|
||||||
- [ ] Progress callback accurate
|
|
||||||
- [ ] Handles network failures gracefully
|
|
||||||
- [ ] Retries work correctly
|
|
||||||
- [ ] Unit tests with various file sizes
|
|
||||||
- [ ] API documented
|
|
||||||
|
|
||||||
**Estimated Time**: 10-12 hours
|
|
||||||
**Priority**: High
|
|
||||||
**Dependencies**: Phases 2, 3 complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 5: Folder Management (Issue #11)
|
|
||||||
|
|
||||||
**Goal**: Remote folder operations and navigation.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `folder_manager.hpp` interface
|
|
||||||
- [ ] Implement folder listing:
|
|
||||||
- List contents of remote folder
|
|
||||||
- Parse file metadata (size, mtime, type)
|
|
||||||
- Recursive listing support
|
|
||||||
- Filtering (files only, folders only)
|
|
||||||
- [ ] Folder creation:
|
|
||||||
- Create single folder
|
|
||||||
- Create nested folders (mkdir -p)
|
|
||||||
- Validate folder names
|
|
||||||
- [ ] Folder navigation:
|
|
||||||
- Path normalization
|
|
||||||
- Parent folder detection
|
|
||||||
- Breadcrumb generation
|
|
||||||
- [ ] Caching (optional):
|
|
||||||
- Cache folder contents
|
|
||||||
- TTL-based invalidation
|
|
||||||
- Memory limits
|
|
||||||
- [ ] Write unit tests
|
|
||||||
- [ ] Document folder operations
|
|
||||||
|
|
||||||
### API Design
|
|
||||||
```cpp
|
|
||||||
class FolderManager {
|
|
||||||
public:
|
|
||||||
FolderManager(WebDAVClient& client, AuthManager& auth);
|
|
||||||
|
|
||||||
// Folder operations
|
|
||||||
std::vector<FileInfo> listFolder(const std::string& path);
|
|
||||||
bool createFolder(const std::string& path);
|
|
||||||
bool createFolders(const std::string& path); // mkdir -p
|
|
||||||
bool deleteFolder(const std::string& path);
|
|
||||||
bool folderExists(const std::string& path);
|
|
||||||
|
|
||||||
// Navigation helpers
|
|
||||||
std::string getParentFolder(const std::string& path);
|
|
||||||
std::vector<std::string> getBreadcrumbs(const std::string& path);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FileInfo {
|
|
||||||
std::string name;
|
|
||||||
std::string path;
|
|
||||||
bool isDirectory;
|
|
||||||
size_t size;
|
|
||||||
time_t modifiedTime;
|
|
||||||
std::string contentType;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] Lists folders correctly
|
|
||||||
- [ ] Creates folders successfully
|
|
||||||
- [ ] Handles nested paths
|
|
||||||
- [ ] Metadata parsing accurate
|
|
||||||
- [ ] Unit tests comprehensive
|
|
||||||
- [ ] API documented
|
|
||||||
|
|
||||||
**Estimated Time**: 8-10 hours
|
|
||||||
**Priority**: Medium
|
|
||||||
**Dependencies**: Phases 2, 3 complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 6: Favorites and Recent Folders (Issue #12)
|
|
||||||
|
|
||||||
**Goal**: Persistence layer for user preferences.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Create `config.hpp` interface
|
|
||||||
- [ ] Implement favorites management:
|
|
||||||
- Add favorite folder
|
|
||||||
- Remove favorite folder
|
|
||||||
- List favorites
|
|
||||||
- Reorder favorites
|
|
||||||
- [ ] Implement recent folders tracking:
|
|
||||||
- Auto-track used folders
|
|
||||||
- Configurable limit (default: 5)
|
|
||||||
- LRU eviction
|
|
||||||
- Duplicate detection
|
|
||||||
- [ ] JSON persistence:
|
|
||||||
- Save to file
|
|
||||||
- Load from file
|
|
||||||
- Handle missing/corrupt files
|
|
||||||
- Migration support
|
|
||||||
- [ ] Platform-specific paths:
|
|
||||||
- Linux: ~/.config/nextcloud-share/
|
|
||||||
- 3DS: /nextcloud-share/
|
|
||||||
- Switch: /switch/nextcloud-share/
|
|
||||||
- [ ] Write unit tests
|
|
||||||
- [ ] Document config format
|
|
||||||
|
|
||||||
### API Design
|
|
||||||
```cpp
|
|
||||||
class Config {
|
|
||||||
public:
|
|
||||||
Config(const std::string& configPath = "");
|
|
||||||
|
|
||||||
// Favorites
|
|
||||||
void addFavorite(const std::string& path, const std::string& name = "");
|
|
||||||
void removeFavorite(const std::string& path);
|
|
||||||
std::vector<FolderInfo> getFavorites() const;
|
|
||||||
|
|
||||||
// Recent folders
|
|
||||||
void addRecentFolder(const std::string& path);
|
|
||||||
std::vector<std::string> getRecentFolders() const;
|
|
||||||
void setMaxRecentFolders(int count);
|
|
||||||
|
|
||||||
// Persistence
|
|
||||||
bool load();
|
|
||||||
bool save();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FolderInfo {
|
|
||||||
std::string path;
|
|
||||||
std::string displayName;
|
|
||||||
time_t lastUsed;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] Favorites persist across restarts
|
|
||||||
- [ ] Recent folders tracked correctly
|
|
||||||
- [ ] JSON format clean and readable
|
|
||||||
- [ ] Handles missing config gracefully
|
|
||||||
- [ ] Unit tests cover edge cases
|
|
||||||
- [ ] API documented
|
|
||||||
|
|
||||||
**Estimated Time**: 6-8 hours
|
|
||||||
**Priority**: Low
|
|
||||||
**Dependencies**: None (standalone)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 7: Testing and Documentation (Issue #13)
|
|
||||||
|
|
||||||
**Goal**: Comprehensive test coverage and documentation.
|
|
||||||
|
|
||||||
### Tasks
|
|
||||||
- [ ] Achieve >80% code coverage
|
|
||||||
- [ ] Integration tests with real Nextcloud:
|
|
||||||
- Test against cloud.tomusan.com
|
|
||||||
- Test against disobedient.cloud
|
|
||||||
- Verify all operations work
|
|
||||||
- [ ] Mock server for offline testing:
|
|
||||||
- Mock HTTP responses
|
|
||||||
- Simulate errors
|
|
||||||
- Test edge cases
|
|
||||||
- [ ] Performance testing:
|
|
||||||
- Large file uploads
|
|
||||||
- Many small files
|
|
||||||
- Concurrent operations
|
|
||||||
- [ ] Generate Doxygen documentation
|
|
||||||
- [ ] Write architecture document
|
|
||||||
- [ ] Create usage examples
|
|
||||||
- [ ] Document build process
|
|
||||||
- [ ] Add API reference
|
|
||||||
|
|
||||||
### Documentation Structure
|
|
||||||
```
|
|
||||||
docs/
|
|
||||||
├── api.md # Full API reference
|
|
||||||
├── architecture.md # Library design and internals
|
|
||||||
├── building.md # Build instructions
|
|
||||||
├── examples.md # Usage examples
|
|
||||||
├── testing.md # How to run tests
|
|
||||||
├── contributing.md # Contribution guidelines
|
|
||||||
└── changelog.md # Version history
|
|
||||||
```
|
|
||||||
|
|
||||||
### Acceptance Criteria
|
|
||||||
- [ ] All classes have Doxygen comments
|
|
||||||
- [ ] Code coverage >80%
|
|
||||||
- [ ] Integration tests pass
|
|
||||||
- [ ] Documentation complete
|
|
||||||
- [ ] Examples compile and run
|
|
||||||
- [ ] Ready for platform integration
|
|
||||||
|
|
||||||
**Estimated Time**: 10-12 hours
|
|
||||||
**Priority**: High
|
|
||||||
**Dependencies**: All phases complete
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Issues to Create
|
|
||||||
|
|
||||||
Based on this plan, create the following Gitea issues:
|
|
||||||
|
|
||||||
### Issue: Initialize libnextcloud Project Structure
|
|
||||||
**Labels**: library, setup, priority:critical
|
|
||||||
**Description**:
|
|
||||||
```
|
|
||||||
Set up the shared library project structure and build system for libnextcloud.
|
|
||||||
|
|
||||||
## Tasks
|
|
||||||
- [ ] Create `shared/` directory structure
|
|
||||||
- [ ] Set up CMakeLists.txt for library
|
|
||||||
- [ ] Create version.hpp and types.hpp
|
|
||||||
- [ ] Set up Google Test framework
|
|
||||||
- [ ] Create basic README
|
|
||||||
- [ ] Add pkg-config file generation
|
|
||||||
- [ ] Verify library compiles standalone
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
- libcurl 7.68+
|
|
||||||
- mbedTLS 2.16+
|
|
||||||
- tinyxml2 9.0+
|
|
||||||
- Google Test 1.11+
|
|
||||||
|
|
||||||
## Acceptance Criteria
|
|
||||||
- [ ] CMake builds library successfully
|
|
||||||
- [ ] Can link against library from test project
|
|
||||||
- [ ] Version info accessible at runtime
|
|
||||||
- [ ] Ready for component implementation
|
|
||||||
|
|
||||||
Estimated: 4-6 hours
|
|
||||||
Blocks: #8, #9, #10, #11, #12, #13
|
|
||||||
```
|
|
||||||
|
|
||||||
### Keep Existing Issues (Update Dependencies)
|
|
||||||
|
|
||||||
**Issue #8**: Design and implement WebDAV client
|
|
||||||
- Add dependency: "Requires libnextcloud scaffolding (new issue)"
|
|
||||||
- Priority: High
|
|
||||||
- Estimated: 12-16 hours
|
|
||||||
|
|
||||||
**Issue #9**: Implement authentication system
|
|
||||||
- Add dependency: "Requires #8"
|
|
||||||
- Priority: High
|
|
||||||
- Estimated: 6-8 hours
|
|
||||||
|
|
||||||
**Issue #10**: Implement file upload functionality
|
|
||||||
- Add dependency: "Requires #8, #9"
|
|
||||||
- Priority: High
|
|
||||||
- Estimated: 10-12 hours
|
|
||||||
|
|
||||||
**Issue #11**: Implement folder management
|
|
||||||
- Add dependency: "Requires #8, #9"
|
|
||||||
- Priority: Medium
|
|
||||||
- Estimated: 8-10 hours
|
|
||||||
|
|
||||||
**Issue #12**: Implement favorites and recent folders
|
|
||||||
- Priority: Low
|
|
||||||
- Estimated: 6-8 hours
|
|
||||||
|
|
||||||
**Issue #13**: Write unit tests for shared library
|
|
||||||
- Add dependency: "Requires #8-#12"
|
|
||||||
- Priority: High
|
|
||||||
- Estimated: 10-12 hours
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Build System Design
|
|
||||||
|
|
||||||
### CMakeLists.txt Structure
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
project(libnextcloud VERSION 0.1.0 LANGUAGES CXX)
|
|
||||||
|
|
||||||
# C++17 required
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
|
|
||||||
# Library sources
|
|
||||||
add_library(nextcloud
|
|
||||||
src/webdav_client.cpp
|
|
||||||
src/auth.cpp
|
|
||||||
src/upload_manager.cpp
|
|
||||||
src/folder_manager.cpp
|
|
||||||
src/config.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Include directories
|
|
||||||
target_include_directories(nextcloud
|
|
||||||
PUBLIC
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
PRIVATE
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
)
|
|
||||||
|
|
||||||
# Dependencies
|
|
||||||
find_package(CURL REQUIRED)
|
|
||||||
find_package(MbedTLS REQUIRED)
|
|
||||||
find_package(tinyxml2 REQUIRED)
|
|
||||||
|
|
||||||
target_link_libraries(nextcloud
|
|
||||||
PUBLIC
|
|
||||||
CURL::libcurl
|
|
||||||
MbedTLS::mbedtls
|
|
||||||
tinyxml2::tinyxml2
|
|
||||||
)
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(tests)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Install rules
|
|
||||||
install(TARGETS nextcloud EXPORT nextcloudTargets)
|
|
||||||
install(DIRECTORY include/ DESTINATION include)
|
|
||||||
install(EXPORT nextcloudTargets
|
|
||||||
FILE nextcloudTargets.cmake
|
|
||||||
NAMESPACE nextcloud::
|
|
||||||
DESTINATION lib/cmake/nextcloud
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Platform-Specific Considerations
|
|
||||||
|
|
||||||
**Nintendo 3DS**:
|
|
||||||
- Static library only (no shared objects)
|
|
||||||
- mbedTLS available via dkp-pacman
|
|
||||||
- libcurl with 3DS patches
|
|
||||||
- Filesystem: `/nextcloud-share/config.json`
|
|
||||||
|
|
||||||
**Nintendo Switch**:
|
|
||||||
- Static library
|
|
||||||
- Standard libcurl and mbedTLS
|
|
||||||
- Filesystem: `/switch/nextcloud-share/config.json`
|
|
||||||
|
|
||||||
**Linux/PC**:
|
|
||||||
- Shared library (.so) or static
|
|
||||||
- System libcurl and mbedTLS
|
|
||||||
- Filesystem: `~/.config/nextcloud-share/config.json`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
- Mock all external dependencies (HTTP, filesystem)
|
|
||||||
- Test each class in isolation
|
|
||||||
- Cover edge cases and error conditions
|
|
||||||
- Fast execution (<1 second total)
|
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
- Real HTTP requests to test Nextcloud servers
|
|
||||||
- Require valid credentials from config.json
|
|
||||||
- Test full workflows end-to-end
|
|
||||||
- Can be skipped if credentials not available
|
|
||||||
|
|
||||||
### Performance Tests
|
|
||||||
- Upload 1GB file and measure time
|
|
||||||
- Upload 1000 small files
|
|
||||||
- Concurrent uploads
|
|
||||||
- Memory usage profiling
|
|
||||||
|
|
||||||
### Test Configuration
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"test": {
|
|
||||||
"servers": [
|
|
||||||
{
|
|
||||||
"name": "tomusan",
|
|
||||||
"url": "https://cloud.tomusan.com",
|
|
||||||
"username": "test",
|
|
||||||
"password": "xxx"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "disobedient",
|
|
||||||
"url": "https://disobedient.cloud/nextcloud",
|
|
||||||
"username": "test",
|
|
||||||
"password": "xxx"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Timeline Estimate
|
|
||||||
|
|
||||||
**Total Estimated Time**: 56-74 hours
|
|
||||||
|
|
||||||
| Phase | Tasks | Estimated Time |
|
|
||||||
|-------|-------|----------------|
|
|
||||||
| 1. Scaffolding | Project setup | 4-6 hours |
|
|
||||||
| 2. WebDAV Client | HTTP/WebDAV implementation | 12-16 hours |
|
|
||||||
| 3. Authentication | Auth system | 6-8 hours |
|
|
||||||
| 4. Upload Manager | File uploads | 10-12 hours |
|
|
||||||
| 5. Folder Management | Folder operations | 8-10 hours |
|
|
||||||
| 6. Favorites/Recent | Config persistence | 6-8 hours |
|
|
||||||
| 7. Testing/Docs | Tests and docs | 10-12 hours |
|
|
||||||
|
|
||||||
**Realistic Timeline**: 2-3 weeks working part-time (15-20 hrs/week)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Success Criteria
|
|
||||||
|
|
||||||
The library is complete when:
|
|
||||||
|
|
||||||
- ✅ All phases implemented and tested
|
|
||||||
- ✅ Code coverage >80%
|
|
||||||
- ✅ Integration tests pass with real Nextcloud
|
|
||||||
- ✅ API documentation complete
|
|
||||||
- ✅ Examples compile and run
|
|
||||||
- ✅ Can be integrated into 3DS app
|
|
||||||
- ✅ Ready for additional platforms (Switch, Wii U, etc.)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. **Review this plan** - Adjust scope, estimates, priorities
|
|
||||||
2. **Create Gitea issues** - One for scaffolding, update existing issues
|
|
||||||
3. **Start Phase 1** - Set up project structure
|
|
||||||
4. **Implement phases sequentially** - Each phase depends on previous
|
|
||||||
5. **Test continuously** - Don't defer testing to the end
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Ready to proceed?** Let's create the issues and start building!
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
project(libnextcloud VERSION 0.1.0 LANGUAGES CXX)
|
|
||||||
|
|
||||||
# C++17 required
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
||||||
|
|
||||||
# Options
|
|
||||||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
|
||||||
option(BUILD_TESTING "Build tests" ON)
|
|
||||||
option(BUILD_EXAMPLES "Build examples" OFF)
|
|
||||||
|
|
||||||
# Library sources (currently empty, will be populated as we implement components)
|
|
||||||
set(NEXTCLOUD_SOURCES
|
|
||||||
# src/webdav_client.cpp # Will be added in future
|
|
||||||
# src/auth.cpp # Will be added in future
|
|
||||||
# src/upload_manager.cpp # Will be added in future
|
|
||||||
# src/folder_manager.cpp # Will be added in future
|
|
||||||
# src/config.cpp # Will be added in future
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create library target
|
|
||||||
# For now, it's header-only (version.hpp and types.hpp)
|
|
||||||
# We'll add sources when we implement components
|
|
||||||
add_library(nextcloud INTERFACE)
|
|
||||||
|
|
||||||
# Include directories
|
|
||||||
target_include_directories(nextcloud
|
|
||||||
INTERFACE
|
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
||||||
$<INSTALL_INTERFACE:include>
|
|
||||||
)
|
|
||||||
|
|
||||||
# Require C++17 for consumers
|
|
||||||
target_compile_features(nextcloud INTERFACE cxx_std_17)
|
|
||||||
|
|
||||||
# Dependencies (will be uncommented as we add implementation)
|
|
||||||
# find_package(CURL REQUIRED)
|
|
||||||
# find_package(MbedTLS REQUIRED)
|
|
||||||
# find_package(tinyxml2 REQUIRED)
|
|
||||||
|
|
||||||
# Link libraries (commented out until we have actual implementation)
|
|
||||||
# target_link_libraries(nextcloud
|
|
||||||
# PUBLIC
|
|
||||||
# CURL::libcurl
|
|
||||||
# MbedTLS::mbedtls
|
|
||||||
# tinyxml2::tinyxml2
|
|
||||||
# )
|
|
||||||
|
|
||||||
# Compiler warnings
|
|
||||||
if(MSVC)
|
|
||||||
target_compile_options(nextcloud INTERFACE /W4)
|
|
||||||
else()
|
|
||||||
target_compile_options(nextcloud INTERFACE -Wall -Wextra -Wpedantic)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(tests)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Examples
|
|
||||||
if(BUILD_EXAMPLES)
|
|
||||||
add_subdirectory(examples)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Install rules
|
|
||||||
install(TARGETS nextcloud
|
|
||||||
EXPORT nextcloudTargets
|
|
||||||
LIBRARY DESTINATION lib
|
|
||||||
ARCHIVE DESTINATION lib
|
|
||||||
RUNTIME DESTINATION bin
|
|
||||||
INCLUDES DESTINATION include
|
|
||||||
)
|
|
||||||
|
|
||||||
install(DIRECTORY include/
|
|
||||||
DESTINATION include
|
|
||||||
FILES_MATCHING PATTERN "*.hpp"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate and install CMake config files
|
|
||||||
include(CMakePackageConfigHelpers)
|
|
||||||
|
|
||||||
write_basic_package_version_file(
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
|
|
||||||
VERSION ${PROJECT_VERSION}
|
|
||||||
COMPATIBILITY AnyNewerVersion
|
|
||||||
)
|
|
||||||
|
|
||||||
configure_package_config_file(
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/nextcloudConfig.cmake.in"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
|
|
||||||
INSTALL_DESTINATION lib/cmake/nextcloud
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfig.cmake"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/nextcloudConfigVersion.cmake"
|
|
||||||
DESTINATION lib/cmake/nextcloud
|
|
||||||
)
|
|
||||||
|
|
||||||
install(EXPORT nextcloudTargets
|
|
||||||
FILE nextcloudTargets.cmake
|
|
||||||
NAMESPACE nextcloud::
|
|
||||||
DESTINATION lib/cmake/nextcloud
|
|
||||||
)
|
|
||||||
|
|
||||||
# pkg-config file
|
|
||||||
configure_file(
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/libnextcloud.pc.in"
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
|
|
||||||
@ONLY
|
|
||||||
)
|
|
||||||
|
|
||||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnextcloud.pc"
|
|
||||||
DESTINATION lib/pkgconfig
|
|
||||||
)
|
|
||||||
|
|
||||||
# Print configuration summary
|
|
||||||
message(STATUS "")
|
|
||||||
message(STATUS "libnextcloud Configuration Summary:")
|
|
||||||
message(STATUS " Version: ${PROJECT_VERSION}")
|
|
||||||
message(STATUS " Build type: ${CMAKE_BUILD_TYPE}")
|
|
||||||
message(STATUS " C++ standard: C++${CMAKE_CXX_STANDARD}")
|
|
||||||
message(STATUS " Shared libraries: ${BUILD_SHARED_LIBS}")
|
|
||||||
message(STATUS " Build tests: ${BUILD_TESTING}")
|
|
||||||
message(STATUS " Build examples: ${BUILD_EXAMPLES}")
|
|
||||||
message(STATUS " Install prefix: ${CMAKE_INSTALL_PREFIX}")
|
|
||||||
message(STATUS "")
|
|
||||||
288
shared/README.md
288
shared/README.md
@@ -1,288 +0,0 @@
|
|||||||
# libnextcloud
|
|
||||||
|
|
||||||
Cross-platform C++17 library for Nextcloud connectivity on embedded devices and homebrew platforms.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
`libnextcloud` provides a clean, modern C++ API for interacting with Nextcloud servers. It's designed to work on resource-constrained devices like game console homebrew (Nintendo 3DS, Switch, Wii U) while also supporting desktop platforms.
|
|
||||||
|
|
||||||
**Status**: 🚧 In Development - Scaffolding complete, components being implemented
|
|
||||||
|
|
||||||
## Features (Planned)
|
|
||||||
|
|
||||||
- ✅ **Version Management**: Semantic versioning with compile-time and runtime queries
|
|
||||||
- ✅ **Type System**: Comprehensive error codes and data structures
|
|
||||||
- 🚧 **WebDAV Client**: HTTP/HTTPS communication with Nextcloud WebDAV API
|
|
||||||
- 🚧 **Authentication**: Basic Auth (OAuth2 planned)
|
|
||||||
- 🚧 **File Upload**: Streaming uploads with chunking and progress tracking
|
|
||||||
- 🚧 **Folder Management**: List, create, navigate remote folders
|
|
||||||
- 🚧 **Favorites & Recent**: Persistent user preferences
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
### Build Tools
|
|
||||||
- **CMake** 3.15 or later
|
|
||||||
- **C++17 compiler**: GCC 7+, Clang 5+, MSVC 2017+
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
**Required** (when implementation complete):
|
|
||||||
- libcurl 7.68+
|
|
||||||
- mbedTLS 2.16+
|
|
||||||
- tinyxml2 9.0+
|
|
||||||
|
|
||||||
**Testing**:
|
|
||||||
- Google Test 1.11+
|
|
||||||
|
|
||||||
**Header-Only**:
|
|
||||||
- nlohmann/json 3.10+ (for configuration, future)
|
|
||||||
|
|
||||||
### Platform Support
|
|
||||||
|
|
||||||
| Platform | Status | Notes |
|
|
||||||
|----------|--------|-------|
|
|
||||||
| Linux | ✅ Development | Primary development platform |
|
|
||||||
| Nintendo 3DS | ✅ Planned | Via devkitARM in container |
|
|
||||||
| Nintendo Switch | 🔜 Planned | |
|
|
||||||
| Wii U | 🔜 Planned | |
|
|
||||||
| PlayStation Vita | 🔜 Planned | |
|
|
||||||
| Windows | 🔜 Planned | |
|
|
||||||
| macOS | 🔜 Planned | |
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Configure (modern CMake style)
|
|
||||||
cmake -S . -B build
|
|
||||||
|
|
||||||
# Build
|
|
||||||
cmake --build build
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
cmake --build build --target test
|
|
||||||
# or with CTest for detailed output:
|
|
||||||
# ctest --test-dir build --output-on-failure
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using in Your Project
|
|
||||||
|
|
||||||
#### CMake
|
|
||||||
|
|
||||||
```cmake
|
|
||||||
find_package(nextcloud REQUIRED)
|
|
||||||
|
|
||||||
add_executable(my_app main.cpp)
|
|
||||||
target_link_libraries(my_app nextcloud::nextcloud)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### pkg-config
|
|
||||||
|
|
||||||
```bash
|
|
||||||
g++ -std=c++17 main.cpp $(pkg-config --cflags --libs libnextcloud)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Basic Usage
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <nextcloud/version.hpp>
|
|
||||||
#include <nextcloud/types.hpp>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
// Get library version
|
|
||||||
std::cout << "libnextcloud v" << nextcloud::getVersionString() << std::endl;
|
|
||||||
|
|
||||||
// Check version compatibility
|
|
||||||
if (nextcloud::isVersionAtLeast(0, 1, 0)) {
|
|
||||||
std::cout << "Version is compatible!" << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use error types
|
|
||||||
nextcloud::NextcloudError error = nextcloud::NextcloudError::Success;
|
|
||||||
std::cout << "Status: " << nextcloud::errorToString(error) << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
shared/
|
|
||||||
├── CMakeLists.txt # Build configuration
|
|
||||||
├── README.md # This file
|
|
||||||
├── libnextcloud.pc.in # pkg-config template
|
|
||||||
├── nextcloudConfig.cmake.in # CMake config template
|
|
||||||
├── include/
|
|
||||||
│ └── nextcloud/
|
|
||||||
│ ├── version.hpp # Version information
|
|
||||||
│ ├── types.hpp # Common types and errors
|
|
||||||
│ ├── webdav_client.hpp # (Coming soon)
|
|
||||||
│ ├── auth.hpp # (Coming soon)
|
|
||||||
│ ├── upload_manager.hpp # (Coming soon)
|
|
||||||
│ ├── folder_manager.hpp # (Coming soon)
|
|
||||||
│ └── config.hpp # (Coming soon)
|
|
||||||
├── src/ # Implementation files (future)
|
|
||||||
├── tests/
|
|
||||||
│ ├── CMakeLists.txt
|
|
||||||
│ └── smoke_test.cpp # Basic tests
|
|
||||||
├── examples/ # Usage examples (future)
|
|
||||||
└── docs/ # Documentation (future)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Building for Platforms
|
|
||||||
|
|
||||||
### Linux (Development)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir build && cd build
|
|
||||||
cmake ..
|
|
||||||
make
|
|
||||||
make test
|
|
||||||
```
|
|
||||||
|
|
||||||
### Nintendo 3DS (Container)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# From project root
|
|
||||||
podman run --rm -v .:/project:z tomusan/devkitarm-3ds:latest \
|
|
||||||
bash -c "cd /project/shared && mkdir -p build && cd build && cmake .. && make"
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Documentation
|
|
||||||
|
|
||||||
### Version Information
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <nextcloud/version.hpp>
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
nextcloud::VERSION_MAJOR // 0
|
|
||||||
nextcloud::VERSION_MINOR // 1
|
|
||||||
nextcloud::VERSION_PATCH // 0
|
|
||||||
nextcloud::VERSION_STRING // "0.1.0"
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
std::string getVersionString();
|
|
||||||
void getVersion(int& major, int& minor, int& patch);
|
|
||||||
bool isVersionAtLeast(int major, int minor, int patch);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <nextcloud/types.hpp>
|
|
||||||
|
|
||||||
// Error codes
|
|
||||||
enum class NextcloudError {
|
|
||||||
Success,
|
|
||||||
NetworkError,
|
|
||||||
AuthenticationFailed,
|
|
||||||
ServerError,
|
|
||||||
FileNotFound,
|
|
||||||
// ... more error codes
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert to string
|
|
||||||
const char* errorToString(NextcloudError error);
|
|
||||||
|
|
||||||
// Result type
|
|
||||||
nextcloud::Result<int> result;
|
|
||||||
if (result.isSuccess()) {
|
|
||||||
// Use result.value
|
|
||||||
} else {
|
|
||||||
std::cerr << result.errorMessage() << std::endl;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Data Structures
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Upload progress
|
|
||||||
struct UploadProgress {
|
|
||||||
std::string filename;
|
|
||||||
uint64_t bytesUploaded;
|
|
||||||
uint64_t totalBytes;
|
|
||||||
float percentComplete;
|
|
||||||
float bytesPerSecond;
|
|
||||||
int secondsRemaining;
|
|
||||||
};
|
|
||||||
|
|
||||||
// File information
|
|
||||||
struct FileInfo {
|
|
||||||
std::string name;
|
|
||||||
std::string path;
|
|
||||||
bool isDirectory;
|
|
||||||
uint64_t size;
|
|
||||||
std::time_t modifiedTime;
|
|
||||||
std::string contentType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Folder information
|
|
||||||
struct FolderInfo {
|
|
||||||
std::string path;
|
|
||||||
std::string displayName;
|
|
||||||
std::time_t lastUsed;
|
|
||||||
bool isFavorite;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
cd build
|
|
||||||
ctest --output-on-failure
|
|
||||||
|
|
||||||
# Or use the custom target
|
|
||||||
make run_tests
|
|
||||||
|
|
||||||
# Run specific test
|
|
||||||
./tests/smoke_test
|
|
||||||
```
|
|
||||||
|
|
||||||
## Development Status
|
|
||||||
|
|
||||||
- ✅ **Phase 1: Scaffolding** - Complete
|
|
||||||
- Directory structure
|
|
||||||
- CMake build system
|
|
||||||
- Version and types headers
|
|
||||||
- Google Test integration
|
|
||||||
- Basic smoke tests
|
|
||||||
|
|
||||||
- 🚧 **Phase 2: WebDAV Client** - Not started
|
|
||||||
- Issue #8
|
|
||||||
|
|
||||||
- 🚧 **Phase 3: Authentication** - Not started
|
|
||||||
- Issue #9
|
|
||||||
|
|
||||||
- 🚧 **Phase 4: Upload Manager** - Not started
|
|
||||||
- Issue #10
|
|
||||||
|
|
||||||
- 🚧 **Phase 5: Folder Management** - Not started
|
|
||||||
- Issue #11
|
|
||||||
|
|
||||||
- 🚧 **Phase 6: Favorites & Recent** - Not started
|
|
||||||
- Issue #12
|
|
||||||
|
|
||||||
- 🚧 **Phase 7: Testing & Docs** - Not started
|
|
||||||
- Issue #13
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
See [CONTRIBUTING.md](../CONTRIBUTING.md) in the project root.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
[License TBD - to be determined]
|
|
||||||
|
|
||||||
## Related Documentation
|
|
||||||
|
|
||||||
- [Project Plan](../.plans/CreateLibNextcloud.md)
|
|
||||||
- [Issue #25](https://git.tomusan.com/maj/nextcloud-share/issues/25) - Initialize libnextcloud
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Note**: This library is in active development. The API is subject to change until version 1.0.0.
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
#ifndef NEXTCLOUD_TYPES_HPP
|
|
||||||
#define NEXTCLOUD_TYPES_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
namespace nextcloud {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Error codes for Nextcloud operations
|
|
||||||
*/
|
|
||||||
enum class NextcloudError {
|
|
||||||
Success = 0,
|
|
||||||
|
|
||||||
// Network errors
|
|
||||||
NetworkError,
|
|
||||||
ConnectionFailed,
|
|
||||||
Timeout,
|
|
||||||
SSLError,
|
|
||||||
|
|
||||||
// Authentication errors
|
|
||||||
AuthenticationFailed,
|
|
||||||
InvalidCredentials,
|
|
||||||
Unauthorized,
|
|
||||||
|
|
||||||
// Server errors
|
|
||||||
ServerError,
|
|
||||||
ServiceUnavailable,
|
|
||||||
InsufficientStorage,
|
|
||||||
|
|
||||||
// File/path errors
|
|
||||||
FileNotFound,
|
|
||||||
PathNotFound,
|
|
||||||
InvalidPath,
|
|
||||||
FileAlreadyExists,
|
|
||||||
PathAlreadyExists,
|
|
||||||
|
|
||||||
// Operation errors
|
|
||||||
OperationFailed,
|
|
||||||
OperationCancelled,
|
|
||||||
InvalidOperation,
|
|
||||||
|
|
||||||
// Parsing/format errors
|
|
||||||
ParseError,
|
|
||||||
InvalidResponse,
|
|
||||||
UnsupportedFormat,
|
|
||||||
|
|
||||||
// Configuration errors
|
|
||||||
InvalidConfiguration,
|
|
||||||
MissingConfiguration,
|
|
||||||
|
|
||||||
// Unknown
|
|
||||||
Unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Convert error code to human-readable string
|
|
||||||
* @param error The error code
|
|
||||||
* @return String description of the error
|
|
||||||
*/
|
|
||||||
inline const char* errorToString(NextcloudError error) {
|
|
||||||
switch (error) {
|
|
||||||
case NextcloudError::Success: return "Success";
|
|
||||||
case NextcloudError::NetworkError: return "Network error";
|
|
||||||
case NextcloudError::ConnectionFailed: return "Connection failed";
|
|
||||||
case NextcloudError::Timeout: return "Operation timed out";
|
|
||||||
case NextcloudError::SSLError: return "SSL/TLS error";
|
|
||||||
case NextcloudError::AuthenticationFailed: return "Authentication failed";
|
|
||||||
case NextcloudError::InvalidCredentials: return "Invalid credentials";
|
|
||||||
case NextcloudError::Unauthorized: return "Unauthorized";
|
|
||||||
case NextcloudError::ServerError: return "Server error";
|
|
||||||
case NextcloudError::ServiceUnavailable: return "Service unavailable";
|
|
||||||
case NextcloudError::InsufficientStorage: return "Insufficient storage";
|
|
||||||
case NextcloudError::FileNotFound: return "File not found";
|
|
||||||
case NextcloudError::PathNotFound: return "Path not found";
|
|
||||||
case NextcloudError::InvalidPath: return "Invalid path";
|
|
||||||
case NextcloudError::FileAlreadyExists: return "File already exists";
|
|
||||||
case NextcloudError::PathAlreadyExists: return "Path already exists";
|
|
||||||
case NextcloudError::OperationFailed: return "Operation failed";
|
|
||||||
case NextcloudError::OperationCancelled: return "Operation cancelled";
|
|
||||||
case NextcloudError::InvalidOperation: return "Invalid operation";
|
|
||||||
case NextcloudError::ParseError: return "Parse error";
|
|
||||||
case NextcloudError::InvalidResponse: return "Invalid response";
|
|
||||||
case NextcloudError::UnsupportedFormat: return "Unsupported format";
|
|
||||||
case NextcloudError::InvalidConfiguration: return "Invalid configuration";
|
|
||||||
case NextcloudError::MissingConfiguration: return "Missing configuration";
|
|
||||||
case NextcloudError::Unknown: return "Unknown error";
|
|
||||||
default: return "Unrecognized error";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Result type for operations that can fail
|
|
||||||
* @tparam T The success value type
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
struct Result {
|
|
||||||
NextcloudError error;
|
|
||||||
T value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if the operation was successful
|
|
||||||
* @return True if no error occurred
|
|
||||||
*/
|
|
||||||
bool isSuccess() const { return error == NextcloudError::Success; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if an error occurred
|
|
||||||
* @return True if an error occurred
|
|
||||||
*/
|
|
||||||
bool isError() const { return error != NextcloudError::Success; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get error message
|
|
||||||
* @return Human-readable error description
|
|
||||||
*/
|
|
||||||
const char* errorMessage() const { return errorToString(error); }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Upload progress information
|
|
||||||
*/
|
|
||||||
struct UploadProgress {
|
|
||||||
std::string filename; ///< Name of file being uploaded
|
|
||||||
uint64_t bytesUploaded; ///< Number of bytes uploaded so far
|
|
||||||
uint64_t totalBytes; ///< Total file size in bytes
|
|
||||||
float percentComplete; ///< Completion percentage (0.0 - 100.0)
|
|
||||||
float bytesPerSecond; ///< Current transfer speed
|
|
||||||
int secondsRemaining; ///< Estimated seconds remaining (-1 if unknown)
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Information about a file or directory
|
|
||||||
*/
|
|
||||||
struct FileInfo {
|
|
||||||
std::string name; ///< File or directory name
|
|
||||||
std::string path; ///< Full path on server
|
|
||||||
bool isDirectory; ///< True if this is a directory
|
|
||||||
uint64_t size; ///< File size in bytes (0 for directories)
|
|
||||||
std::time_t modifiedTime; ///< Last modification time (Unix timestamp)
|
|
||||||
std::string contentType; ///< MIME type (e.g., "image/png")
|
|
||||||
std::string etag; ///< ETag for change detection
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Information about a favorite or recent folder
|
|
||||||
*/
|
|
||||||
struct FolderInfo {
|
|
||||||
std::string path; ///< Full path on server
|
|
||||||
std::string displayName; ///< User-friendly name
|
|
||||||
std::time_t lastUsed; ///< Last access time (Unix timestamp)
|
|
||||||
bool isFavorite; ///< True if marked as favorite
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief HTTP response information
|
|
||||||
*/
|
|
||||||
struct HttpResponse {
|
|
||||||
int statusCode; ///< HTTP status code (e.g., 200, 404)
|
|
||||||
std::string body; ///< Response body
|
|
||||||
std::string contentType; ///< Content-Type header value
|
|
||||||
NextcloudError error; ///< Error code if request failed
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if response indicates success (2xx status code)
|
|
||||||
* @return True if status code is 200-299
|
|
||||||
*/
|
|
||||||
bool isSuccess() const {
|
|
||||||
return statusCode >= 200 && statusCode < 300 && error == NextcloudError::Success;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace nextcloud
|
|
||||||
|
|
||||||
#endif // NEXTCLOUD_TYPES_HPP
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#ifndef NEXTCLOUD_VERSION_HPP
|
|
||||||
#define NEXTCLOUD_VERSION_HPP
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace nextcloud {
|
|
||||||
|
|
||||||
// Semantic versioning
|
|
||||||
constexpr int VERSION_MAJOR = 0;
|
|
||||||
constexpr int VERSION_MINOR = 1;
|
|
||||||
constexpr int VERSION_PATCH = 0;
|
|
||||||
|
|
||||||
// Build metadata
|
|
||||||
constexpr const char* VERSION_STRING = "0.1.0";
|
|
||||||
constexpr const char* BUILD_DATE = __DATE__;
|
|
||||||
constexpr const char* BUILD_TIME = __TIME__;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the library version as a string
|
|
||||||
* @return Version string in format "MAJOR.MINOR.PATCH"
|
|
||||||
*/
|
|
||||||
inline std::string getVersionString() {
|
|
||||||
return VERSION_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the library version components
|
|
||||||
* @param major Output parameter for major version
|
|
||||||
* @param minor Output parameter for minor version
|
|
||||||
* @param patch Output parameter for patch version
|
|
||||||
*/
|
|
||||||
inline void getVersion(int& major, int& minor, int& patch) {
|
|
||||||
major = VERSION_MAJOR;
|
|
||||||
minor = VERSION_MINOR;
|
|
||||||
patch = VERSION_PATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check if the library version is at least the specified version
|
|
||||||
* @param major Required major version
|
|
||||||
* @param minor Required minor version
|
|
||||||
* @param patch Required patch version
|
|
||||||
* @return True if current version >= required version
|
|
||||||
*/
|
|
||||||
inline bool isVersionAtLeast(int major, int minor, int patch) {
|
|
||||||
if (VERSION_MAJOR > major) return true;
|
|
||||||
if (VERSION_MAJOR < major) return false;
|
|
||||||
|
|
||||||
if (VERSION_MINOR > minor) return true;
|
|
||||||
if (VERSION_MINOR < minor) return false;
|
|
||||||
|
|
||||||
return VERSION_PATCH >= patch;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace nextcloud
|
|
||||||
|
|
||||||
#endif // NEXTCLOUD_VERSION_HPP
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
|
||||||
exec_prefix=${prefix}
|
|
||||||
libdir=${exec_prefix}/lib
|
|
||||||
includedir=${prefix}/include
|
|
||||||
|
|
||||||
Name: libnextcloud
|
|
||||||
Description: Cross-platform C++ library for Nextcloud connectivity
|
|
||||||
Version: @PROJECT_VERSION@
|
|
||||||
Requires:
|
|
||||||
Cflags: -I${includedir}
|
|
||||||
Libs: -L${libdir} -lnextcloud
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
@PACKAGE_INIT@
|
|
||||||
|
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/nextcloudTargets.cmake")
|
|
||||||
|
|
||||||
check_required_components(nextcloud)
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
|
|
||||||
# Find Google Test
|
|
||||||
find_package(GTest REQUIRED)
|
|
||||||
|
|
||||||
# Include Google Test helpers
|
|
||||||
include(GoogleTest)
|
|
||||||
|
|
||||||
# Test executable
|
|
||||||
add_executable(smoke_test
|
|
||||||
smoke_test.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Link against the library and GTest
|
|
||||||
target_link_libraries(smoke_test
|
|
||||||
PRIVATE
|
|
||||||
nextcloud
|
|
||||||
GTest::GTest
|
|
||||||
GTest::Main
|
|
||||||
)
|
|
||||||
|
|
||||||
# Discover and register tests
|
|
||||||
gtest_discover_tests(smoke_test)
|
|
||||||
|
|
||||||
# Add custom target to run tests
|
|
||||||
add_custom_target(run_tests
|
|
||||||
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
|
|
||||||
DEPENDS smoke_test
|
|
||||||
COMMENT "Running tests..."
|
|
||||||
)
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include <nextcloud/version.hpp>
|
|
||||||
#include <nextcloud/types.hpp>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file smoke_test.cpp
|
|
||||||
* @brief Basic smoke tests to verify library setup
|
|
||||||
*
|
|
||||||
* These tests ensure that the library headers compile correctly
|
|
||||||
* and basic functionality works as expected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Test version information
|
|
||||||
TEST(VersionTest, VersionConstants) {
|
|
||||||
EXPECT_EQ(nextcloud::VERSION_MAJOR, 0);
|
|
||||||
EXPECT_EQ(nextcloud::VERSION_MINOR, 1);
|
|
||||||
EXPECT_EQ(nextcloud::VERSION_PATCH, 0);
|
|
||||||
EXPECT_STREQ(nextcloud::VERSION_STRING, "0.1.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(VersionTest, GetVersionString) {
|
|
||||||
std::string version = nextcloud::getVersionString();
|
|
||||||
EXPECT_EQ(version, "0.1.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(VersionTest, GetVersionComponents) {
|
|
||||||
int major, minor, patch;
|
|
||||||
nextcloud::getVersion(major, minor, patch);
|
|
||||||
EXPECT_EQ(major, 0);
|
|
||||||
EXPECT_EQ(minor, 1);
|
|
||||||
EXPECT_EQ(patch, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(VersionTest, IsVersionAtLeast) {
|
|
||||||
// Current version is 0.1.0
|
|
||||||
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 0, 0));
|
|
||||||
EXPECT_TRUE(nextcloud::isVersionAtLeast(0, 1, 0));
|
|
||||||
EXPECT_FALSE(nextcloud::isVersionAtLeast(0, 2, 0));
|
|
||||||
EXPECT_FALSE(nextcloud::isVersionAtLeast(1, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test error types
|
|
||||||
TEST(TypesTest, ErrorToString) {
|
|
||||||
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::Success), "Success");
|
|
||||||
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::NetworkError), "Network error");
|
|
||||||
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::AuthenticationFailed), "Authentication failed");
|
|
||||||
EXPECT_STREQ(nextcloud::errorToString(nextcloud::NextcloudError::FileNotFound), "File not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, ResultSuccess) {
|
|
||||||
nextcloud::Result<int> result;
|
|
||||||
result.error = nextcloud::NextcloudError::Success;
|
|
||||||
result.value = 42;
|
|
||||||
|
|
||||||
EXPECT_TRUE(result.isSuccess());
|
|
||||||
EXPECT_FALSE(result.isError());
|
|
||||||
EXPECT_EQ(result.value, 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, ResultError) {
|
|
||||||
nextcloud::Result<std::string> result;
|
|
||||||
result.error = nextcloud::NextcloudError::NetworkError;
|
|
||||||
result.value = "";
|
|
||||||
|
|
||||||
EXPECT_FALSE(result.isSuccess());
|
|
||||||
EXPECT_TRUE(result.isError());
|
|
||||||
EXPECT_STREQ(result.errorMessage(), "Network error");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, UploadProgressStruct) {
|
|
||||||
nextcloud::UploadProgress progress;
|
|
||||||
progress.filename = "test.txt";
|
|
||||||
progress.bytesUploaded = 50;
|
|
||||||
progress.totalBytes = 100;
|
|
||||||
progress.percentComplete = 50.0f;
|
|
||||||
progress.bytesPerSecond = 1024.0f;
|
|
||||||
progress.secondsRemaining = 1;
|
|
||||||
|
|
||||||
EXPECT_EQ(progress.filename, "test.txt");
|
|
||||||
EXPECT_EQ(progress.bytesUploaded, 50);
|
|
||||||
EXPECT_EQ(progress.totalBytes, 100);
|
|
||||||
EXPECT_FLOAT_EQ(progress.percentComplete, 50.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, FileInfoStruct) {
|
|
||||||
nextcloud::FileInfo file;
|
|
||||||
file.name = "document.pdf";
|
|
||||||
file.path = "/Documents/document.pdf";
|
|
||||||
file.isDirectory = false;
|
|
||||||
file.size = 1024;
|
|
||||||
file.modifiedTime = 1234567890;
|
|
||||||
file.contentType = "application/pdf";
|
|
||||||
|
|
||||||
EXPECT_EQ(file.name, "document.pdf");
|
|
||||||
EXPECT_EQ(file.path, "/Documents/document.pdf");
|
|
||||||
EXPECT_FALSE(file.isDirectory);
|
|
||||||
EXPECT_EQ(file.size, 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, FolderInfoStruct) {
|
|
||||||
nextcloud::FolderInfo folder;
|
|
||||||
folder.path = "/Photos";
|
|
||||||
folder.displayName = "My Photos";
|
|
||||||
folder.lastUsed = 1234567890;
|
|
||||||
folder.isFavorite = true;
|
|
||||||
|
|
||||||
EXPECT_EQ(folder.path, "/Photos");
|
|
||||||
EXPECT_EQ(folder.displayName, "My Photos");
|
|
||||||
EXPECT_TRUE(folder.isFavorite);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, HttpResponseSuccess) {
|
|
||||||
nextcloud::HttpResponse response;
|
|
||||||
response.statusCode = 200;
|
|
||||||
response.body = "OK";
|
|
||||||
response.contentType = "text/plain";
|
|
||||||
response.error = nextcloud::NextcloudError::Success;
|
|
||||||
|
|
||||||
EXPECT_TRUE(response.isSuccess());
|
|
||||||
EXPECT_EQ(response.statusCode, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(TypesTest, HttpResponseError) {
|
|
||||||
nextcloud::HttpResponse response;
|
|
||||||
response.statusCode = 404;
|
|
||||||
response.body = "Not Found";
|
|
||||||
response.error = nextcloud::NextcloudError::FileNotFound;
|
|
||||||
|
|
||||||
EXPECT_FALSE(response.isSuccess());
|
|
||||||
EXPECT_EQ(response.statusCode, 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user