package main
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"flag"
"io/ioutil"
"os"
"os/signal"
"syscall"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
"git.deuxfleurs.fr/Deuxfleurs/easybridge/mxlib"
)
type ConfigFile struct {
LogLevel string `json:"log_level"`
Registration string `json:"registration"`
ASBindAddr string `json:"appservice_bind_addr"`
Server string `json:"homeserver_url"`
MatrixDomain string `json:"matrix_domain"`
NameFormat string `json:"name_format"`
WebBindAddr string `json:"web_bind_addr"`
WebURL string `json:"web_url"`
SessionKey string `json:"web_session_key"`
DbType string `json:"db_type"`
DbPath string `json:"db_path"`
AvatarFile string `json:"easybridge_avatar"`
}
var configFlag = flag.String("config", "./config.json", "Configuration file path")
var config *ConfigFile
var registration *mxlib.Registration
func readConfig() ConfigFile {
defaultKey := make([]byte, 32)
rand.Read(defaultKey)
config_file := ConfigFile{
LogLevel: "info",
ASBindAddr: "0.0.0.0:8321",
WebBindAddr: "0.0.0.0:8281",
Registration: "./registration.yaml",
Server: "http://localhost:8008",
NameFormat: "{}_ezbr_",
DbType: "sqlite3",
DbPath: "easybridge.db",
AvatarFile: "./easybridge.jpg",
SessionKey: hex.EncodeToString(defaultKey),
}
_, err := os.Stat(*configFlag)
if os.IsNotExist(err) {
// Generate default config file
log.Printf("Generating default config file as %s", *configFlag)
bytes, err := json.MarshalIndent(&config_file, "", " ")
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(*configFlag, bytes, 0644)
if err != nil {
log.Fatal(err)
}
return config_file
}
if err != nil {
log.Fatal(err)
}
bytes, err := ioutil.ReadFile(*configFlag)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(bytes, &config_file)
if err != nil {
log.Fatal(err)
}
return config_file
}
func readRegistration(file string) mxlib.Registration {
rnd := make([]byte, 64)
n, err := rand.Read(rnd)
if err != nil || n != 64 {
log.Fatal(err)
}
reg := mxlib.Registration{
Id: "Easybridge",
Url: "http://localhost:8321",
AsToken: hex.EncodeToString(rnd[:32]),
HsToken: hex.EncodeToString(rnd[32:]),
SenderLocalpart: "_ezbr_",
RateLimited: false,
Namespaces: mxlib.RegistrationNamespaceSet{
Users: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{
Exclusive: true,
Regex: "@.*_ezbr_",
},
},
Aliases: []mxlib.RegistrationNamespace{
mxlib.RegistrationNamespace{
Exclusive: true,
Regex: "#.*_ezbr_",
},
},
Rooms: []mxlib.RegistrationNamespace{},
},
}
_, err = os.Stat(file)
if os.IsNotExist(err) {
// Generate default config file
log.Printf("Generating default registration file as %s", file)
bytes, err := yaml.Marshal(®)
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile(file, bytes, 0644)
if err != nil {
log.Fatal(err)
}
return reg
}
if err != nil {
log.Fatal(err)
}
bytes, err := ioutil.ReadFile(file)
if err != nil {
log.Fatal(err)
}
err = yaml.Unmarshal(bytes, ®)
if err != nil {
log.Fatal(err)
}
return reg
}
func main() {
flag.Parse()
// Read configuration
config_file := readConfig()
config = &config_file
log_level, err := log.ParseLevel(config.LogLevel)
if err != nil {
log.Fatal(err)
}
log.SetLevel(log_level)
reg_file := readRegistration(config.Registration)
registration = ®_file
// Create context and handlers for errors and signals
ctx, stop_all := context.WithCancel(context.Background())
errch := make(chan error)
sigch := make(chan os.Signal)
signal.Notify(sigch, os.Interrupt, syscall.SIGTERM)
defer func() {
signal.Stop(sigch)
stop_all()
}()
// Start appservice and web server
_, err = StartAppService(errch, ctx)
if err != nil {
log.Fatal(err)
}
_ = StartWeb(errch, ctx)
// Wait for an error somewhere or interrupt signal
select {
case err = <-errch:
log.Error(err)
stop_all()
case sig := <-sigch:
log.Warnf("Got signal: %s", sig.String())
stop_all()
case <-ctx.Done():
}
log.Info("Closing all account connections...")
CloseAllAccountsForShutdown()
log.Info("Exiting.")
}