Understanding the Connection Management Service Architecture in CasaOS
CasaOS implements a dedicated service-layer architecture for managing SMB connections, encapsulating database persistence, system-level mounting, and HTTP API concerns behind a clean ConnectionsService interface.
The connection management service architecture in CasaOS provides a robust, testable foundation for handling Samba shares. By isolating SMB operations into a distinct service layer, the codebase maintains separation between HTTP handlers, data persistence, and low-level filesystem mounts. This design leverages GORM for database operations and direct system calls for kernel-level SMB mounting.
Core Components of the Connection Management Service
The architecture consists of three primary components that work together to provide a complete SMB connection lifecycle management solution.
The ConnectionsService Interface
At the heart of the system lies the ConnectionsService interface defined in service/connections.go. This contract establishes the public API for all connection-related operations, ensuring that HTTP handlers remain decoupled from implementation details.
type ConnectionsService interface {
GetConnectionsList() []model2.ConnectionsDBModel
GetConnectionByHost(host string) []model2.ConnectionsDBModel
GetConnectionByID(id string) model2.ConnectionsDBModel
CreateConnection(*model2.ConnectionsDBModel)
DeleteConnection(id string)
UpdateConnection(*model2.ConnectionsDBModel)
MountSmaba(username, host, directory, port, mountPoint, password string) error
UnmountSmaba(mountPoint string) error
}
The interface exposes standard CRUD operations for connection metadata alongside specialized mount/unmount methods that handle kernel-level SMB filesystem operations.
The connectionsStruct Implementation
The concrete implementation, connectionsStruct, resides in the same file (service/connections.go) and holds a *gorm.DB reference for database operations. This struct implements all interface methods, bridging the gap between high-level service calls and low-level system execution.
For persistence operations, the implementation uses standard GORM patterns. For filesystem operations, it executes system calls using unix.Mount and mount.Unmount to expose remote SMB shares under /mnt/<host>/ directories. This encapsulation ensures that HTTP handlers never directly interact with the kernel or database driver.
The ConnectionsDBModel Persistence Layer
Connection metadata persists through the ConnectionsDBModel defined in service/model/o_connections.go. This GORM-mapped struct represents the database schema for the o_connections table:
type ConnectionsDBModel struct {
ID uint `gorm:"column:id;primary_key"`
Updated int64 `gorm:"autoUpdateTime"`
Created int64 `gorm:"autoCreateTime"`
Username string
Password string
Host string
Port string
Status string
Directories string // comma-separated list
MountPoint string // e.g. "/mnt/<host>"
}
The model serves as the single source of truth for connection configuration, storing credentials, host information, and mount point locations required for SMB operations.
Service Container Integration
The connection service wires into CasaOS's dependency injection container through service/service.go. The NewService function constructs a store struct that aggregates all sub-services, including the connection service instantiated via NewConnectionsService(db).
The container exposes the service through MyService.Connections(), making it available to any caller without requiring direct instantiation. This pattern follows the service-repository architecture, allowing HTTP handlers to access connection management through a standardized facade:
// Access pattern used throughout the application
service.MyService.Connections().GetConnectionsList()
HTTP Handler Integration and Workflow
The route/v1/samba.go file demonstrates how HTTP handlers leverage the connection management service architecture to orchestrate complex SMB workflows while maintaining clean separation of concerns.
Listing Connections
The handler retrieves all configured connections through the service interface, converting database models to API responses:
func GetSambaConnectionsList(ctx echo.Context) error {
connections := service.MyService.Connections().GetConnectionsList()
// ...convert to API model and return...
}
This approach keeps the HTTP layer agnostic to database query implementation details.
Creating SMB Connections
Creating a connection involves multiple coordinated steps through the service layer:
func PostSambaConnectionsCreate(ctx echo.Context) error {
// Parse request → model.Connections
dirs, err := samba.GetSambaSharesList(host, port, user, pass)
// Build DB model
conn := model2.ConnectionsDBModel{
Username: user,
Password: pass,
Host: host,
Port: port,
Directories: strings.Join(dirs, ","),
MountPoint: "/mnt/" + host,
}
// Ensure mount root exists
file.IsNotExistMkDir(conn.MountPoint)
// Mount each discovered share
for _, d := range dirs {
mp := conn.MountPoint + "/" + d
file.IsNotExistMkDir(mp)
service.MyService.Connections().
MountSmaba(user, host, d, port, mp, pass)
}
// Persist the connection record
service.MyService.Connections().CreateConnection(&conn)
}
The handler orchestrates validation, share discovery, filesystem mounting, and persistence without directly managing database connections or kernel calls.
Deleting Connections
Deletion reverses the creation process by unmounting shares before removing database records:
func DeleteSambaConnections(ctx echo.Context) error {
id := ctx.Param("id")
conn := service.MyService.Connections().GetConnectionByID(id)
shares, _ := samba.GetSambaSharesList(conn.Host, conn.Port,
conn.Username, conn.Password)
for _, s := range shares {
mountPath := "/mnt/" + conn.Host + "/" + s
if service.IsMounted(mountPath) {
service.MyService.Connections().UnmountSmaba(mountPath)
}
}
// Clean up empty mount root
if empty, _ := ioutil.ReadDir(conn.MountPoint); len(empty) == 0 {
os.RemoveAll(conn.MountPoint)
}
service.MyService.Connections().DeleteConnection(id)
}
Dependency Flow and Architecture Pattern
The connection management service architecture in CasaOS follows a clear dependency hierarchy:
HTTP Handler (route/v1/samba.go)
↓
MyService.Connections() ←─── NewService (store) ──── DB (gorm)
↓
connectionsStruct methods (CRUD + mount/unmount)
↓
GORM → SQLite/PostgreSQL (persisted connections)
unix/mount → kernel (SMB mounts)
This design implements the service-repository pattern, where HTTP handlers communicate through high-level service interfaces, the service manages repository access via GORM, and system-level actions remain encapsulated within the implementation. The architecture ensures that changes to database schema, ORM configuration, or mount implementation strategies do not cascade into HTTP handler code.
Summary
- Interface-driven design: The
ConnectionsServiceinterface inservice/connections.godecouples HTTP handlers from implementation details, enabling testable, maintainable code. - Three-layer architecture: The system separates concerns into interface definition (
ConnectionsService), concrete implementation (connectionsStruct), and persistence model (ConnectionsDBModel). - Service container pattern:
NewServiceinservice/service.gowires the connection service into a central repository accessible viaMyService.Connections(). - System call encapsulation: Mount operations use
unix.Mountandmount.Unmountinternally while exposing simple method signatures to callers. - Complete lifecycle management: The architecture handles connection creation, persistence, mounting, unmounting, and deletion through a cohesive API.
Frequently Asked Questions
How does CasaOS persist SMB connection credentials?
CasaOS stores SMB connection credentials in a database table mapped to the ConnectionsDBModel struct in service/model/o_connections.go. The GORM ORM manages this persistence layer, storing username, password, host, port, and mount point information in the o_connections table. The connectionsStruct implementation in service/connections.go handles all database interactions through this model.
What happens when a user creates a new SMB connection in CasaOS?
When creating a connection, the system first validates the request and probes the remote host using samba.GetSambaSharesList to discover available shares. It then creates a ConnectionsDBModel record, establishes the mount point directory under /mnt/<host>/, iterates over discovered shares, and calls MountSmaba for each share via the connection service. Finally, it persists the configuration to the database using CreateConnection.
Why does CasaOS use a service interface for connection management?
The interface-based design allows CasaOS to separate HTTP route handlers from database and filesystem implementation details. This approach enables unit testing through mock implementations, supports future changes to the persistence layer or mount mechanisms without affecting API endpoints, and follows Go best practices for dependency injection. The ConnectionsService interface in service/connections.go defines this contract explicitly.
Where does CasaOS mount SMB shares on the filesystem?
According to the source code in service/connections.go and route/v1/samba.go, CasaOS mounts SMB shares under /mnt/<host>/ directories, where <host> represents the target server hostname. Individual shares mount as subdirectories within this path (e.g., /mnt/servername/sharename). The MountPoint field in ConnectionsDBModel tracks these locations for subsequent unmounting and cleanup operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →