options.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. Endpoints []Endpoint `json:"endpoints,omitempty"`
  17. Inbounds []Inbound `json:"inbounds,omitempty"`
  18. Outbounds []Outbound `json:"outbounds,omitempty"`
  19. Route *RouteOptions `json:"route,omitempty"`
  20. Services []Service `json:"services,omitempty"`
  21. Experimental *ExperimentalOptions `json:"experimental,omitempty"`
  22. }
  23. type Options _Options
  24. func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  25. decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
  26. decoder.DisallowUnknownFields()
  27. err := decoder.Decode((*_Options)(o))
  28. if err != nil {
  29. return err
  30. }
  31. o.RawMessage = content
  32. return checkOptions(o)
  33. }
  34. type LogOptions struct {
  35. Disabled bool `json:"disabled,omitempty"`
  36. Level string `json:"level,omitempty"`
  37. Output string `json:"output,omitempty"`
  38. Timestamp bool `json:"timestamp,omitempty"`
  39. DisableColor bool `json:"-"`
  40. }
  41. type StubOptions struct{}
  42. func checkOptions(options *Options) error {
  43. err := checkInbounds(options.Inbounds)
  44. if err != nil {
  45. return err
  46. }
  47. err = checkOutbounds(options.Outbounds, options.Endpoints)
  48. if err != nil {
  49. return err
  50. }
  51. return nil
  52. }
  53. func checkInbounds(inbounds []Inbound) error {
  54. seen := make(map[string]bool)
  55. for i, inbound := range inbounds {
  56. tag := inbound.Tag
  57. if tag == "" {
  58. tag = F.ToString(i)
  59. }
  60. if seen[tag] {
  61. return E.New("duplicate inbound tag: ", tag)
  62. }
  63. seen[tag] = true
  64. }
  65. return nil
  66. }
  67. func checkOutbounds(outbounds []Outbound, endpoints []Endpoint) error {
  68. seen := make(map[string]bool)
  69. for i, outbound := range outbounds {
  70. tag := outbound.Tag
  71. if tag == "" {
  72. tag = F.ToString(i)
  73. }
  74. if seen[tag] {
  75. return E.New("duplicate outbound/endpoint tag: ", tag)
  76. }
  77. seen[tag] = true
  78. }
  79. for i, endpoint := range endpoints {
  80. tag := endpoint.Tag
  81. if tag == "" {
  82. tag = F.ToString(i)
  83. }
  84. if seen[tag] {
  85. return E.New("duplicate outbound/endpoint tag: ", tag)
  86. }
  87. seen[tag] = true
  88. }
  89. return nil
  90. }