Set install dir to /opt/AGL and move conf to $HOME/.xds-server
[src/xds/xds-server.git] / lib / xdsconfig / fileconfig.go
1 package xdsconfig
2
3 import (
4         "encoding/json"
5         "os"
6         "os/user"
7         "path"
8         "path/filepath"
9         "strings"
10
11         common "github.com/iotbzh/xds-common/golib"
12 )
13
14 const (
15         // ConfigDir Directory in user HOME directory where xds config will be saved
16         ConfigDir = ".xds-server"
17         // GlobalConfigFilename Global config filename
18         GlobalConfigFilename = "config.json"
19         // FoldersConfigFilename Folders config filename
20         FoldersConfigFilename = "server-config_folders.xml"
21 )
22
23 // SyncThingConf definition
24 type SyncThingConf struct {
25         BinDir          string `json:"binDir"`
26         Home            string `json:"home"`
27         GuiAddress      string `json:"gui-address"`
28         GuiAPIKey       string `json:"gui-apikey"`
29         RescanIntervalS int    `json:"rescanIntervalS"`
30 }
31
32 // FileConfig is the JSON structure of xds-server config file (config.json)
33 type FileConfig struct {
34         WebAppDir    string         `json:"webAppDir"`
35         ShareRootDir string         `json:"shareRootDir"`
36         SdkRootDir   string         `json:"sdkRootDir"`
37         HTTPPort     string         `json:"httpPort"`
38         SThgConf     *SyncThingConf `json:"syncthing"`
39         LogsDir      string         `json:"logsDir"`
40 }
41
42 // readGlobalConfig reads configuration from a config file.
43 // Order to determine which config file is used:
44 //  1/ from command line option: "--config myConfig.json"
45 //  2/ $HOME/.xds-server/config.json file
46 //  3/ /etc/xds-server/config.json file
47 //  4/ <xds-server executable dir>/config.json file
48 func readGlobalConfig(c *Config, confFile string) error {
49
50         searchIn := make([]string, 0, 3)
51         if confFile != "" {
52                 searchIn = append(searchIn, confFile)
53         }
54         if usr, err := user.Current(); err == nil {
55                 searchIn = append(searchIn, path.Join(usr.HomeDir, ConfigDir,
56                         GlobalConfigFilename))
57         }
58
59         searchIn = append(searchIn, "/etc/xds-server/config.json")
60
61         exePath := os.Args[0]
62         exeAbsPath, err := filepath.Abs(os.Args[0])
63         if err == nil {
64                 exePath, err = filepath.EvalSymlinks(exeAbsPath)
65                 if err == nil {
66                         exePath = filepath.Dir(exePath)
67                 } else {
68                         exePath = filepath.Dir(exeAbsPath)
69                 }
70         }
71         searchIn = append(searchIn, path.Join(exePath, "config.json"))
72
73         var cFile *string
74         for _, p := range searchIn {
75                 if _, err := os.Stat(p); err == nil {
76                         cFile = &p
77                         break
78                 }
79         }
80         if cFile == nil {
81                 // No config file found
82                 return nil
83         }
84         c.Log.Infof("Use config file: %s", *cFile)
85
86         // TODO move on viper package to support comments in JSON and also
87         // bind with flags (command line options)
88         // see https://github.com/spf13/viper#working-with-flags
89         fd, _ := os.Open(*cFile)
90         defer fd.Close()
91         fCfg := FileConfig{}
92         if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
93                 return err
94         }
95
96         // Support environment variables (IOW ${MY_ENV_VAR} syntax) in config.json
97         vars := []*string{
98                 &fCfg.WebAppDir,
99                 &fCfg.ShareRootDir,
100                 &fCfg.SdkRootDir,
101                 &fCfg.LogsDir}
102         if fCfg.SThgConf != nil {
103                 vars = append(vars, &fCfg.SThgConf.Home, &fCfg.SThgConf.BinDir)
104         }
105         for _, field := range vars {
106                 var err error
107                 if *field, err = common.ResolveEnvVar(*field); err != nil {
108                         return err
109                 }
110         }
111
112         // Use config file settings else use default config
113         if fCfg.WebAppDir == "" {
114                 fCfg.WebAppDir = c.FileConf.WebAppDir
115         }
116         if fCfg.ShareRootDir == "" {
117                 fCfg.ShareRootDir = c.FileConf.ShareRootDir
118         }
119         if fCfg.SdkRootDir == "" {
120                 fCfg.SdkRootDir = c.FileConf.SdkRootDir
121         }
122         if fCfg.HTTPPort == "" {
123                 fCfg.HTTPPort = c.FileConf.HTTPPort
124         }
125         if fCfg.LogsDir == "" {
126                 fCfg.LogsDir = c.FileConf.LogsDir
127         }
128
129         // Resolve webapp dir (support relative or full path)
130         fCfg.WebAppDir = strings.Trim(fCfg.WebAppDir, " ")
131         if !strings.HasPrefix(fCfg.WebAppDir, "/") && exePath != "" {
132                 cwd, _ := os.Getwd()
133
134                 // Check first from current directory
135                 for _, rootD := range []string{exePath, cwd} {
136                         ff := path.Join(rootD, fCfg.WebAppDir, "index.html")
137                         if common.Exists(ff) {
138                                 fCfg.WebAppDir = path.Join(rootD, fCfg.WebAppDir)
139                                 break
140                         }
141                 }
142         }
143
144         c.FileConf = fCfg
145         return nil
146 }
147
148 // FoldersConfigFilenameGet
149 func FoldersConfigFilenameGet() (string, error) {
150         usr, err := user.Current()
151         if err != nil {
152                 return "", err
153         }
154         return path.Join(usr.HomeDir, ConfigDir, FoldersConfigFilename), nil
155 }