feat: restructure project layout and move SOAP implementation to internal package
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/0x524A/onvif-go/soap"
|
||||
"github.com/0x524A/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// Device service namespace
|
||||
|
||||
+26
-1
@@ -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 │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
@@ -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
|
||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/0x524A/onvif-go/soap"
|
||||
"github.com/0x524A/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// Imaging service namespace
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/0x524A/onvif-go/soap"
|
||||
"github.com/0x524A/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// Media service namespace
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/0x524A/onvif-go/soap"
|
||||
"github.com/0x524A/onvif-go/internal/soap"
|
||||
)
|
||||
|
||||
// PTZ service namespace
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user