perf_opt.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. package nginx
  2. import (
  3. "fmt"
  4. "os"
  5. "sort"
  6. "time"
  7. "github.com/pkg/errors"
  8. "github.com/tufanbarisyildirim/gonginx/config"
  9. "github.com/tufanbarisyildirim/gonginx/dumper"
  10. "github.com/tufanbarisyildirim/gonginx/parser"
  11. )
  12. // PerfOpt represents Nginx performance optimization settings
  13. type PerfOpt struct {
  14. WorkerProcesses string `json:"worker_processes"` // auto or number
  15. WorkerConnections string `json:"worker_connections"` // max connections
  16. KeepaliveTimeout string `json:"keepalive_timeout"` // timeout in seconds
  17. Gzip string `json:"gzip"` // on or off
  18. GzipMinLength string `json:"gzip_min_length"` // min length to compress
  19. GzipCompLevel string `json:"gzip_comp_level"` // compression level
  20. ClientMaxBodySize string `json:"client_max_body_size"` // max body size (with unit: k, m, g)
  21. ServerNamesHashBucketSize string `json:"server_names_hash_bucket_size"` // hash bucket size
  22. ClientHeaderBufferSize string `json:"client_header_buffer_size"` // header buffer size (with unit: k, m, g)
  23. ClientBodyBufferSize string `json:"client_body_buffer_size"` // body buffer size (with unit: k, m, g)
  24. }
  25. // UpdatePerfOpt updates the Nginx performance optimization settings
  26. func UpdatePerfOpt(opt *PerfOpt) error {
  27. confPath := GetConfPath("nginx.conf")
  28. if confPath == "" {
  29. return errors.New("failed to get nginx.conf path")
  30. }
  31. // Read the current configuration
  32. content, err := os.ReadFile(confPath)
  33. if err != nil {
  34. return errors.Wrap(err, "failed to read nginx.conf")
  35. }
  36. // Create a backup file
  37. backupPath := fmt.Sprintf("%s.backup.%d", confPath, time.Now().Unix())
  38. err = os.WriteFile(backupPath, content, 0644)
  39. if err != nil {
  40. return errors.Wrap(err, "failed to create backup file")
  41. }
  42. // Parse the configuration
  43. p := parser.NewStringParser(string(content), parser.WithSkipValidDirectivesErr())
  44. conf, err := p.Parse()
  45. if err != nil {
  46. return errors.Wrap(err, "failed to parse nginx.conf")
  47. }
  48. // Process the configuration and update performance settings
  49. updateNginxConfig(conf.Block, opt)
  50. // Dump the updated configuration
  51. updatedConf := dumper.DumpBlock(conf.Block, dumper.IndentedStyle)
  52. // Write the updated configuration
  53. err = os.WriteFile(confPath, []byte(updatedConf), 0644)
  54. if err != nil {
  55. return errors.Wrap(err, "failed to write updated nginx.conf")
  56. }
  57. return nil
  58. }
  59. // updateNginxConfig updates the performance settings in the Nginx configuration
  60. func updateNginxConfig(block config.IBlock, opt *PerfOpt) {
  61. if block == nil {
  62. return
  63. }
  64. directives := block.GetDirectives()
  65. // Update main context directives
  66. updateOrAddDirective(block, directives, "worker_processes", opt.WorkerProcesses)
  67. // Look for events, http, and other blocks
  68. for _, directive := range directives {
  69. if directive.GetName() == "events" && directive.GetBlock() != nil {
  70. // Update events block directives
  71. eventsBlock := directive.GetBlock()
  72. eventsDirectives := eventsBlock.GetDirectives()
  73. updateOrAddDirective(eventsBlock, eventsDirectives, "worker_connections", opt.WorkerConnections)
  74. } else if directive.GetName() == "http" && directive.GetBlock() != nil {
  75. // Update http block directives
  76. httpBlock := directive.GetBlock()
  77. httpDirectives := httpBlock.GetDirectives()
  78. updateOrAddDirective(httpBlock, httpDirectives, "keepalive_timeout", opt.KeepaliveTimeout)
  79. updateOrAddDirective(httpBlock, httpDirectives, "gzip", opt.Gzip)
  80. updateOrAddDirective(httpBlock, httpDirectives, "gzip_min_length", opt.GzipMinLength)
  81. updateOrAddDirective(httpBlock, httpDirectives, "gzip_comp_level", opt.GzipCompLevel)
  82. updateOrAddDirective(httpBlock, httpDirectives, "client_max_body_size", opt.ClientMaxBodySize)
  83. updateOrAddDirective(httpBlock, httpDirectives, "server_names_hash_bucket_size", opt.ServerNamesHashBucketSize)
  84. updateOrAddDirective(httpBlock, httpDirectives, "client_header_buffer_size", opt.ClientHeaderBufferSize)
  85. updateOrAddDirective(httpBlock, httpDirectives, "client_body_buffer_size", opt.ClientBodyBufferSize)
  86. }
  87. }
  88. }
  89. // updateOrAddDirective updates a directive if it exists, or adds it to the block if it doesn't
  90. func updateOrAddDirective(block config.IBlock, directives []config.IDirective, name string, value string) {
  91. if value == "" {
  92. return
  93. }
  94. // Search for existing directive
  95. for _, directive := range directives {
  96. if directive.GetName() == name {
  97. // Update existing directive
  98. if len(directive.GetParameters()) > 0 {
  99. directive.GetParameters()[0].Value = value
  100. }
  101. return
  102. }
  103. }
  104. // If we get here, we need to add a new directive
  105. // Create a new directive and add it to the block
  106. // This requires knowledge of the underlying implementation
  107. // For now, we'll use the Directive type from gonginx/config
  108. newDirective := &config.Directive{
  109. Name: name,
  110. Parameters: []config.Parameter{{Value: value}},
  111. }
  112. // Add the new directive to the block
  113. // This is specific to the gonginx library implementation
  114. switch block := block.(type) {
  115. case *config.Config:
  116. block.Block.Directives = append(block.Block.Directives, newDirective)
  117. case *config.Block:
  118. block.Directives = append(block.Directives, newDirective)
  119. case *config.HTTP:
  120. block.Directives = append(block.Directives, newDirective)
  121. }
  122. }
  123. // sortDirectives sorts directives alphabetically by name
  124. func sortDirectives(directives []config.IDirective) {
  125. sort.SliceStable(directives, func(i, j int) bool {
  126. // Ensure both i and j can return valid names
  127. return directives[i].GetName() < directives[j].GetName()
  128. })
  129. }