Use autogenerated Synchting apikey.
[src/xds/xds-server.git] / lib / xdsconfig / fileconfig.go
1 package xdsconfig
2
3 import (
4         "encoding/json"
5         "fmt"
6         "os"
7         "os/user"
8         "path"
9         "path/filepath"
10         "regexp"
11         "strings"
12
13         "github.com/iotbzh/xds-server/lib/common"
14 )
15
16 type SyncThingConf struct {
17         BinDir     string `json:"binDir"`
18         Home       string `json:"home"`
19         GuiAddress string `json:"gui-address"`
20         GuiAPIKey  string `json:"gui-apikey"`
21 }
22
23 type FileConfig struct {
24         WebAppDir    string         `json:"webAppDir"`
25         ShareRootDir string         `json:"shareRootDir"`
26         SdkRootDir   string         `json:"sdkRootDir"`
27         HTTPPort     string         `json:"httpPort"`
28         SThgConf     *SyncThingConf `json:"syncthing"`
29         LogsDir      string         `json:"logsDir"`
30 }
31
32 // getConfigFromFile reads configuration from a config file.
33 // Order to determine which config file is used:
34 //  1/ from command line option: "--config myConfig.json"
35 //  2/ $HOME/.xds/config.json file
36 //  3/ <current_dir>/config.json file
37 //  4/ <xds-server executable dir>/config.json file
38
39 func updateConfigFromFile(c *Config, confFile string) error {
40
41         searchIn := make([]string, 0, 3)
42         if confFile != "" {
43                 searchIn = append(searchIn, confFile)
44         }
45         if usr, err := user.Current(); err == nil {
46                 searchIn = append(searchIn, path.Join(usr.HomeDir, ".xds", "config.json"))
47         }
48         cwd, err := os.Getwd()
49         if err == nil {
50                 searchIn = append(searchIn, path.Join(cwd, "config.json"))
51         }
52         exePath, err := filepath.Abs(filepath.Dir(os.Args[0]))
53         if err == nil {
54                 searchIn = append(searchIn, path.Join(exePath, "config.json"))
55         }
56
57         var cFile *string
58         for _, p := range searchIn {
59                 if _, err := os.Stat(p); err == nil {
60                         cFile = &p
61                         break
62                 }
63         }
64         if cFile == nil {
65                 // No config file found
66                 return nil
67         }
68
69         c.Log.Infof("Use config file: %s", *cFile)
70
71         // TODO move on viper package to support comments in JSON and also
72         // bind with flags (command line options)
73         // see https://github.com/spf13/viper#working-with-flags
74
75         fd, _ := os.Open(*cFile)
76         defer fd.Close()
77         fCfg := FileConfig{}
78         if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
79                 return err
80         }
81         c.FileConf = fCfg
82
83         // Support environment variables (IOW ${MY_ENV_VAR} syntax) in config.json
84         for _, field := range []*string{
85                 &fCfg.WebAppDir,
86                 &fCfg.ShareRootDir,
87                 &fCfg.SdkRootDir,
88                 &fCfg.LogsDir,
89                 &fCfg.SThgConf.Home,
90                 &fCfg.SThgConf.BinDir} {
91
92                 rep, err := resolveEnvVar(*field)
93                 if err != nil {
94                         return err
95                 }
96                 *field = path.Clean(rep)
97         }
98
99         // Config file settings overwrite default config
100
101         if fCfg.WebAppDir != "" {
102                 c.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
103         }
104         // Is it a full path ?
105         if !strings.HasPrefix(c.WebAppDir, "/") && exePath != "" {
106                 // Check first from current directory
107                 for _, rootD := range []string{cwd, exePath} {
108                         ff := path.Join(rootD, c.WebAppDir, "index.html")
109                         if common.Exists(ff) {
110                                 c.WebAppDir = path.Join(rootD, c.WebAppDir)
111                                 break
112                         }
113                 }
114         }
115
116         if fCfg.ShareRootDir != "" {
117                 c.ShareRootDir = fCfg.ShareRootDir
118         }
119
120         if fCfg.HTTPPort != "" {
121                 c.HTTPPort = fCfg.HTTPPort
122         }
123
124         return nil
125 }
126
127 // resolveEnvVar Resolved environment variable regarding the syntax ${MYVAR}
128 func resolveEnvVar(s string) (string, error) {
129         re := regexp.MustCompile("\\${(.*)}")
130         vars := re.FindAllStringSubmatch(s, -1)
131         res := s
132         for _, v := range vars {
133                 val := os.Getenv(v[1])
134                 if val == "" {
135                         return res, fmt.Errorf("ERROR: %s env variable not defined", v[1])
136                 }
137
138                 rer := regexp.MustCompile("\\${" + v[1] + "}")
139                 res = rer.ReplaceAllString(res, val)
140         }
141
142         return res, nil
143 }