github.com/ipfans/trojan-go@v0.11.0/proxy/option.go (about)

     1  package proxy
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/ipfans/trojan-go/common"
    13  	"github.com/ipfans/trojan-go/constant"
    14  	"github.com/ipfans/trojan-go/log"
    15  	"github.com/ipfans/trojan-go/option"
    16  )
    17  
    18  type Option struct {
    19  	path *string
    20  }
    21  
    22  func (o *Option) Name() string {
    23  	return Name
    24  }
    25  
    26  func detectAndReadConfig(file string) ([]byte, bool, error) {
    27  	isJSON := false
    28  	switch {
    29  	case strings.HasSuffix(file, ".json"):
    30  		isJSON = true
    31  	case strings.HasSuffix(file, ".yaml"), strings.HasSuffix(file, ".yml"):
    32  		isJSON = false
    33  	default:
    34  		log.Fatalf("unsupported config format: %s. use .yaml or .json instead.", file)
    35  	}
    36  
    37  	data, err := ioutil.ReadFile(file)
    38  	if err != nil {
    39  		return nil, false, err
    40  	}
    41  	return data, isJSON, nil
    42  }
    43  
    44  func (o *Option) Handle() error {
    45  	defaultConfigPath := []string{
    46  		"config.json",
    47  		"config.yml",
    48  		"config.yaml",
    49  	}
    50  
    51  	isJSON := false
    52  	var data []byte
    53  	var err error
    54  
    55  	switch *o.path {
    56  	case "":
    57  		log.Warn("no specified config file, use default path to detect config file")
    58  		for _, file := range defaultConfigPath {
    59  			log.Warn("try to load config from default path:", file)
    60  			data, isJSON, err = detectAndReadConfig(file)
    61  			if err != nil {
    62  				log.Warn(err)
    63  				continue
    64  			}
    65  			break
    66  		}
    67  	default:
    68  		data, isJSON, err = detectAndReadConfig(*o.path)
    69  		if err != nil {
    70  			log.Fatal(err)
    71  		}
    72  	}
    73  
    74  	if data != nil {
    75  		log.Info("trojan-go", constant.Version, "initializing")
    76  		proxy, err := NewProxyFromConfigData(data, isJSON)
    77  		if err != nil {
    78  			log.Fatal(err)
    79  		}
    80  		err = proxy.Run()
    81  		if err != nil {
    82  			log.Fatal(err)
    83  		}
    84  	}
    85  
    86  	log.Fatal("no valid config")
    87  	return nil
    88  }
    89  
    90  func (o *Option) Priority() int {
    91  	return -1
    92  }
    93  
    94  func init() {
    95  	option.RegisterHandler(&Option{
    96  		path: flag.String("config", "", "Trojan-Go config filename (.yaml/.yml/.json)"),
    97  	})
    98  	option.RegisterHandler(&StdinOption{
    99  		format:       flag.String("stdin-format", "disabled", "Read from standard input (yaml/json)"),
   100  		suppressHint: flag.Bool("stdin-suppress-hint", false, "Suppress hint text"),
   101  	})
   102  }
   103  
   104  type StdinOption struct {
   105  	format       *string
   106  	suppressHint *bool
   107  }
   108  
   109  func (o *StdinOption) Name() string {
   110  	return Name + "_STDIN"
   111  }
   112  
   113  func (o *StdinOption) Handle() error {
   114  	isJSON, e := o.isFormatJson()
   115  	if e != nil {
   116  		return e
   117  	}
   118  
   119  	if o.suppressHint == nil || !*o.suppressHint {
   120  		fmt.Printf("Trojan-Go %s (%s/%s)\n", constant.Version, runtime.GOOS, runtime.GOARCH)
   121  		if isJSON {
   122  			fmt.Println("Reading JSON configuration from stdin.")
   123  		} else {
   124  			fmt.Println("Reading YAML configuration from stdin.")
   125  		}
   126  	}
   127  
   128  	data, e := ioutil.ReadAll(bufio.NewReader(os.Stdin))
   129  	if e != nil {
   130  		log.Fatalf("Failed to read from stdin: %s", e.Error())
   131  	}
   132  
   133  	proxy, err := NewProxyFromConfigData(data, isJSON)
   134  	if err != nil {
   135  		log.Fatal(err)
   136  	}
   137  	err = proxy.Run()
   138  	if err != nil {
   139  		log.Fatal(err)
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (o *StdinOption) Priority() int {
   146  	return 0
   147  }
   148  
   149  func (o *StdinOption) isFormatJson() (isJson bool, e error) {
   150  	if o.format == nil {
   151  		return false, common.NewError("format specifier is nil")
   152  	}
   153  	if *o.format == "disabled" {
   154  		return false, common.NewError("reading from stdin is disabled")
   155  	}
   156  	return strings.ToLower(*o.format) == "json", nil
   157  }