lurkcoin-core/lurkcoin/api/config.go

214 lines
5.2 KiB
Go
Raw Permalink Normal View History

2020-04-21 12:24:16 +02:00
//
// lurkcoin configuration
// Copyright © 2020 by luk3yx
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
package api
import (
"fmt"
2021-02-22 07:19:35 +01:00
"github.com/luk3yx/lurkcoin-core/lurkcoin"
"github.com/luk3yx/lurkcoin-core/lurkcoin/databases"
2020-04-21 12:24:16 +02:00
"gopkg.in/yaml.v2"
"io/ioutil"
2020-04-21 12:24:16 +02:00
"log"
2020-06-15 07:44:51 +02:00
"net"
2020-04-21 12:24:16 +02:00
"net/http"
"os"
"path/filepath"
2020-04-21 12:24:16 +02:00
"strings"
)
type Config struct {
// The name of this service (for example "lurkcoin"). This is also used as
// the default server name for the v2 API.
Name string `yaml:"name"`
2020-06-15 07:44:51 +02:00
// The network protocol to use when binding to the socket. Defaults to
// "tcp", can be set to "unix" for example.
NetworkProtocol string `yaml:"network_protocol"`
2020-04-21 12:24:16 +02:00
// The address to bind to (optional) and port.
Address string `yaml:"address"`
Port uint16 `yaml:"port"`
// An optional logfile
Logfile string `yaml:"logfile"`
Database struct {
Type string `yaml:"type"`
Location string `yaml:"location"`
Options map[string]string `yaml:"options"`
} `yaml:"database"`
// TLS
TLS struct {
Enable bool `yaml:"enable"`
CertFile string `yaml:"cert_file"`
KeyFile string `yaml:"key_file"`
} `yaml:"tls"`
// Admin pages
AdminPages struct {
Enable bool `yaml:"enable"`
Users AdminLoginDetails `yaml:"users"`
} `yaml:"admin_pages"`
// HTTP redirects
Redirects map[string]string `yaml:"redirects"`
// The minimum HTTPS API version to support.
MinAPIVersion uint8 `yaml:"min_api_version"`
// Suppresses any HTTP-related logs such as TLS handshake errors.
SuppressHTTPLogs bool `yaml:"suppress_http_logs"`
// Disables HTTP keep-alives.
DisableHTTPKeepAlives bool `yaml:"disable_http_keepalives"`
2020-04-21 12:24:16 +02:00
}
func LoadConfig(filename string) (*Config, error) {
f, err := os.OpenFile(filename, os.O_RDONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
var config Config
decoder := yaml.NewDecoder(f)
decoder.SetStrict(true)
err = decoder.Decode(&config)
if err != nil {
return nil, err
}
if config.Name == "lurkcoin" {
log.Println("Warning: The selected server name already exists!")
}
return &config, nil
}
func OpenDatabase(config *Config) (lurkcoin.Database, error) {
return databases.OpenDatabase(
config.Database.Type,
config.Database.Location,
config.Database.Options,
)
}
func StartServer(config *Config) {
lurkcoin.SeedPRNG()
lurkcoin.PrintASCIIArt()
log.Printf("Supported database types: %s",
strings.Join(databases.GetSupportedDatabaseTypes(), ", "))
db, err := OpenDatabase(config)
if err != nil {
log.Fatal(err)
}
router := MakeHTTPRouter(db, config)
2020-06-15 07:44:51 +02:00
var address, networkProtocol, urlAddress string
switch config.NetworkProtocol {
case "", "tcp":
if config.Port == 0 {
address = config.Address
} else {
address = fmt.Sprintf("%s:%d", address, config.Port)
}
networkProtocol = "tcp"
urlAddress = address
if address != "" && address[0] == ':' {
urlAddress = "[::]" + urlAddress
}
case "unix":
address = config.Address
networkProtocol = "unix"
urlAddress = "unix:" + address + ":"
if config.Port != 0 {
log.Fatal("The port option is invalid with UNIX sockets.")
}
default:
log.Fatalf("Unrecognised network protocol: %q", config.NetworkProtocol)
2020-04-21 12:24:16 +02:00
}
2020-06-15 07:44:51 +02:00
2020-04-21 12:24:16 +02:00
if config.TLS.Enable {
log.Printf("Starting server on https://%s/", urlAddress)
} else {
log.Printf("Starting server on http://%s/", urlAddress)
}
2020-06-15 07:55:43 +02:00
// Remove any socket file that already exists
var changeSocketPermissions bool
2020-06-15 07:55:43 +02:00
if networkProtocol == "unix" {
os.Remove(address)
// Only call chmod if no other users can write to the directory
if stat, err := os.Stat(filepath.Dir(address)); err == nil {
2021-02-22 07:19:35 +01:00
changeSocketPermissions = stat.Mode()&022 == 0
}
2020-06-15 07:55:43 +02:00
}
2020-06-15 07:44:51 +02:00
// Bind to the address
var ln net.Listener
ln, err = net.Listen(networkProtocol, address)
if err != nil {
log.Fatal(err)
}
2020-06-15 07:55:43 +02:00
// Change permissions on the UNIX socket
if changeSocketPermissions {
2020-06-15 07:55:43 +02:00
if err := os.Chmod(address, 0777); err != nil {
log.Fatal(err)
}
}
2020-06-15 07:44:51 +02:00
// Switch to the logfile
2020-04-21 12:24:16 +02:00
if config.Logfile != "" {
f, err := os.OpenFile(
config.Logfile,
os.O_WRONLY|os.O_APPEND|os.O_CREATE,
0600,
)
if err != nil {
log.Fatal(err)
}
defer f.Close()
log.Printf("Using logfile %#v.", config.Logfile)
log.SetOutput(f)
}
// Suppress HTTP logs.
2020-04-21 12:24:16 +02:00
server := &http.Server{Addr: address, Handler: router}
if config.SuppressHTTPLogs {
server.ErrorLog = log.New(ioutil.Discard, "", 0)
}
2020-04-21 12:24:16 +02:00
// My laptop doesn't work nicely with Keep-Alive.
if config.DisableHTTPKeepAlives {
server.SetKeepAlivesEnabled(false)
}
2020-04-21 12:24:16 +02:00
2020-06-15 07:44:51 +02:00
// Serve the webpage
2020-04-21 12:24:16 +02:00
if config.TLS.Enable {
2020-06-15 07:44:51 +02:00
err = server.ServeTLS(ln, config.TLS.CertFile, config.TLS.KeyFile)
2020-04-21 12:24:16 +02:00
} else {
2020-06-15 07:44:51 +02:00
err = server.Serve(ln)
2020-04-21 12:24:16 +02:00
}
log.Fatal(err)
}