Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
227
native/desktop/maplefile/internal/app/wire.go
Normal file
227
native/desktop/maplefile/internal/app/wire.go
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
//go:build wireinject
|
||||
// +build wireinject
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/wire"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/maplefile/client"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/config"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage/leveldb"
|
||||
|
||||
// Domain imports
|
||||
sessionDomain "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/session"
|
||||
|
||||
// Repository imports
|
||||
sessionRepo "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/repo/session"
|
||||
|
||||
// Service imports
|
||||
authService "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/auth"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/httpclient"
|
||||
keyCache "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/keycache"
|
||||
passwordStore "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/passwordstore"
|
||||
rateLimiter "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/ratelimiter"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/search"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/securitylog"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/storagemanager"
|
||||
syncService "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/sync"
|
||||
tokenManager "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/service/tokenmanager"
|
||||
|
||||
// Use case imports
|
||||
sessionUC "codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/usecase/session"
|
||||
)
|
||||
|
||||
// InitializeApplication creates a fully configured Application using Wire DI
|
||||
func InitializeApplication() (*Application, error) {
|
||||
wire.Build(
|
||||
// Infrastructure
|
||||
ProvideLogger,
|
||||
config.New,
|
||||
ProvideMapleFileClient,
|
||||
|
||||
// Session Repository (global - not user-specific)
|
||||
ProvideSessionRepository,
|
||||
|
||||
// Storage Manager (handles user-specific storage lifecycle)
|
||||
storagemanager.ProvideManager,
|
||||
// Bind *storagemanager.Manager to sync.RepositoryProvider interface
|
||||
wire.Bind(new(syncService.RepositoryProvider), new(*storagemanager.Manager)),
|
||||
|
||||
// Use Case Layer
|
||||
sessionUC.ProvideCreateUseCase,
|
||||
sessionUC.ProvideGetByIdUseCase,
|
||||
sessionUC.ProvideDeleteUseCase,
|
||||
sessionUC.ProvideSaveUseCase,
|
||||
|
||||
// Service Layer
|
||||
authService.ProvideService,
|
||||
tokenManager.ProvideManager,
|
||||
passwordStore.ProvideService,
|
||||
keyCache.ProvideService,
|
||||
rateLimiter.ProvideService,
|
||||
httpclient.ProvideService,
|
||||
securitylog.ProvideService,
|
||||
search.New,
|
||||
|
||||
// Sync Services
|
||||
syncService.ProvideCollectionSyncService,
|
||||
syncService.ProvideFileSyncService,
|
||||
syncService.ProvideService,
|
||||
|
||||
// Application
|
||||
ProvideApplication,
|
||||
)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ProvideLogger creates the application logger with environment-aware configuration.
|
||||
// Defaults to production mode for security. Development mode must be explicitly enabled.
|
||||
func ProvideLogger() (*zap.Logger, error) {
|
||||
mode := os.Getenv("MAPLEFILE_MODE")
|
||||
|
||||
// Only use development logger if explicitly set to "dev" or "development"
|
||||
if mode == "dev" || mode == "development" {
|
||||
// Development: console format, debug level, with caller and stacktrace
|
||||
return zap.NewDevelopment()
|
||||
}
|
||||
|
||||
// Default to production: JSON format, info level, no caller info, no stacktrace
|
||||
// This is the secure default - production mode unless explicitly in dev
|
||||
cfg := zap.NewProductionConfig()
|
||||
cfg.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
|
||||
cfg.DisableCaller = true
|
||||
cfg.DisableStacktrace = true
|
||||
return cfg.Build()
|
||||
}
|
||||
|
||||
// ProvideSessionRepository creates the session repository with its storage.
|
||||
// Session storage is GLOBAL (not user-specific) because it stores the current login session.
|
||||
func ProvideSessionRepository(logger *zap.Logger) (sessionDomain.Repository, error) {
|
||||
provider, err := config.NewLevelDBConfigurationProviderForSession()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionStorage := leveldb.NewDiskStorage(provider, logger.Named("session-storage"))
|
||||
return sessionRepo.ProvideRepository(sessionStorage), nil
|
||||
}
|
||||
|
||||
// zapLoggerAdapter adapts *zap.Logger to client.Logger interface
|
||||
type zapLoggerAdapter struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
func (a *zapLoggerAdapter) Debug(msg string, keysAndValues ...interface{}) {
|
||||
fields := keysAndValuesToZapFields(keysAndValues...)
|
||||
a.logger.Debug(msg, fields...)
|
||||
}
|
||||
|
||||
func (a *zapLoggerAdapter) Info(msg string, keysAndValues ...interface{}) {
|
||||
fields := keysAndValuesToZapFields(keysAndValues...)
|
||||
a.logger.Info(msg, fields...)
|
||||
}
|
||||
|
||||
func (a *zapLoggerAdapter) Warn(msg string, keysAndValues ...interface{}) {
|
||||
fields := keysAndValuesToZapFields(keysAndValues...)
|
||||
a.logger.Warn(msg, fields...)
|
||||
}
|
||||
|
||||
func (a *zapLoggerAdapter) Error(msg string, keysAndValues ...interface{}) {
|
||||
fields := keysAndValuesToZapFields(keysAndValues...)
|
||||
a.logger.Error(msg, fields...)
|
||||
}
|
||||
|
||||
// keysAndValuesToZapFields converts key-value pairs to zap fields
|
||||
func keysAndValuesToZapFields(keysAndValues ...interface{}) []zap.Field {
|
||||
fields := make([]zap.Field, 0, len(keysAndValues)/2)
|
||||
for i := 0; i+1 < len(keysAndValues); i += 2 {
|
||||
key, ok := keysAndValues[i].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
fields = append(fields, zap.Any(key, keysAndValues[i+1]))
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// BuildMode is set at compile time via -ldflags
|
||||
// Example: go build -ldflags "-X codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/app.BuildMode=dev"
|
||||
var BuildMode string
|
||||
|
||||
// ProvideMapleFileClient creates the backend API client
|
||||
func ProvideMapleFileClient(configService config.ConfigService, logger *zap.Logger) (*client.Client, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Determine the API URL based on the mode
|
||||
// Priority: 1) Environment variable, 2) Build-time variable, 3) Default to production
|
||||
mode := os.Getenv("MAPLEFILE_MODE")
|
||||
|
||||
// Log the detected mode
|
||||
logger.Info("Startup: checking mode configuration",
|
||||
zap.String("MAPLEFILE_MODE_env", mode),
|
||||
zap.String("BuildMode_compile_time", BuildMode),
|
||||
)
|
||||
|
||||
if mode == "" {
|
||||
if BuildMode != "" {
|
||||
mode = BuildMode
|
||||
logger.Info("Startup: using compile-time BuildMode", zap.String("mode", mode))
|
||||
} else {
|
||||
mode = "production" // Default to production (secure default)
|
||||
logger.Info("Startup: no mode set, defaulting to production", zap.String("mode", mode))
|
||||
}
|
||||
}
|
||||
|
||||
var baseURL string
|
||||
switch mode {
|
||||
case "production":
|
||||
baseURL = client.ProductionURL // https://maplefile.ca
|
||||
case "dev", "development":
|
||||
baseURL = client.LocalURL // http://localhost:8000
|
||||
default:
|
||||
// Fallback: check config file for custom URL
|
||||
cfg, err := configService.GetConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
baseURL = cfg.CloudProviderAddress
|
||||
}
|
||||
|
||||
// Create logger adapter for the API client
|
||||
clientLogger := &zapLoggerAdapter{logger: logger.Named("api-client")}
|
||||
|
||||
// Create client with the determined URL and logger
|
||||
apiClient := client.New(client.Config{
|
||||
BaseURL: baseURL,
|
||||
Logger: clientLogger,
|
||||
})
|
||||
|
||||
logger.Info("MapleFile API client initialized",
|
||||
zap.String("mode", mode),
|
||||
zap.String("base_url", baseURL),
|
||||
)
|
||||
|
||||
// Security: Warn if using unencrypted HTTP (should only happen in dev mode)
|
||||
if strings.HasPrefix(baseURL, "http://") {
|
||||
logger.Warn("SECURITY WARNING: Using unencrypted HTTP connection",
|
||||
zap.String("mode", mode),
|
||||
zap.String("base_url", baseURL),
|
||||
zap.String("recommendation", "This should only be used for local development"),
|
||||
)
|
||||
}
|
||||
|
||||
// Update the config to reflect the current backend URL (skip in production as it's immutable)
|
||||
if mode != "production" {
|
||||
if err := configService.SetCloudProviderAddress(ctx, baseURL); err != nil {
|
||||
logger.Warn("Failed to update cloud provider address in config", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
return apiClient, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue