summaryrefslogtreecommitdiffstats
path: root/recipes-graphics/wayland/weston-ini-conf.bbappend
diff options
context:
space:
mode:
authorRonan Le Martret <ronan.lemartret@iot.bzh>2017-03-24 11:16:26 +0100
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2017-03-30 07:36:52 +0000
commit726fdfebd33e0c2d000c68db3f5495fffb50af2a (patch)
tree68028e61ec9633fde0dda2c1c084df7bb70aca46 /recipes-graphics/wayland/weston-ini-conf.bbappend
parent73338d9e0e288bcc08c821ef9b05f2571f928fd0 (diff)
Generate weston.ini dynamically
* bbappend on new package weston-ini-conf * for agl-demo, weston.ini must use ivi-shell.so Bug-AGL: SPEC-477 Change-Id: I3356900adfc166381dc01a158233348183a1c6db Signed-off-by: Ronan Le Martret <ronan.lemartret@iot.bzh>
Diffstat (limited to 'recipes-graphics/wayland/weston-ini-conf.bbappend')
-rw-r--r--recipes-graphics/wayland/weston-ini-conf.bbappend6
1 files changed, 6 insertions, 0 deletions
diff --git a/recipes-graphics/wayland/weston-ini-conf.bbappend b/recipes-graphics/wayland/weston-ini-conf.bbappend
new file mode 100644
index 000000000..b79c52608
--- /dev/null
+++ b/recipes-graphics/wayland/weston-ini-conf.bbappend
@@ -0,0 +1,6 @@
+WESTONCORE[shell] ??= "ivi-shell.so"
+
+WESTONIVISHELL[ivi-module] ??= "ivi-controller.so"
+WESTONIVISHELL[ivi-input-module] ??= "ivi-input-controller.so"
+
+WESTONSECTION[WESTONIVISHELL] = "ivi-shell"
3 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
package st

import (
	"encoding/json"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"syscall"
	"time"

	"strings"

	"fmt"

	"io"

	"io/ioutil"

	"regexp"

	"github.com/Sirupsen/logrus"
	common "github.com/iotbzh/xds-common/golib"
	"github.com/iotbzh/xds-server/lib/xdsconfig"
	"github.com/syncthing/syncthing/lib/config"
)

// SyncThing .
type SyncThing struct {
	BaseURL   string
	APIKey    string
	Home      string
	STCmd     *exec.Cmd
	STICmd    *exec.Cmd
	MyID      string
	Connected bool

	// Private fields
	binDir      string
	logsDir     string
	exitSTChan  chan ExitChan
	exitSTIChan chan ExitChan
	conf        *xdsconfig.Config
	client      *common.HTTPClient
	log         *logrus.Logger
	Events      *Events
}

// ExitChan Channel used for process exit
type ExitChan struct {
	status int
	err    error
}

// ConfigInSync Check whether if Syncthing configuration is in sync
type configInSync struct {
	ConfigInSync bool `json:"configInSync"`
}

// FolderStatus Information about the current status of a folder.
type FolderStatus struct {
	GlobalFiles       int   `json:"globalFiles"`
	GlobalDirectories int   `json:"globalDirectories"`
	GlobalSymlinks    int   `json:"globalSymlinks"`
	GlobalDeleted     int   `json:"globalDeleted"`
	GlobalBytes       int64 `json:"globalBytes"`

	LocalFiles       int   `json:"localFiles"`
	LocalDirectories int   `json:"localDirectories"`
	LocalSymlinks    int   `json:"localSymlinks"`
	LocalDeleted     int   `json:"localDeleted"`
	LocalBytes       int64 `json:"localBytes"`

	NeedFiles       int   `json:"needFiles"`
	NeedDirectories int   `json:"needDirectories"`
	NeedSymlinks    int   `json:"needSymlinks"`
	NeedDeletes     int   `json:"needDeletes"`
	NeedBytes       int64 `json:"needBytes"`

	InSyncFiles int   `json:"inSyncFiles"`
	InSyncBytes int64 `json:"inSyncBytes"`

	State        string    `json:"state"`
	StateChanged time.Time `json:"stateChanged"`

	Sequence int64 `json:"sequence"`

	IgnorePatterns bool `json:"ignorePatterns"`
}

// NewSyncThing creates a new instance of Syncthing
func NewSyncThing(conf *xdsconfig.Config, log *logrus.Logger) *SyncThing {
	var url, apiKey, home, binDir string

	stCfg := conf.FileConf.SThgConf
	if stCfg != nil {
		url = stCfg.GuiAddress
		apiKey = stCfg.GuiAPIKey
		home = stCfg.Home
		binDir = stCfg.BinDir
	}

	if url == "" {
		url = "http://localhost:8385"
	}
	if url[0:7] != "http://" {
		url = "http://" + url
	}

	if home == "" {
		panic("home parameter must be set")
	}

	s := SyncThing{
		BaseURL: url,
		APIKey:  apiKey,
		Home:    home,
		binDir:  binDir,
		logsDir: conf.FileConf.LogsDir,
		log:     log,
		conf:    conf,
	}

	// Create Events monitoring
	s.Events = s.NewEventListener()

	return &s
}

// Start Starts syncthing process
func (s *SyncThing) startProc(exeName string, args []string, env []string, eChan *chan ExitChan) (*exec.Cmd, error) {
	var err error
	var exePath string

	// Kill existing process (useful for debug ;-) )
	if os.Getenv("DEBUG_MODE") != "" {
		exec.Command("bash", "-c", "pkill -9 "+exeName).Output()
	}

	// When not set (or set to '.') set bin to path of xds-agent executable
	bdir := s.binDir
	if bdir == "" || bdir == "." {
		exe, _ := os.Executable()
		if exeAbsPath, err := filepath.Abs(exe); err == nil {
			if exePath, err := filepath.EvalSymlinks(exeAbsPath); err == nil {
				bdir = filepath.Dir(exePath)
			}
		}
	}

	exePath, err = exec.LookPath(path.Join(bdir, exeName))
	if err != nil {
		// Let's try in /opt/AGL/bin
		exePath, err = exec.LookPath(path.Join("opt", "AGL", "bin", exeName))
		if err != nil {
			return nil, fmt.Errorf("Cannot find %s executable in %s", exeName, bdir)
		}
	}
	cmd := exec.Command(exePath, args...)
	cmd.Env = os.Environ()
	for _, ev := range env {
		cmd.Env = append(cmd.Env, ev)
	}

	// open log file
	var outfile *os.File
	logFilename := filepath.Join(s.logsDir, exeName+".log")
	if s.logsDir != "" {
		outfile, err := os.Create(logFilename)
		if err != nil {
			return nil, fmt.Errorf("Cannot create log file %s", logFilename)
		}

		cmdOut, err := cmd.StdoutPipe()
		if err != nil {
			return nil, fmt.Errorf("Pipe stdout error for : %s", err)
		}

		go io.Copy(outfile, cmdOut)
	}

	err = cmd.Start()
	if err != nil {
		return nil, err
	}

	*eChan = make(chan ExitChan, 1)
	go func(c *exec.Cmd, oF *os.File) {
		status := 0
		sts, err := c.Process.Wait()
		if !sts.Success() {
			s := sts.Sys().(syscall.WaitStatus)
			status = s.ExitStatus()
		}
		if oF != nil {
			oF.Close()
		}
		s.log.Debugf("%s exited with status %d, err %v", exeName, status, err)

		*eChan <- ExitChan{status, err}
	}(cmd, outfile)

	return cmd, nil
}

// Start Starts syncthing process
func (s *SyncThing) Start() (*exec.Cmd, error) {
	var err error

	s.log.Infof(" ST home=%s", s.Home)
	s.log.Infof(" ST  url=%s", s.BaseURL)

	args := []string{
		"--home=" + s.Home,
		"-no-browser",
		"--gui-address=" + s.BaseURL,
	}

	if s.APIKey != "" {
		args = append(args, "-gui-apikey=\""+s.APIKey+"\"")
		s.log.Infof(" ST apikey=%s", s.APIKey)
	}
	if s.log.Level == logrus.DebugLevel {
		args = append(args, "-verbose")
	}

	env := []string{
		"STNODEFAULTFOLDER=1",
		"STNOUPGRADE=1",
	}

	s.STCmd, err = s.startProc("syncthing", args, env, &s.exitSTChan)

	// Use autogenerated apikey if not set by config.json
	if err == nil && s.APIKey == "" {
		if fd, err := os.Open(filepath.Join(s.Home, "config.xml")); err == nil {
			defer fd.Close()
			if b, err := ioutil.ReadAll(fd); err == nil {
				re := regexp.MustCompile("<apikey>(.*)</apikey>")
				key := re.FindStringSubmatch(string(b))
				if len(key) >= 1 {
					s.APIKey = key[1]
				}
			}
		}
	}

	return s.STCmd, err
}

// StartInotify Starts syncthing-inotify process
func (s *SyncThing) StartInotify() (*exec.Cmd, error) {
	var err error
	exeName := "syncthing-inotify"

	s.log.Infof(" STI  url=%s", s.BaseURL)

	args := []string{
		"-target=" + s.BaseURL,
	}
	if s.APIKey != "" {
		args = append(args, "-api="+s.APIKey)
		s.log.Infof("%s uses apikey=%s", exeName, s.APIKey)
	}
	if s.log.Level == logrus.DebugLevel {
		args = append(args, "-verbosity=4")
	}

	env := []string{}

	s.STICmd, err = s.startProc(exeName, args, env, &s.exitSTIChan)

	return s.STICmd, err
}

func (s *SyncThing) stopProc(pname string, proc *os.Process, exit chan ExitChan) {
	if err := proc.Signal(os.Interrupt); err != nil {
		s.log.Infof("Proc interrupt %s error: %s", pname, err.Error())

		select {
		case <-exit:
		case <-time.After(time.Second):
			// A bigger bonk on the head.
			if err := proc.Signal(os.Kill); err != nil {
				s.log.Infof("Proc term %s error: %s", pname, err.Error())
			}
			<-exit
		}
	}
	s.log.Infof("%s stopped (PID %d)", pname, proc.Pid)
}

// Stop Stops syncthing process
func (s *SyncThing) Stop() {
	if s.STCmd == nil {
		return
	}
	s.stopProc("syncthing", s.STCmd.Process, s.exitSTChan)
	s.STCmd = nil
}

// StopInotify Stops syncthing process
func (s *SyncThing) StopInotify() {
	if s.STICmd == nil {
		return
	}
	s.stopProc("syncthing-inotify", s.STICmd.Process, s.exitSTIChan)
	s.STICmd = nil
}

// Connect Establish HTTP connection with Syncthing
func (s *SyncThing) Connect() error {
	var err error
	s.Connected = false
	s.client, err = common.HTTPNewClient(s.BaseURL,
		common.HTTPClientConfig{
			URLPrefix:           "/rest",
			HeaderClientKeyName: "X-Syncthing-ID",
			LogOut:              s.conf.LogVerboseOut,
			LogPrefix:           "SYNCTHING: ",
			LogLevel:            common.HTTPLogLevelWarning,
		})
	s.client.SetLogLevel(s.log.Level.String())

	if err != nil {
		msg := ": " + err.Error()
		if strings.Contains(err.Error(), "connection refused") {
			msg = fmt.Sprintf("(url: %s)", s.BaseURL)
		}
		return fmt.Errorf("ERROR: cannot connect to Syncthing %s", msg)
	}
	if s.client == nil {
		return fmt.Errorf("ERROR: cannot connect to Syncthing (null client)")
	}

	s.MyID, err = s.IDGet()
	if err != nil {
		return fmt.Errorf("ERROR: cannot retrieve ID")
	}

	s.Connected = true

	// Start events monitoring
	err = s.Events.Start()

	return err
}

// IDGet returns the Syncthing ID of Syncthing instance running locally
func (s *SyncThing) IDGet() (string, error) {
	var data []byte
	if err := s.client.HTTPGet("system/status", &data); err != nil {
		return "", err
	}
	status := make(map[string]interface{})
	json.Unmarshal(data, &status)
	return status["myID"].(string), nil
}

// ConfigGet returns the current Syncthing configuration
func (s *SyncThing) ConfigGet() (config.Configuration, error) {
	var data []byte
	config := config.Configuration{}
	if err := s.client.HTTPGet("system/config", &data); err != nil {
		return config, err
	}
	err := json.Unmarshal(data, &config)
	return config, err
}

// ConfigSet set Syncthing configuration
func (s *SyncThing) ConfigSet(cfg config.Configuration) error {
	body, err := json.Marshal(cfg)
	if err != nil {
		return err
	}
	return s.client.HTTPPost("system/config", string(body))
}

// IsConfigInSync Returns true if configuration is in sync
func (s *SyncThing) IsConfigInSync() (bool, error) {
	var data []byte
	var d configInSync
	if err := s.client.HTTPGet("system/config/insync", &data); err != nil {
		return false, err
	}
	if err := json.Unmarshal(data, &d); err != nil {
		return false, err
	}
	return d.ConfigInSync, nil
}