options.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package option
  2. import (
  3. "bytes"
  4. "context"
  5. E "github.com/sagernet/sing/common/exceptions"
  6. "github.com/sagernet/sing/common/json"
  7. )
  8. type _Options struct {
  9. RawMessage json.RawMessage `json:"-"`
  10. Schema string `json:"$schema,omitempty"`
  11. Log *LogOptions `json:"log,omitempty"`
  12. DNS *DNSOptions `json:"dns,omitempty"`
  13. NTP *NTPOptions `json:"ntp,omitempty"`
  14. Certificate *CertificateOptions `json:"certificate,omitempty"`
  15. Endpoints []Endpoint `json:"endpoints,omitempty"`
  16. Inbounds []Inbound `json:"inbounds,omitempty"`
  17. Outbounds []Outbound `json:"outbounds,omitempty"`
  18. Route *RouteOptions `json:"route,omitempty"`
  19. Services []Service `json:"services,omitempty"`
  20. Experimental *ExperimentalOptions `json:"experimental,omitempty"`
  21. }
  22. type Options _Options
  23. func (o *Options) UnmarshalJSONContext(ctx context.Context, content []byte) error {
  24. decoder := json.NewDecoderContext(ctx, bytes.NewReader(content))
  25. decoder.DisallowUnknownFields()
  26. err := decoder.Decode((*_Options)(o))
  27. if err != nil {
  28. return err
  29. }
  30. o.RawMessage = content
  31. return checkOptions(o)
  32. }
  33. type LogOptions struct {
  34. Disabled bool `json:"disabled,omitempty"`
  35. Level string `json:"level,omitempty"`
  36. Output string `json:"output,omitempty"`
  37. Timestamp bool `json:"timestamp,omitempty"`
  38. DisableColor bool `json:"-"`
  39. }
  40. type StubOptions struct{}
  41. func checkOptions(options *Options) error {
  42. err := checkInbounds(options.Inbounds)
  43. if err != nil {
  44. return err
  45. }
  46. err = checkOutbounds(options.Outbounds, options.Endpoints)
  47. if err != nil {
  48. return err
  49. }
  50. return nil
  51. }
  52. func checkInbounds(inbounds []Inbound) error {
  53. seen := make(map[string]bool)
  54. for _, inbound := range inbounds {
  55. if inbound.Tag == "" {
  56. continue
  57. }
  58. if seen[inbound.Tag] {
  59. return E.New("duplicate inbound tag: ", inbound.Tag)
  60. }
  61. seen[inbound.Tag] = true
  62. }
  63. return nil
  64. }
  65. func checkOutbounds(outbounds []Outbound, endpoints []Endpoint) error {
  66. seen := make(map[string]bool)
  67. for _, outbound := range outbounds {
  68. if outbound.Tag == "" {
  69. continue
  70. }
  71. if seen[outbound.Tag] {
  72. return E.New("duplicate outbound/endpoint tag: ", outbound.Tag)
  73. }
  74. seen[outbound.Tag] = true
  75. }
  76. for _, endpoint := range endpoints {
  77. if endpoint.Tag == "" {
  78. continue
  79. }
  80. if seen[endpoint.Tag] {
  81. return E.New("duplicate outbound/endpoint tag: ", endpoint.Tag)
  82. }
  83. seen[endpoint.Tag] = true
  84. }
  85. return nil
  86. }