Move most of the initialization steps from main.go to packages

Because it:
- Declutters main.go
- Makes code reusable
master
Hugo Thunnissen 4 years ago
parent 32eddf7498
commit e392242c79

@ -6,38 +6,30 @@ import (
"github.com/Rhymen/go-whatsapp"
"github.com/hugot/go-deltachat/deltachat"
core "github.com/hugot/whapp-deltachat/whappdc-core"
)
type Database interface {
GetWhappJIDForDCID(DCID uint32) (*string, error)
}
func NewWhappBridge(
wac *whatsapp.Conn,
db Database,
UserChatID uint32,
) *WhappBridge {
func NewWhappBridge(bridgeContext *core.BridgeContext) *WhappBridge {
return &WhappBridge{
wac: wac,
db: db,
UserChatID: UserChatID,
bridgeCtx: bridgeContext,
}
}
type WhappBridge struct {
wac *whatsapp.Conn
db Database
UserChatID uint32
bridgeCtx *core.BridgeContext
}
func (b *WhappBridge) Accepts(c *deltachat.Chat, m *deltachat.Message) bool {
chatID := c.GetID()
chatJID, err := b.db.GetWhappJIDForDCID(chatID)
chatJID, err := b.bridgeCtx.DB.GetWhappJIDForDCID(chatID)
if err != nil {
// The database is failing, time to die :(
log.Fatal(err)
// The database is failing, very much an edge case.
log.Println(err)
b.bridgeCtx.SendLog(err.Error())
return false
}
return chatJID != nil
@ -48,18 +40,18 @@ func (b *WhappBridge) Execute(
chat *deltachat.Chat,
m *deltachat.Message,
) {
JID, err := b.db.GetWhappJIDForDCID(chat.GetID())
JID, err := b.bridgeCtx.DB.GetWhappJIDForDCID(chat.GetID())
if err != nil {
c.SendTextMessage(
b.UserChatID,
log.Println(err)
b.bridgeCtx.SendLog(
fmt.Sprintf(
"Whapp bridge dying: %s",
"Database error in Whapp bridge: %s",
err.Error(),
),
)
log.Fatal(err)
return
}
text := whatsapp.TextMessage{
@ -69,11 +61,10 @@ func (b *WhappBridge) Execute(
Text: m.GetText(),
}
_, err = b.wac.Send(text)
_, err = b.bridgeCtx.WhappConn.Send(text)
if err != nil {
c.SendTextMessage(
b.UserChatID,
b.bridgeCtx.SendLog(
fmt.Sprintf(
"Error sending message to %s. \nMessage contents: %s\nError: %s",
*JID,

@ -6,12 +6,8 @@ import (
"os"
"os/signal"
"syscall"
"time"
"github.com/hugot/go-deltachat/deltabot"
"github.com/hugot/go-deltachat/deltachat"
"github.com/hugot/whapp-deltachat/botcommands"
"github.com/hugot/whapp-deltachat/whappdc"
bridge "github.com/hugot/whapp-deltachat/whappdc-bridge"
core "github.com/hugot/whapp-deltachat/whappdc-core"
)
@ -34,70 +30,14 @@ func main() {
ensureDirectoryOrDie(config.App.DataFolder)
ensureDirectoryOrDie(config.App.DataFolder + "/tmp")
db := core.NewDatabase(config.App.DataFolder + "/app.db")
err = db.Init()
messageTracker := &core.MessageTracker{
DB: db,
}
messageTracker.FlushWithInterval(15 * time.Minute)
defer messageTracker.Flush()
bridge := &bridge.Bridge{}
err = bridge.Init(config)
if err != nil {
log.Fatal(err)
}
bridgeCtx := &core.BridgeContext{
Config: config,
DB: db,
MessageTracker: messageTracker,
}
dcClient, err := core.BootstrapDcClientFromConfig(*config, bridgeCtx)
bridgeCtx.SendLog("Whapp-Deltachat started.")
if err != nil {
log.Fatal(err)
}
// Give dc an opportunity to perform some close-down logic
// and close it's db etc.
defer dcClient.Close()
for i := 0; i < 10; i++ {
err = core.CreateAndLoginWhappConnection(
config.App.DataFolder,
bridgeCtx,
)
if err == nil {
break
}
}
if err != nil {
log.Fatal(err)
}
messageWorker := whappdc.NewMessageWorker()
messageWorker.Start()
bridgeCtx.WhappConn.AddHandler(&whappdc.WhappHandler{
BridgeContext: bridgeCtx,
MessageWorker: messageWorker,
})
bot := &deltabot.Bot{}
bot.AddCommand(&botcommands.Echo{})
bot.AddCommand(botcommands.NewWhappBridge(
bridgeCtx.WhappConn, bridgeCtx.DB, bridgeCtx.DCUserChatID,
))
dcClient.On(deltachat.DC_EVENT_INCOMING_MSG, bot.HandleMessage)
defer bridge.Close()
wait := make(chan os.Signal, 1)
signal.Notify(wait, os.Interrupt, syscall.SIGTERM)

@ -0,0 +1,41 @@
package bridge
import (
"time"
"github.com/hugot/go-deltachat/deltabot"
"github.com/hugot/whapp-deltachat/botcommands"
"github.com/hugot/whapp-deltachat/whappdc"
core "github.com/hugot/whapp-deltachat/whappdc-core"
)
type Bridge struct {
Ctx *core.BridgeContext
}
func (b *Bridge) Init(config *core.Config) error {
messageWorker := whappdc.NewMessageWorker()
ctx := core.NewBridgeContext(config, 15*time.Minute)
err := ctx.Init(
whappdc.NewWhappHandler(ctx, messageWorker),
[]deltabot.Command{
&botcommands.Echo{},
botcommands.NewWhappBridge(ctx),
},
)
if err != nil {
return err
}
messageWorker.Start()
b.Ctx = ctx
return nil
}
func (b *Bridge) Close() error {
return b.Ctx.Close()
}

@ -2,8 +2,10 @@ package core
import (
"log"
"time"
"github.com/Rhymen/go-whatsapp"
"github.com/hugot/go-deltachat/deltabot"
"github.com/hugot/go-deltachat/deltachat"
)
@ -11,12 +13,89 @@ type BridgeContext struct {
Config *Config
WhappConn *whatsapp.Conn
DCContext *deltachat.Context
DCClient *deltachat.Client
DB *Database
MessageTracker *MessageTracker
DCUserID uint32
DCUserChatID uint32
}
func NewBridgeContext(config *Config, msgTrackerFlushInterval time.Duration) *BridgeContext {
db := NewDatabase(config.App.DataFolder + "/app.db")
messageTracker := NewMessageTracker(db, msgTrackerFlushInterval)
return &BridgeContext{
Config: config,
DB: db,
MessageTracker: messageTracker,
}
}
// Do all the initialization stuff like intializing databases & services, configuring
// clients, connecting to remote servers, logging in etc.
func (b *BridgeContext) Init(
whappHandler whatsapp.Handler,
botCommands []deltabot.Command,
) error {
err := b.DB.Init()
if err != nil {
return err
}
dcClient, err := BootstrapDcClientFromConfig(*b.Config, b)
b.SendLog("Whapp-Deltachat started.")
if err != nil {
return err
}
for i := 0; i < 10; i++ {
err = CreateAndLoginWhappConnection(b.Config.App.DataFolder, b)
if err == nil {
break
}
}
if err != nil {
return err
}
b.WhappConn.AddHandler(whappHandler)
bot := &deltabot.Bot{}
for _, command := range botCommands {
bot.AddCommand(command)
}
dcClient.On(deltachat.DC_EVENT_INCOMING_MSG, bot.HandleMessage)
return nil
}
func (b *BridgeContext) Close() error {
_, err := b.WhappConn.Disconnect()
if err != nil {
return err
}
err = b.MessageTracker.Flush()
if err != nil {
return err
}
b.DCClient.Close()
err = b.DB.Close()
return err
}
// Find or create a deltachat verified group chat for a whatsapp JID and return it's ID.
func (b *BridgeContext) GetOrCreateDCIDForJID(JID string) (uint32, error) {
if DCID, _ := b.DB.GetDCIDForWhappJID(JID); DCID != nil {

@ -66,6 +66,10 @@ func (d *Database) Init() error {
return nil
}
func (d *Database) Close() error {
return d.db.Close()
}
func (d *Database) GetDCIDForWhappJID(JID string) (*uint32, error) {
var DCID *uint32

@ -85,6 +85,7 @@ func BootstrapDcClientFromConfig(config Config, ctx *BridgeContext) (*deltachat.
ctx.DCUserID = dcUserID
ctx.DCUserChatID = userChatID
ctx.DCContext = DCCtx
ctx.DCClient = dcClient
return dcClient, err
}

@ -6,6 +6,16 @@ import (
"time"
)
func NewMessageTracker(DB *Database, flushInterval time.Duration) *MessageTracker {
tracker := &MessageTracker{
DB: DB,
}
tracker.FlushWithInterval(flushInterval)
return tracker
}
// MessageTracker will keep track of encountered whatsapp messages to prevent sending them
// twice. It's storage is buffered to prevent continuous locks on the database. This means
// that calling WasSent immediately after calling MarkSent will most likely not return an

@ -13,6 +13,13 @@ type WhappHandler struct {
MessageWorker *MessageWorker
}
func NewWhappHandler(bridgeCtx *core.BridgeContext, messageWorker *MessageWorker) *WhappHandler {
return &WhappHandler{
BridgeContext: bridgeCtx,
MessageWorker: messageWorker,
}
}
func (h *WhappHandler) HandleError(err error) {
// If connection to the whapp servers failed for some reason, just retry.
if _, connectionFailed := err.(*whatsapp.ErrConnectionFailed); connectionFailed {

Loading…
Cancel
Save