config.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // pkg/config/config.go
  2. package config
  3. import (
  4. "fmt"
  5. "os"
  6. "git.linuxforward.com/byom/byom-golang-lib/pkg/auth"
  7. "git.linuxforward.com/byom/byom-golang-lib/pkg/database"
  8. "git.linuxforward.com/byom/byom-golang-lib/pkg/logger"
  9. "git.linuxforward.com/byom/byom-golang-lib/pkg/server"
  10. "git.linuxforward.com/byom/byom-golang-lib/pkg/smtp"
  11. "git.linuxforward.com/byom/byom-golang-lib/pkg/storage"
  12. "git.linuxforward.com/byom/byom-golang-lib/pkg/webhook"
  13. "gopkg.in/yaml.v3"
  14. )
  15. type Config struct {
  16. App *App `yaml:"app"`
  17. Auth *auth.Config `yaml:"auth"`
  18. Server *server.Config `yaml:"server"`
  19. Database *database.Config `yaml:"database"`
  20. Log *logger.Config `yaml:"log"`
  21. Storage *storage.Config `yaml:"storage"`
  22. Smtp *smtp.Config `yaml:"smtp,omitempty"`
  23. Webhook *webhook.Config `yaml:"webhook,omitempty"`
  24. CloudComputing *CloudComputing `yaml:"cloud_computing,omitempty"`
  25. SocialNetworks *SocialNetworks `yaml:"social_networks,omitempty"`
  26. }
  27. func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
  28. type plain Config
  29. err := unmarshal((*plain)(c))
  30. if err != nil {
  31. return err
  32. }
  33. if c.App == nil {
  34. return NewFieldError("validate", "root", "app", "", ErrMissingRequired, "app section is required")
  35. }
  36. // Conditional validation based on app name
  37. switch c.App.Name {
  38. case "design":
  39. if c.CloudComputing == nil {
  40. return NewFieldError("validate", "root", "cloud_computing", "", ErrMissingRequired, "cloud_computing section is required for design app")
  41. }
  42. case "trends":
  43. if c.SocialNetworks == nil {
  44. return NewFieldError("validate", "root", "social_networks", "", ErrMissingRequired, "social_networks section is required for trends app")
  45. }
  46. }
  47. return nil
  48. }
  49. type App struct {
  50. Name string `yaml:"name"`
  51. Environment string `yaml:"environment"`
  52. }
  53. func (c *App) UnmarshalYAML(unmarshal func(interface{}) error) error {
  54. type plain App
  55. err := unmarshal((*plain)(c))
  56. if err != nil {
  57. return err
  58. }
  59. if c.Name == "" {
  60. return NewFieldError("validate", "app", "name", "", ErrMissingRequired, "app name is required")
  61. }
  62. if c.Environment == "" {
  63. c.Environment = "development"
  64. }
  65. // Validate app name
  66. validNames := map[string]bool{"core": true, "design": true, "trends": true}
  67. if !validNames[c.Name] {
  68. return NewFieldError("validate", "app", "name", c.Name, ErrInvalidAppName, "app name must be one of: core, design, trends")
  69. }
  70. return nil
  71. }
  72. type CloudComputing struct {
  73. Provider string `yaml:"provider"`
  74. Region string `yaml:"region"`
  75. MaxCapacity int `yaml:"max_capacity"`
  76. }
  77. func (c *CloudComputing) UnmarshalYAML(unmarshal func(interface{}) error) error {
  78. type plain CloudComputing
  79. err := unmarshal((*plain)(c))
  80. if err != nil {
  81. return err
  82. }
  83. if c.Provider == "" {
  84. return NewFieldError("validate", "cloud_computing", "provider", "", ErrMissingRequired, "provider is required")
  85. }
  86. if c.Region == "" {
  87. return NewFieldError("validate", "cloud_computing", "region", "", ErrMissingRequired, "region is required")
  88. }
  89. if c.MaxCapacity <= 0 {
  90. return NewFieldError("validate", "cloud_computing", "max_capacity", fmt.Sprintf("%d", c.MaxCapacity), ErrInvalidValue, "max_capacity must be greater than 0")
  91. }
  92. return nil
  93. }
  94. type SocialNetworks struct {
  95. Networks []SocialNetwork `yaml:"networks"`
  96. }
  97. type SocialNetwork struct {
  98. Name string `yaml:"name"`
  99. APIKey string `yaml:"api_key"`
  100. APIToken string `yaml:"api_token"`
  101. }
  102. func (c *SocialNetworks) UnmarshalYAML(unmarshal func(interface{}) error) error {
  103. type plain SocialNetworks
  104. err := unmarshal((*plain)(c))
  105. if err != nil {
  106. return err
  107. }
  108. if len(c.Networks) == 0 {
  109. return NewFieldError("validate", "social_networks", "networks", "", ErrMissingRequired, "at least one social network is required")
  110. }
  111. for i, network := range c.Networks {
  112. section := fmt.Sprintf("social_networks.networks[%d]", i)
  113. if network.Name == "" {
  114. return NewFieldError("validate", section, "name", "", ErrMissingRequired, "network name is required")
  115. }
  116. if network.APIKey == "" {
  117. return NewFieldError("validate", section, "api_key", "", ErrMissingRequired, "API key is required")
  118. }
  119. if network.APIToken == "" {
  120. return NewFieldError("validate", section, "api_token", "", ErrMissingRequired, "API token is required")
  121. }
  122. }
  123. return nil
  124. }
  125. func ReadConfig(configPath string) (*Config, error) {
  126. data, err := os.ReadFile(configPath)
  127. if err != nil {
  128. if os.IsNotExist(err) {
  129. return nil, NewError("read", ErrFileNotFound, configPath)
  130. }
  131. if os.IsPermission(err) {
  132. return nil, NewError("read", ErrFilePermission, configPath)
  133. }
  134. return nil, NewError("read", err, "failed to read config file")
  135. }
  136. config := &Config{}
  137. err = yaml.Unmarshal(data, config)
  138. if err != nil {
  139. return nil, NewError("parse", ErrInvalidYAML, err.Error())
  140. }
  141. // Validate all config sections that implement Validator interface
  142. validators := []Validator{}
  143. if config.Storage != nil {
  144. validators = append(validators, config.Storage)
  145. }
  146. if config.Database != nil {
  147. validators = append(validators, config.Database)
  148. }
  149. if config.Log != nil {
  150. validators = append(validators, config.Log)
  151. }
  152. if config.Server != nil {
  153. validators = append(validators, config.Server)
  154. }
  155. if config.Auth != nil {
  156. validators = append(validators, config.Auth)
  157. }
  158. if config.Webhook != nil {
  159. validators = append(validators, config.Webhook)
  160. }
  161. if err := ValidateAll(validators...); err != nil {
  162. return nil, err
  163. }
  164. return config, nil
  165. }