options.go 2.4 KB

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