diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bae0398..67a336f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ main ] + branches: [ master ] pull_request: - branches: [ main ] + branches: [ master ] jobs: test: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5983215..a3e1d6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - See `docs/SIMPLIFIED_ENDPOINT.md` for details - Comprehensive test coverage for endpoint normalization (12 test cases) - New example: `examples/simplified-endpoint/` demonstrating all endpoint formats +- Documentation: `docs/PROJECT_STRUCTURE.md` explaining project organization - Initial release of go-onvif library + +### Changed +- **Project Structure**: Implemented ideal Go project layout + - Moved `soap/` to `internal/soap/` (private implementation) + - Public API remains at root level for clean imports + - Follows Standard Go Project Layout for libraries + - Updated all imports throughout codebase + - See `docs/PROJECT_STRUCTURE.md` and `docs/ARCHITECTURE.md` for details +- Updated `docs/ARCHITECTURE.md` to reflect new project structure - ONVIF Client with context support - Device service implementation - GetDeviceInformation diff --git a/device.go b/device.go index 16e764f..69efc97 100644 --- a/device.go +++ b/device.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "fmt" - "github.com/0x524A/onvif-go/soap" + "github.com/0x524A/onvif-go/internal/soap" ) // Device service namespace diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 8202b6a..b6cbc45 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -6,6 +6,31 @@ go-onvif is a modern, performant Go library for communicating with ONVIF-complia ## Architecture +### Project Structure + +The project follows the **Standard Go Project Layout** for libraries: + +``` +onvif-go/ +├── *.go # Public API (client.go, device.go, media.go, ptz.go, imaging.go) +├── internal/ # Private implementation details +│ └── soap/ # SOAP client (not exported) +├── discovery/ # Device discovery (public subpackage) +├── server/ # ONVIF server implementation (public subpackage) +├── cmd/ # Command-line tools +├── examples/ # Usage examples +├── docs/ # Documentation +├── test/ # Testing utilities +└── testdata/ # Test fixtures +``` + +**Design Rationale:** +- **Root-level API**: Main package at root for clean imports (`github.com/0x524A/onvif-go`) +- **internal/**: Private packages not intended for external use (SOAP implementation) +- **Subpackages**: Additional features like `discovery/` and `server/` +- **cmd/**: Executable applications and tools +- **examples/**: Demonstrate library usage + ### Core Components ``` @@ -27,7 +52,7 @@ go-onvif is a modern, performant Go library for communicating with ONVIF-complia ↓ ┌─────────────────────────────────────────────────────────────┐ │ Transport Layer │ -│ - SOAP Client (soap/soap.go) │ +│ - SOAP Client (internal/soap/soap.go) │ │ - WS-Security Authentication │ │ - XML Marshaling/Unmarshaling │ └─────────────────────────────────────────────────────────────┘ diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..6c7fdce --- /dev/null +++ b/docs/PROJECT_STRUCTURE.md @@ -0,0 +1,390 @@ +# Project Structure + +## Overview + +The `onvif-go` project follows the **Standard Go Project Layout** optimized for a library package. This structure provides clear separation between public APIs, private implementation details, executable commands, and supporting resources. + +## Directory Layout + +``` +onvif-go/ +├── *.go # Public API files (root level) +│ ├── client.go # Main ONVIF client +│ ├── device.go # Device service operations +│ ├── media.go # Media service operations +│ ├── ptz.go # PTZ service operations +│ ├── imaging.go # Imaging service operations +│ ├── types.go # Public type definitions +│ ├── errors.go # Error types and handling +│ └── doc.go # Package documentation +│ +├── internal/ # Private packages (not importable externally) +│ └── soap/ # SOAP client implementation +│ ├── soap.go # SOAP envelope building and parsing +│ └── soap_test.go # SOAP client tests +│ +├── discovery/ # Device discovery subpackage (public) +│ ├── discovery.go # WS-Discovery implementation +│ └── discovery_test.go # Discovery tests +│ +├── server/ # ONVIF server implementation (public) +│ ├── server.go # Main server +│ ├── device.go # Device service handlers +│ ├── media.go # Media service handlers +│ ├── ptz.go # PTZ service handlers +│ ├── imaging.go # Imaging service handlers +│ └── soap/ # Server SOAP handling +│ └── handler.go # SOAP request handler +│ +├── cmd/ # Command-line applications +│ ├── onvif-cli/ # Interactive CLI tool +│ ├── onvif-quick/ # Quick test utility +│ ├── onvif-server/ # Virtual camera server +│ ├── onvif-diagnostics/ # Diagnostic tool +│ └── generate-tests/ # Test generation utility +│ +├── examples/ # Example applications +│ ├── device-info/ # Get device information +│ ├── discovery/ # Discover cameras +│ ├── ptz-control/ # PTZ operations +│ ├── imaging-settings/ # Imaging configuration +│ ├── complete-demo/ # Full feature demo +│ ├── simplified-endpoint/ # Endpoint format demo +│ └── .../ # Additional examples +│ +├── docs/ # Documentation +│ ├── ARCHITECTURE.md # Architecture overview +│ ├── PROJECT_STRUCTURE.md # This file +│ ├── SIMPLIFIED_ENDPOINT.md # Endpoint API docs +│ └── .../ # Additional documentation +│ +├── test/ # Additional test utilities +├── testdata/ # Test fixtures and data +├── testing/ # Testing helpers +│ +├── .github/ # GitHub workflows and configs +│ └── workflows/ +│ └── release.yml # Release automation +│ +├── go.mod # Go module definition +├── go.sum # Dependency checksums +├── Makefile # Build automation +├── Dockerfile # Container image +├── README.md # Project readme +├── CHANGELOG.md # Version history +├── LICENSE # License information +├── CONTRIBUTING.md # Contribution guidelines +├── QUICKSTART.md # Quick start guide +└── BUILDING.md # Build instructions +``` + +## Design Principles + +### 1. Library-First Design + +As a **library package**, the main API lives at the root level: + +```go +import "github.com/0x524A/onvif-go" + +client, err := onvif.NewClient("192.168.1.100") +``` + +**Benefits:** +- Clean, simple import path +- Follows Go conventions for libraries +- Easy to discover and use +- No unnecessary nesting + +### 2. Internal Package for Private Code + +The `internal/` directory contains implementation details not intended for external use: + +```go +// This import is ONLY available within onvif-go: +import "github.com/0x524A/onvif-go/internal/soap" +``` + +**Go's internal package restriction:** +- Cannot be imported by external projects +- Enforced by the Go compiler +- Allows refactoring without breaking changes + +**What goes in internal/**: +- SOAP client implementation +- Protocol-specific details +- Helper functions not part of public API +- Implementation details that might change + +### 3. Subpackages for Additional Features + +Public subpackages for optional or specialized functionality: + +```go +// Discovery subpackage +import "github.com/0x524A/onvif-go/discovery" + +// Server subpackage +import "github.com/0x524A/onvif-go/server" +``` + +**When to create a subpackage:** +- Logically separate feature set +- Can be used independently +- Different import namespace makes sense +- Clear, single responsibility + +### 4. Commands in cmd/ + +Executable applications in `cmd/` directory: + +``` +cmd/ +├── onvif-cli/ # Main CLI tool +├── onvif-server/ # Virtual camera +└── onvif-quick/ # Quick utility +``` + +**Naming convention:** +- Directory name = binary name +- Each cmd has its own `main.go` +- Can import the library: `import "github.com/0x524A/onvif-go"` + +**Build commands:** +```bash +go build ./cmd/onvif-cli +go build ./cmd/onvif-server +``` + +### 5. Examples for Documentation + +The `examples/` directory demonstrates library usage: + +**Structure:** +- Each example is a standalone program +- Clear, focused demonstration +- Can be built and run directly + +**Purpose:** +- Supplement documentation +- Show best practices +- Provide starting points for users + +### 6. Documentation in docs/ + +Comprehensive documentation in `docs/` directory: + +- `ARCHITECTURE.md` - Design and architecture +- `PROJECT_STRUCTURE.md` - This file +- `SIMPLIFIED_ENDPOINT.md` - Feature documentation +- Additional guides as needed + +**Why separate docs/?** +- Keeps root clean +- Organized by topic +- Easy to navigate +- Scalable structure + +## Import Patterns + +### Public API (Root Package) + +```go +// Main client functionality +import "github.com/0x524A/onvif-go" + +client, err := onvif.NewClient("192.168.1.100", + onvif.WithCredentials("admin", "password"), +) +``` + +### Discovery Subpackage + +```go +// Device discovery +import "github.com/0x524A/onvif-go/discovery" + +devices, err := discovery.Discover(ctx, 5*time.Second) +``` + +### Server Subpackage + +```go +// Virtual ONVIF server +import "github.com/0x524A/onvif-go/server" + +srv := server.NewServer( + server.WithCredentials("admin", "admin"), + server.WithAddress(":8080"), +) +``` + +### Internal Package (Library Use Only) + +```go +// Only usable within onvif-go itself +import "github.com/0x524A/onvif-go/internal/soap" + +// External projects CANNOT import internal packages +``` + +## File Organization Best Practices + +### Root Package Files + +Group by service/functionality: +- `client.go` - Client creation and core functionality +- `device.go` - Device service methods +- `media.go` - Media service methods +- `ptz.go` - PTZ service methods +- `imaging.go` - Imaging service methods +- `types.go` - Type definitions +- `errors.go` - Error types +- `doc.go` - Package documentation + +### Test Files + +Co-located with source: +- `client_test.go` - Tests for client.go +- `device_test.go` - Tests for device.go +- Mirrors source file structure + +### Large Packages + +For large packages, consider grouping: +``` +server/ +├── server.go # Main server +├── device.go # Device handlers +├── media.go # Media handlers +├── ptz.go # PTZ handlers +├── imaging.go # Imaging handlers +└── soap/ # SOAP sub-package + └── handler.go +``` + +## Comparison with Other Layouts + +### ❌ Avoid: pkg/ Directory for Libraries + +``` +# DON'T DO THIS for libraries: +my-lib/ +└── pkg/ + └── mylib/ + └── mylib.go + +# Requires: import "github.com/user/my-lib/pkg/mylib" +``` + +**Why not?** +- Unnecessary nesting +- More complex imports +- Not idiomatic for Go libraries +- `pkg/` is for applications with multiple packages + +### ✅ Library Layout (What We Use) + +``` +onvif-go/ +├── *.go # Public API at root +└── internal/ # Private implementation + +# Clean import: import "github.com/user/onvif-go" +``` + +### 📦 Application Layout (Different Use Case) + +For applications (not libraries): +``` +my-app/ +├── cmd/ # Multiple binaries +├── internal/ # Private app code +├── pkg/ # Exported libraries from this app +└── main.go # Or in cmd/ +``` + +## Migration Notes + +### Recent Changes + +**Moved SOAP to internal/:** +- `soap/` → `internal/soap/` +- Updated imports in: + - `device.go` + - `media.go` + - `ptz.go` + - `imaging.go` + - `server/soap/handler.go` + +**Reason:** +- SOAP client is an implementation detail +- Users should interact through high-level API +- Prevents tight coupling to SOAP specifics +- Allows future protocol changes + +### Import Updates + +**Old:** +```go +import "github.com/0x524A/onvif-go/soap" +``` + +**New:** +```go +import "github.com/0x524A/onvif-go/internal/soap" +``` + +**External users:** No changes needed (they never imported soap directly) + +## Benefits of This Structure + +### For Library Users + +1. **Simple imports**: `import "github.com/0x524A/onvif-go"` +2. **Clear API**: Public vs private clearly separated +3. **Stable interface**: Internal changes don't affect users +4. **Good documentation**: Examples and docs organized + +### For Contributors + +1. **Clear organization**: Each file has single responsibility +2. **Easy navigation**: Logical directory structure +3. **Safe refactoring**: Internal package allows changes +4. **Standard layout**: Follows Go conventions + +### For Maintenance + +1. **Backward compatibility**: Internal changes don't break users +2. **Scalability**: Structure supports growth +3. **Testing**: Co-located tests, separate test utilities +4. **Documentation**: Organized in docs/ + +## Future Considerations + +As the project grows: + +1. **More subpackages**: Analytics, events, recording services +2. **Additional internal packages**: Caching, connection pooling +3. **Tool improvements**: Enhanced cmd/ utilities +4. **Documentation growth**: More guides in docs/ + +The current structure supports these additions naturally. + +## References + +- [Standard Go Project Layout](https://github.com/golang-standards/project-layout) +- [Go Blog: Package names](https://go.dev/blog/package-names) +- [Effective Go](https://go.dev/doc/effective_go) +- [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) + +## Summary + +The onvif-go project structure: +- ✅ Follows Go conventions for libraries +- ✅ Public API at root level +- ✅ Internal package for private code +- ✅ Subpackages for additional features +- ✅ Clear separation of concerns +- ✅ Scalable and maintainable +- ✅ User-friendly imports diff --git a/imaging.go b/imaging.go index a8777b3..0c1cd3a 100644 --- a/imaging.go +++ b/imaging.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "fmt" - "github.com/0x524A/onvif-go/soap" + "github.com/0x524A/onvif-go/internal/soap" ) // Imaging service namespace diff --git a/soap/soap.go b/internal/soap/soap.go similarity index 100% rename from soap/soap.go rename to internal/soap/soap.go diff --git a/soap/soap_test.go b/internal/soap/soap_test.go similarity index 100% rename from soap/soap_test.go rename to internal/soap/soap_test.go diff --git a/media.go b/media.go index a62f266..0a5d878 100644 --- a/media.go +++ b/media.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "fmt" - "github.com/0x524A/onvif-go/soap" + "github.com/0x524A/onvif-go/internal/soap" ) // Media service namespace diff --git a/ptz.go b/ptz.go index 48db29e..1c1be89 100644 --- a/ptz.go +++ b/ptz.go @@ -5,7 +5,7 @@ import ( "encoding/xml" "fmt" - "github.com/0x524A/onvif-go/soap" + "github.com/0x524A/onvif-go/internal/soap" ) // PTZ service namespace diff --git a/server/soap/handler.go b/server/soap/handler.go index 404cbb1..6dd6659 100644 --- a/server/soap/handler.go +++ b/server/soap/handler.go @@ -11,7 +11,7 @@ import ( "strings" "time" - originsoap "github.com/0x524A/onvif-go/soap" + originsoap "github.com/0x524A/onvif-go/internal/soap" ) // Handler handles incoming SOAP requests