options.go 2.4 KB

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