Improve exiting (actually it was Mattermost that was creating a deadlock)
This commit is contained in:
parent
df1f2d38b3
commit
d4d3cc422b
7 changed files with 49 additions and 42 deletions
14
account.go
14
account.go
|
@ -44,11 +44,13 @@ func SetAccount(mxid string, name string, protocol string, config map[string]str
|
||||||
return fmt.Errorf("Wrong protocol")
|
return fmt.Errorf("Wrong protocol")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(config, prev_acct.Config) {
|
if !reflect.DeepEqual(config, prev_acct.Config) {
|
||||||
prev_acct.Conn.Close()
|
go func() {
|
||||||
prev_acct.JoinedRooms = map[RoomID]bool{}
|
prev_acct.Conn.Close()
|
||||||
|
prev_acct.JoinedRooms = map[RoomID]bool{}
|
||||||
|
|
||||||
prev_acct.Config = config
|
prev_acct.Config = config
|
||||||
go prev_acct.connect()
|
prev_acct.connect()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
proto, ok := Protocols[protocol]
|
proto, ok := Protocols[protocol]
|
||||||
|
@ -128,11 +130,13 @@ func RemoveAccount(mxUser string, name string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CloseAllAcountsForShutdown() {
|
func CloseAllAccountsForShutdown() {
|
||||||
accountsLock.Lock()
|
accountsLock.Lock()
|
||||||
defer accountsLock.Unlock()
|
defer accountsLock.Unlock()
|
||||||
|
|
||||||
for _, accl := range registeredAccounts {
|
for _, accl := range registeredAccounts {
|
||||||
for _, acct := range accl {
|
for _, acct := range accl {
|
||||||
|
log.Printf("Closing %#v", acct)
|
||||||
acct.Conn.Close()
|
acct.Conn.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
connector/external/external.go
vendored
16
connector/external/external.go
vendored
|
@ -177,6 +177,7 @@ func (ext *External) restartLoop(generation int) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
log.Printf("Process %s stopped, restarting.", ext.command)
|
log.Printf("Process %s stopped, restarting.", ext.command)
|
||||||
|
log.Printf("Generation %d vs %d", ext.generation, generation)
|
||||||
err := ext.setupProc(generation)
|
err := ext.setupProc(generation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ext.proc = nil
|
ext.proc = nil
|
||||||
|
@ -326,22 +327,23 @@ func (ext *External) Close() {
|
||||||
ext.sendJson.Encode(&extMessage{
|
ext.sendJson.Encode(&extMessage{
|
||||||
MsgType: CLOSE,
|
MsgType: CLOSE,
|
||||||
})
|
})
|
||||||
|
ext.proc.Process.Signal(os.Interrupt)
|
||||||
|
|
||||||
proc := ext.proc
|
|
||||||
proc.Process.Signal(os.Interrupt)
|
|
||||||
ext.recvPipe.Close()
|
ext.recvPipe.Close()
|
||||||
ext.sendPipe.Close()
|
ext.sendPipe.Close()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
log.Info("Sending SIGKILL to external process (did not terminate within 1 second)")
|
||||||
|
ext.proc.Process.Kill()
|
||||||
|
}()
|
||||||
|
ext.proc.Wait()
|
||||||
|
|
||||||
ext.proc = nil
|
ext.proc = nil
|
||||||
ext.recvPipe = nil
|
ext.recvPipe = nil
|
||||||
ext.sendPipe = nil
|
ext.sendPipe = nil
|
||||||
ext.sendJson = nil
|
ext.sendJson = nil
|
||||||
ext.handlerChan = nil
|
ext.handlerChan = nil
|
||||||
|
|
||||||
go func() {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
proc.Process.Kill()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Actual message handling :)
|
// ---- Actual message handling :)
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (mm *Mattermost) Configure(c Configuration) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinitialize shared data structures
|
// Reinitialize shared data structures
|
||||||
mm.handlerStopChan = make(chan bool)
|
mm.handlerStopChan = make(chan bool, 1)
|
||||||
|
|
||||||
mm.caches.mmusers = make(map[string]string)
|
mm.caches.mmusers = make(map[string]string)
|
||||||
mm.caches.sentjoined = make(map[string]bool)
|
mm.caches.sentjoined = make(map[string]bool)
|
||||||
|
|
2
external/messenger.py
vendored
2
external/messenger.py
vendored
|
@ -225,7 +225,7 @@ class MessengerBridge:
|
||||||
self.client = MessengerBridgeClient(email=email, password=password, max_tries=1)
|
self.client = MessengerBridgeClient(email=email, password=password, max_tries=1)
|
||||||
|
|
||||||
if not self.client.isLoggedIn():
|
if not self.client.isLoggedIn():
|
||||||
return {"_type": "ret_error", "error": "Unable to login (?)"}
|
return {"_type": "rep_error", "error": "Unable to login (?)"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
f = open(client_file, "wb")
|
f = open(client_file, "wb")
|
||||||
|
|
43
main.go
43
main.go
|
@ -10,7 +10,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
@ -176,44 +175,36 @@ func main() {
|
||||||
reg_file := readRegistration(config.Registration)
|
reg_file := readRegistration(config.Registration)
|
||||||
registration = ®_file
|
registration = ®_file
|
||||||
|
|
||||||
// Start appservice and web management interface
|
// Create context and handlers for errors and signals
|
||||||
|
ctx, stop_all := context.WithCancel(context.Background())
|
||||||
errch := make(chan error)
|
errch := make(chan error)
|
||||||
sigch := make(chan os.Signal)
|
sigch := make(chan os.Signal)
|
||||||
signal.Notify(sigch, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigch, os.Interrupt, syscall.SIGTERM)
|
||||||
|
defer func() {
|
||||||
|
signal.Stop(sigch)
|
||||||
|
stop_all()
|
||||||
|
}()
|
||||||
|
|
||||||
as_server, err := StartAppService(errch)
|
// Start appservice and web server
|
||||||
|
_, err = StartAppService(errch, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
web_server := StartWeb(errch)
|
_ = StartWeb(errch, ctx)
|
||||||
|
|
||||||
// Wait for an error somewhere or interrupt signal
|
// Wait for an error somewhere or interrupt signal
|
||||||
select {
|
select {
|
||||||
case err = <-errch:
|
case err = <-errch:
|
||||||
if err != nil {
|
log.Error(err)
|
||||||
log.Error(err)
|
stop_all()
|
||||||
}
|
|
||||||
case sig := <-sigch:
|
case sig := <-sigch:
|
||||||
log.Warnf("Got signal %s", sig.String())
|
log.Warnf("Got signal: %s", sig.String())
|
||||||
|
stop_all()
|
||||||
|
case <-ctx.Done():
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shut down, hopefully this is not a too bad way to do it
|
log.Info("Closing all account connections...")
|
||||||
log.Warn("Shuttind down")
|
CloseAllAccountsForShutdown()
|
||||||
delay := 2 * time.Second
|
log.Info("Exiting.")
|
||||||
|
|
||||||
ctx1, _ := context.WithTimeout(context.TODO(), delay)
|
|
||||||
go as_server.Shutdown(ctx1)
|
|
||||||
|
|
||||||
ctx2, _ := context.WithTimeout(context.TODO(), delay)
|
|
||||||
go web_server.Shutdown(ctx2)
|
|
||||||
|
|
||||||
time.Sleep(delay)
|
|
||||||
CloseAllAcountsForShutdown()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
os.Exit(1)
|
|
||||||
} else {
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,7 +18,7 @@ import (
|
||||||
|
|
||||||
var mx *mxlib.Client
|
var mx *mxlib.Client
|
||||||
|
|
||||||
func StartAppService(errch chan error) (*http.Server, error) {
|
func StartAppService(errch chan error, ctx context.Context) (*http.Server, error) {
|
||||||
mx = mxlib.NewClient(config.Server, registration.AsToken)
|
mx = mxlib.NewClient(config.Server, registration.AsToken)
|
||||||
|
|
||||||
err := InitDb()
|
err := InitDb()
|
||||||
|
@ -56,6 +58,9 @@ func StartAppService(errch chan error) (*http.Server, error) {
|
||||||
http_server := &http.Server{
|
http_server := &http.Server{
|
||||||
Addr: config.ASBindAddr,
|
Addr: config.ASBindAddr,
|
||||||
Handler: checkTokenAndLog(router),
|
Handler: checkTokenAndLog(router),
|
||||||
|
BaseContext: func(net.Listener) context.Context {
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
err := http_server.ListenAndServe()
|
err := http_server.ListenAndServe()
|
||||||
|
|
7
web.go
7
web.go
|
@ -1,7 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -21,7 +23,7 @@ const SESSION_NAME = "easybridge_session"
|
||||||
var sessionsStore sessions.Store = nil
|
var sessionsStore sessions.Store = nil
|
||||||
var userKeys = map[string]*[32]byte{}
|
var userKeys = map[string]*[32]byte{}
|
||||||
|
|
||||||
func StartWeb(errch chan error) *http.Server {
|
func StartWeb(errch chan error, ctx context.Context) *http.Server {
|
||||||
session_key := blake2b.Sum256([]byte(config.SessionKey))
|
session_key := blake2b.Sum256([]byte(config.SessionKey))
|
||||||
sessionsStore = sessions.NewCookieStore(session_key[:])
|
sessionsStore = sessions.NewCookieStore(session_key[:])
|
||||||
|
|
||||||
|
@ -39,6 +41,9 @@ func StartWeb(errch chan error) *http.Server {
|
||||||
web_server := &http.Server{
|
web_server := &http.Server{
|
||||||
Addr: config.WebBindAddr,
|
Addr: config.WebBindAddr,
|
||||||
Handler: logRequest(r),
|
Handler: logRequest(r),
|
||||||
|
BaseContext: func(net.Listener) context.Context {
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
err := web_server.ListenAndServe()
|
err := web_server.ListenAndServe()
|
||||||
|
|
Loading…
Reference in a new issue