Feature: Support multiline irc parsing (#39)

* feat: initial multiline support

* refactor: handle multiple indexers per network

* wip: setup indexer

* build: add docker compose for testing

* chore: remove temp mock indexers

* chore: update deps

* refactor: update and store network handler

* build: update test compose

* chore: minor cleanup
This commit is contained in:
Ludvig Lundgren 2021-12-21 21:15:42 +01:00 committed by GitHub
parent 506cef6f0f
commit c4d580eb03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1100 additions and 1042 deletions

View file

@ -4,6 +4,8 @@ import (
"context"
"database/sql"
sq "github.com/Masterminds/squirrel"
"github.com/autobrr/autobrr/internal/domain"
"github.com/rs/zerolog/log"
@ -74,6 +76,39 @@ func (ir *IrcRepo) DeleteNetwork(ctx context.Context, id int64) error {
return nil
}
func (ir *IrcRepo) FindActiveNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
rows, err := ir.db.QueryContext(ctx, "SELECT id, enabled, name, server, port, tls, pass, invite_command, nickserv_account, nickserv_password FROM irc_network WHERE enabled = true")
if err != nil {
log.Fatal().Err(err)
}
defer rows.Close()
var networks []domain.IrcNetwork
for rows.Next() {
var net domain.IrcNetwork
var pass, inviteCmd sql.NullString
var tls sql.NullBool
if err := rows.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &net.NickServ.Account, &net.NickServ.Password); err != nil {
log.Fatal().Err(err)
}
net.TLS = tls.Bool
net.Pass = pass.String
net.InviteCommand = inviteCmd.String
networks = append(networks, net)
}
if err := rows.Err(); err != nil {
return nil, err
}
return networks, nil
}
func (ir *IrcRepo) ListNetworks(ctx context.Context) ([]domain.IrcNetwork, error) {
rows, err := ir.db.QueryContext(ctx, "SELECT id, enabled, name, server, port, tls, pass, invite_command, nickserv_account, nickserv_password FROM irc_network")
@ -132,6 +167,45 @@ func (ir *IrcRepo) ListChannels(networkID int64) ([]domain.IrcChannel, error) {
return channels, nil
}
func (ir *IrcRepo) CheckExistingNetwork(ctx context.Context, network *domain.IrcNetwork) (*domain.IrcNetwork, error) {
queryBuilder := sq.
Select("id", "enabled", "name", "server", "port", "tls", "pass", "invite_command", "nickserv_account", "nickserv_password").
From("irc_network").
Where("server = ?", network.Server).
Where("nickserv_account = ?", network.NickServ.Account)
query, args, err := queryBuilder.ToSql()
if err != nil {
log.Error().Stack().Err(err).Msg("irc.check_existing_network: error fetching data")
return nil, err
}
log.Trace().Str("database", "irc.check_existing_network").Msgf("query: '%v', args: '%v'", query, args)
row := ir.db.QueryRowContext(ctx, query, args...)
var net domain.IrcNetwork
var pass, inviteCmd, nickPass sql.NullString
var tls sql.NullBool
err = row.Scan(&net.ID, &net.Enabled, &net.Name, &net.Server, &net.Port, &tls, &pass, &inviteCmd, &net.NickServ.Account, &nickPass)
if err == sql.ErrNoRows {
// no result is not an error in our case
return nil, nil
} else if err != nil {
log.Error().Stack().Err(err).Msg("irc.check_existing_network: error scanning data to struct")
return nil, err
}
net.TLS = tls.Bool
net.Pass = pass.String
net.InviteCommand = inviteCmd.String
net.NickServ.Password = nickPass.String
return &net, nil
}
func (ir *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
netName := toNullString(network.Name)
@ -167,6 +241,10 @@ func (ir *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
nsPassword,
network.ID,
)
if err != nil {
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
return err
}
} else {
var res sql.Result
@ -180,7 +258,7 @@ func (ir *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
invite_command,
nickserv_account,
nickserv_password
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT DO NOTHING`,
network.Enabled,
netName,
network.Server,
@ -192,7 +270,7 @@ func (ir *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
nsPassword,
)
if err != nil {
log.Error().Stack().Err(err).Msg("error executing query")
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
return err
}
@ -202,6 +280,100 @@ func (ir *IrcRepo) StoreNetwork(network *domain.IrcNetwork) error {
return err
}
func (ir *IrcRepo) UpdateNetwork(ctx context.Context, network *domain.IrcNetwork) error {
netName := toNullString(network.Name)
pass := toNullString(network.Pass)
inviteCmd := toNullString(network.InviteCommand)
nsAccount := toNullString(network.NickServ.Account)
nsPassword := toNullString(network.NickServ.Password)
var err error
// update record
_, err = ir.db.ExecContext(ctx, `UPDATE irc_network
SET enabled = ?,
name = ?,
server = ?,
port = ?,
tls = ?,
pass = ?,
invite_command = ?,
nickserv_account = ?,
nickserv_password = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?`,
network.Enabled,
netName,
network.Server,
network.Port,
network.TLS,
pass,
inviteCmd,
nsAccount,
nsPassword,
network.ID,
)
if err != nil {
log.Error().Stack().Err(err).Msg("irc.store_network: error executing query")
return err
}
return err
}
// TODO create new channel handler to only add, not delete
func (ir *IrcRepo) StoreNetworkChannels(ctx context.Context, networkID int64, channels []domain.IrcChannel) error {
tx, err := ir.db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
_, err = tx.ExecContext(ctx, `DELETE FROM irc_channel WHERE network_id = ?`, networkID)
if err != nil {
log.Error().Stack().Err(err).Msgf("error deleting channels for network: %v", networkID)
return err
}
for _, channel := range channels {
var res sql.Result
pass := toNullString(channel.Password)
res, err = tx.ExecContext(ctx, `INSERT INTO irc_channel (
enabled,
detached,
name,
password,
network_id
) VALUES (?, ?, ?, ?, ?)`,
channel.Enabled,
true,
channel.Name,
pass,
networkID,
)
if err != nil {
log.Error().Stack().Err(err).Msg("error executing query")
return err
}
channel.ID, err = res.LastInsertId()
}
err = tx.Commit()
if err != nil {
log.Error().Stack().Err(err).Msgf("error deleting network: %v", networkID)
return err
}
return nil
}
func (ir *IrcRepo) StoreChannel(networkID int64, channel *domain.IrcChannel) error {
pass := toNullString(channel.Password)
@ -231,7 +403,7 @@ func (ir *IrcRepo) StoreChannel(networkID int64, channel *domain.IrcChannel) err
name,
password,
network_id
) VALUES (?, ?, ?, ?, ?)`,
) VALUES (?, ?, ?, ?, ?) ON CONFLICT DO NOTHING`,
channel.Enabled,
true,
channel.Name,