summaryrefslogtreecommitdiffstats
path: root/lib/xdsconfig/config.go
blob: df98439e99d7558e3e1ee51fa1e2008358d34de2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
SUMMARY     = "Bluetooth MAP Service Binding"
DESCRIPTION = "AGL Bluetooth MAP Service Binding"
HOMEPAGE    = "https://gerrit.automotivelinux.org/gerrit/#/admin/projects/apps/agl-service-bluetooth-map"
SECTION     = "apps"

LICENSE     = "Apache-2.0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=89aea4e17d99a7cacdbeed46a0096b10"

SRC_URI = "git://gerrit.automotivelinux.org/gerrit/apps/agl-service-bluetooth-map;protocol=https;branch=${AGL_BRANCH}"
SRCREV  = "${AGL_APP_REVISION}"

PV = "1.0+git${SRCPV}"
S  = "${WORKDIR}/git"

DEPENDS = "glib-2.0 json-c"
RDEPENDS_${PN} = "bluez5-obex agl-service-bluetooth"

inherit cmake aglwgt pkgconfig
ht .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
package xdsconfig

import (
	"fmt"
	"strings"

	"os"

	"time"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/iotbzh/xds-server/lib/syncthing"
)

// Config parameters (json format) of /config command
type Config struct {
	Version       string        `json:"version"`
	APIVersion    string        `json:"apiVersion"`
	VersionGitTag string        `json:"gitTag"`
	Builder       BuilderConfig `json:"builder"`
	Folders       FoldersConfig `json:"folders"`

	// Private / un-exported fields
	progName     string
	fileConf     FileConfig
	WebAppDir    string         `json:"-"`
	HTTPPort     string         `json:"-"`
	ShareRootDir string         `json:"-"`
	Log          *logrus.Logger `json:"-"`
	SThg         *st.SyncThing  `json:"-"`
}

// Config default values
const (
	DefaultAPIVersion = "1"
	DefaultPort       = "8000"
	DefaultShareDir   = "/mnt/share"
	DefaultLogLevel   = "error"
)

// Init loads the configuration on start-up
func Init(ctx *cli.Context) (Config, error) {
	var err error

	// Set logger level and formatter
	log := ctx.App.Metadata["logger"].(*logrus.Logger)

	logLevel := ctx.GlobalString("log")
	if logLevel == "" {
		logLevel = DefaultLogLevel
	}
	if log.Level, err = logrus.ParseLevel(logLevel); err != nil {
		fmt.Printf("Invalid log level : \"%v\"\n", logLevel)
		os.Exit(1)
	}
	log.Formatter = &logrus.TextFormatter{}

	// Define default configuration
	c := Config{
		Version:       ctx.App.Metadata["version"].(string),
		APIVersion:    DefaultAPIVersion,
		VersionGitTag: ctx.App.Metadata["git-tag"].(string),
		Builder:       BuilderConfig{},
		Folders:       FoldersConfig{},

		progName:     ctx.App.Name,
		WebAppDir:    "webapp/dist",
		HTTPPort:     DefaultPort,
		ShareRootDir: DefaultShareDir,
		Log:          log,
		SThg:         nil,
	}

	// config file settings overwrite default config
	err = updateConfigFromFile(&c, ctx.GlobalString("config"))
	if err != nil {
		return Config{}, err
	}

	// Update location of shared dir if needed
	if !dirExists(c.ShareRootDir) {
		if err := os.MkdirAll(c.ShareRootDir, 0770); err != nil {
			c.Log.Fatalf("No valid shared directory found (err=%v)", err)
		}
	}
	c.Log.Infoln("Share root directory: ", c.ShareRootDir)

	// FIXME - add a builder interface and support other builder type (eg. native)
	builderType := "syncthing"

	switch builderType {
	case "syncthing":
		// Syncthing settings only configurable from config.json file
		stGuiAddr := c.fileConf.SThgConf.GuiAddress
		stGuiApikey := c.fileConf.SThgConf.GuiAPIKey
		if stGuiAddr == "" {
			stGuiAddr = "http://localhost:8384"
		}
		if stGuiAddr[0:7] != "http://" {
			stGuiAddr = "http://" + stGuiAddr
		}

		// Retry if connection fail
		retry := 5
		for retry > 0 {
			c.SThg = st.NewSyncThing(stGuiAddr, stGuiApikey, c.Log)
			if c.SThg != nil {
				break
			}
			c.Log.Warningf("Establishing connection to Syncthing (retry %d/5)", retry)
			time.Sleep(time.Second)
			retry--
		}
		if c.SThg == nil {
			c.Log.Fatalf("ERROR: cannot connect to Syncthing (url: %s)", stGuiAddr)
		}

		// Retrieve Syncthing config
		id, err := c.SThg.IDGet()
		if err != nil {
			return Config{}, err
		}

		if c.Builder, err = NewBuilderConfig(id); err != nil {
			c.Log.Fatalln(err)
		}

		// Retrieve initial Syncthing config
		stCfg, err := c.SThg.ConfigGet()
		if err != nil {
			return Config{}, err
		}
		for _, stFld := range stCfg.Folders {
			relativePath := strings.TrimPrefix(stFld.RawPath, c.ShareRootDir)
			if relativePath == "" {
				relativePath = stFld.RawPath
			}
			newFld := NewFolderConfig(stFld.ID, stFld.Label, c.ShareRootDir, strings.Trim(relativePath, "/"))
			c.Folders = c.Folders.Update(FoldersConfig{newFld})
		}

	default:
		log.Fatalln("Unsupported builder type")
	}

	return c, nil
}

// GetFolderFromID retrieves the Folder config from id
func (c *Config) GetFolderFromID(id string) *FolderConfig {
	if idx := c.Folders.GetIdx(id); idx != -1 {
		return &c.Folders[idx]
	}
	return nil
}

// UpdateAll updates all the current configuration
func (c *Config) UpdateAll(newCfg Config) error {
	return fmt.Errorf("Not Supported")
	/*
		if err := VerifyConfig(newCfg); err != nil {
			return err
		}

		// TODO: c.Builder = c.Builder.Update(newCfg.Builder)
		c.Folders = c.Folders.Update(newCfg.Folders)

		// SEB A SUP model.NotifyListeners(c, NotifyFoldersChange, FolderConfig{})
		// FIXME To be tested & improved error handling
		for _, f := range c.Folders {
			if err := c.SThg.FolderChange(st.FolderChangeArg{
				ID:           f.ID,
				Label:        f.Label,
				RelativePath: f.RelativePath,
				SyncThingID:  f.SyncThingID,
				ShareRootDir: c.ShareRootDir,
			}); err != nil {
				return err
			}
		}

		return nil
	*/
}

// UpdateFolder updates a specific folder into the current configuration
func (c *Config) UpdateFolder(newFolder FolderConfig) (FolderConfig, error) {
	if err := FolderVerify(newFolder); err != nil {
		return FolderConfig{}, err
	}

	c.Folders = c.Folders.Update(FoldersConfig{newFolder})

	// SEB A SUP model.NotifyListeners(c, NotifyFolderAdd, newFolder)
	err := c.SThg.FolderChange(st.FolderChangeArg{
		ID:           newFolder.ID,
		Label:        newFolder.Label,
		RelativePath: newFolder.RelativePath,
		SyncThingID:  newFolder.SyncThingID,
		ShareRootDir: c.ShareRootDir,
	})

	newFolder.BuilderSThgID = c.Builder.SyncThingID // FIXME - should be removed after local ST config rework
	newFolder.Status = FolderStatusEnable

	return newFolder, err
}

// DeleteFolder deletes a specific folder
func (c *Config) DeleteFolder(id string) (FolderConfig, error) {
	var fld FolderConfig
	var err error

	//SEB A SUP model.NotifyListeners(c, NotifyFolderDelete, fld)
	if err = c.SThg.FolderDelete(id); err != nil {
		return fld, err
	}

	c.Folders, fld, err = c.Folders.Delete(id)

	return fld, err
}

func dirExists(path string) bool {
	_, err := os.Stat(path)
	if os.IsNotExist(err) {
		return false
	}
	return true
}