Given that there may be other Turing complete query interfaces (particularly a Go query API), the timeout config should not be specifically tied to gremlin.
197 lines
5.3 KiB
Go
197 lines
5.3 KiB
Go
// Copyright 2014 The Cayley Authors. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/barakmich/glog"
|
|
)
|
|
|
|
type Config struct {
|
|
DatabaseType string
|
|
DatabasePath string
|
|
DatabaseOptions map[string]interface{}
|
|
ListenHost string
|
|
ListenPort string
|
|
ReadOnly bool
|
|
Timeout time.Duration
|
|
LoadSize int
|
|
}
|
|
|
|
type config struct {
|
|
DatabaseType string `json:"database"`
|
|
DatabasePath string `json:"db_path"`
|
|
DatabaseOptions map[string]interface{} `json:"db_options"`
|
|
ListenHost string `json:"listen_host"`
|
|
ListenPort string `json:"listen_port"`
|
|
ReadOnly bool `json:"read_only"`
|
|
Timeout duration `json:"timeout"`
|
|
LoadSize int `json:"load_size"`
|
|
}
|
|
|
|
func (c *Config) UnmarshalJSON(data []byte) error {
|
|
var t config
|
|
err := json.Unmarshal(data, &t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*c = Config{
|
|
DatabaseType: t.DatabaseType,
|
|
DatabasePath: t.DatabasePath,
|
|
DatabaseOptions: t.DatabaseOptions,
|
|
ListenHost: t.ListenHost,
|
|
ListenPort: t.ListenPort,
|
|
ReadOnly: t.ReadOnly,
|
|
Timeout: time.Duration(t.Timeout),
|
|
LoadSize: t.LoadSize,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Config) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(config{
|
|
DatabaseType: c.DatabaseType,
|
|
DatabasePath: c.DatabasePath,
|
|
DatabaseOptions: c.DatabaseOptions,
|
|
ListenHost: c.ListenHost,
|
|
ListenPort: c.ListenPort,
|
|
ReadOnly: c.ReadOnly,
|
|
Timeout: duration(c.Timeout),
|
|
LoadSize: c.LoadSize,
|
|
})
|
|
}
|
|
|
|
// duration is a time.Duration that satisfies the
|
|
// json.UnMarshaler and json.Marshaler interfaces.
|
|
type duration time.Duration
|
|
|
|
// UnmarshalJSON unmarshals a duration according to the following scheme:
|
|
// * If the element is absent the duration is zero.
|
|
// * If the element is parsable as a time.Duration, the parsed value is kept.
|
|
// * If the element is parsable as a number, that number of seconds is kept.
|
|
func (d *duration) UnmarshalJSON(data []byte) error {
|
|
if len(data) == 0 {
|
|
*d = 0
|
|
return nil
|
|
}
|
|
text := string(data)
|
|
t, err := time.ParseDuration(text)
|
|
if err == nil {
|
|
*d = duration(t)
|
|
return nil
|
|
}
|
|
i, err := strconv.ParseInt(text, 10, 64)
|
|
if err == nil {
|
|
*d = duration(time.Duration(i) * time.Second)
|
|
return nil
|
|
}
|
|
// This hack is to get around strconv.ParseFloat
|
|
// not handling e-notation for integers.
|
|
f, err := strconv.ParseFloat(text, 64)
|
|
*d = duration(time.Duration(f) * time.Second)
|
|
return err
|
|
}
|
|
|
|
func (d *duration) MarshalJSON() ([]byte, error) {
|
|
return []byte(fmt.Sprintf("%q", *d)), nil
|
|
}
|
|
|
|
var (
|
|
databasePath = flag.String("dbpath", "/tmp/testdb", "Path to the database.")
|
|
databaseBackend = flag.String("db", "memstore", "Database Backend.")
|
|
host = flag.String("host", "0.0.0.0", "Host to listen on (defaults to all).")
|
|
loadSize = flag.Int("load_size", 10000, "Size of triplesets to load")
|
|
port = flag.String("port", "64210", "Port to listen on.")
|
|
readOnly = flag.Bool("read_only", false, "Disable writing via HTTP.")
|
|
timeout = flag.Duration("timeout", 30*time.Second, "Elapsed time until an individual query times out.")
|
|
)
|
|
|
|
func ParseConfigFromFile(filename string) *Config {
|
|
config := &Config{}
|
|
if filename == "" {
|
|
return config
|
|
}
|
|
f, err := os.Open(filename)
|
|
if err != nil {
|
|
glog.Fatalln("Couldn't open config file", filename)
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
dec := json.NewDecoder(f)
|
|
err = dec.Decode(config)
|
|
if err != nil {
|
|
glog.Fatalln("Couldn't read config file:", err)
|
|
}
|
|
return config
|
|
}
|
|
|
|
func ParseConfigFromFlagsAndFile(fileFlag string) *Config {
|
|
// Find the file...
|
|
var trueFilename string
|
|
if fileFlag != "" {
|
|
if _, err := os.Stat(fileFlag); os.IsNotExist(err) {
|
|
glog.Fatalln("Cannot find specified configuration file", fileFlag, ", aborting.")
|
|
} else {
|
|
trueFilename = fileFlag
|
|
}
|
|
} else {
|
|
if _, err := os.Stat(os.Getenv("CAYLEY_CFG")); err == nil {
|
|
trueFilename = os.Getenv("CAYLEY_CFG")
|
|
} else {
|
|
if _, err := os.Stat("/etc/cayley.cfg"); err == nil {
|
|
trueFilename = "/etc/cayley.cfg"
|
|
}
|
|
}
|
|
}
|
|
if trueFilename == "" {
|
|
glog.Infoln("Couldn't find a config file in either $CAYLEY_CFG or /etc/cayley.cfg. Going by flag defaults only.")
|
|
}
|
|
config := ParseConfigFromFile(trueFilename)
|
|
|
|
if config.DatabasePath == "" {
|
|
config.DatabasePath = *databasePath
|
|
}
|
|
|
|
if config.DatabaseType == "" {
|
|
config.DatabaseType = *databaseBackend
|
|
}
|
|
|
|
if config.ListenHost == "" {
|
|
config.ListenHost = *host
|
|
}
|
|
|
|
if config.ListenPort == "" {
|
|
config.ListenPort = *port
|
|
}
|
|
|
|
if config.Timeout == 0 {
|
|
config.Timeout = *timeout
|
|
}
|
|
|
|
if config.LoadSize == 0 {
|
|
config.LoadSize = *loadSize
|
|
}
|
|
|
|
config.ReadOnly = config.ReadOnly || *readOnly
|
|
|
|
return config
|
|
}
|