options.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package option
  2. import (
  3. "bytes"
  4. "context"
  5. E "github.com/sagernet/sing/common/exceptions"
  6. F "github.com/sagernet/sing/common/format"
  7. "github.com/sagernet/sing/common/json"
  8. )
  9. type _Options struct {
  10. RawMessage json.RawMessage `json:"-"`
  11. Schema string `json:"$schema,omitempty"`
  12. Log *LogOptions `json:"log,omitempty"`
  13. DNS *DNSOptions `json:"dns,omitempty"`
  14. NTP *NTPOptions `json:"ntp,omitempty"`
  15. Certificate *CertificateOptions `json:"certificate,omitempty"`
  16. CertificateProviders []CertificateProvider `json:"certificate_providers,omitempty"`
  17. HTTPClients []HTTPClient `json:"http_clients,omitempty"`
  18. Endpoints []Endpoint `json:"endpoints,omitempty"`
  19. Inbounds []Inbound `json:"inbounds,omitempty"`
  20. Outbounds []Outbound `json:"outbounds,omitempty"`
  21. Route *RouteOptions `json:"route,omitempty"`
  22. Services []Service `json:"services,omitempty"`
  23. Experimental *ExperimentalOptions `json:"experimental,omitempty"`
  24. }
  25. type Options _Options
  26. func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  27. decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
  28. decoder.DisallowUnknownFields()
  29. err := decoder.Decode((*_Options)(o))
  30. if err != nil {
  31. return err
  32. }
  33. o.RawMessage = content
  34. return checkOptions(o)
  35. }
  36. type LogOptions struct {
  37. Disabled bool `json:"disabled,omitempty"`
  38. Level string `json:"level,omitempty"`
  39. Output string `json:"output,omitempty"`
  40. Timestamp bool `json:"timestamp,omitempty"`
  41. DisableColor bool `json:"-"`
  42. }
  43. type StubOptions struct{}
  44. func checkOptions(options *Options) error {
  45. err := checkInbounds(options.Inbounds)
  46. if err != nil {
  47. return err
  48. }
  49. err = checkOutbounds(options.Outbounds, options.Endpoints)
  50. if err != nil {
  51. return err
  52. }
  53. err = checkCertificateProviders(options.CertificateProviders)
  54. if err != nil {
  55. return err
  56. }
  57. err = checkHTTPClients(options.HTTPClients)
  58. if err != nil {
  59. return err
  60. }
  61. return nil
  62. }
  63. func checkCertificateProviders(providers []CertificateProvider) error {
  64. seen := make(map[string]bool)
  65. for i, provider := range providers {
  66. tag := provider.Tag
  67. if tag == "" {
  68. tag = F.ToString(i)
  69. }
  70. if seen[tag] {
  71. return E.New("duplicate certificate provider tag: ", tag)
  72. }
  73. seen[tag] = true
  74. }
  75. return nil
  76. }
  77. func checkHTTPClients(clients []HTTPClient) error {
  78. seen := make(map[string]bool)
  79. for _, client := range clients {
  80. if client.Tag == "" {
  81. return E.New("missing http client tag")
  82. }
  83. if seen[client.Tag] {
  84. return E.New("duplicate http client tag: ", client.Tag)
  85. }
  86. seen[client.Tag] = true
  87. }
  88. return nil
  89. }
  90. func checkInbounds(inbounds []Inbound) error {
  91. seen := make(map[string]bool)
  92. for i, inbound := range inbounds {
  93. tag := inbound.Tag
  94. if tag == "" {
  95. tag = F.ToString(i)
  96. }
  97. if seen[tag] {
  98. return E.New("duplicate inbound tag: ", tag)
  99. }
  100. seen[tag] = true
  101. }
  102. return nil
  103. }
  104. func checkOutbounds(outbounds []Outbound, endpoints []Endpoint) error {
  105. seen := make(map[string]bool)
  106. for i, outbound := range outbounds {
  107. tag := outbound.Tag
  108. if tag == "" {
  109. tag = F.ToString(i)
  110. }
  111. if seen[tag] {
  112. return E.New("duplicate outbound/endpoint tag: ", tag)
  113. }
  114. seen[tag] = true
  115. }
  116. for i, endpoint := range endpoints {
  117. tag := endpoint.Tag
  118. if tag == "" {
  119. tag = F.ToString(i)
  120. }
  121. if seen[tag] {
  122. return E.New("duplicate outbound/endpoint tag: ", tag)
  123. }
  124. seen[tag] = true
  125. }
  126. return nil
  127. }