Update linter, fix linter errors

This commit is contained in:
eleksir
2025-11-15 15:52:34 +03:00
parent 3ebd2b48d1
commit ee5d40cfee
21 changed files with 1106 additions and 737 deletions

View File

@@ -5,6 +5,7 @@ import (
"encoding/xml"
"fmt"
"runtime"
"slices"
"sort"
"strings"
"time"
@@ -12,26 +13,24 @@ import (
"github.com/davecgh/go-spew/spew"
"github.com/eleksir/go-xmpp"
log "github.com/sirupsen/logrus"
"golang.org/x/exp/slices"
)
// ParseEvent парсит ивенты, прилетающие из модуля xmpp (изменения presence, фразы участников, ошибки).
func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
func (j *Jabber) ParseEvent(e any) { //nolint:maintidx,gocognit,gocyclo
j.LastServerActivity = time.Now().Unix()
switch v := e.(type) {
// Сообщение в чяти
// Сообщение в чяти.
case xmpp.Chat:
log.Debugf("Looks like message, ChatType: %s, From: %s, Subject: %s Text: %s",
v.Type, v.Remote, v.Subject, v.Text)
// Топик чятика присылается в виде сообщения с subject, но без text
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text
// Топик чятика присылается в виде сообщения с subject, но без text.
// В то же время сообщения от людей приходят с пустым subject, но с заполненным text.
if v.Text != "" {
// Чятики бывают групповые и не групповые, от этого зависит Remote, куда направлять сообщение
// Чятики бывают групповые и не групповые, от этого зависит Remote, куда направлять сообщение.
switch v.Type { //nolint:wsl,whitespace
// Групповой чятик
// Групповой чятик.
case "groupchat":
var (
room = strings.SplitN(v.Remote, "/", 2)[0]
@@ -64,7 +63,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
j.LastMucActivity.Set(muc, j.LastServerActivity)
}
// Приватный чятик
// Приватный чятик.
case "chat":
// Здесь у нас может быть 2 вида From:
// slackware-current@conference.jabber.ru/eleksir - это если сообщение из публичного чятика
@@ -80,7 +79,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
j.LastActivity = j.LastServerActivity
// Внезапно, ошибки. По идее они должны ассоциироваться с отправляемыми сообщениями, но по ходу это
// не реализовано, поэтому мы получаем ошибки в форме отдельного чятика
// не реализовано, поэтому мы получаем ошибки в форме отдельного чятика.
case "error":
// Это ошибка со стороны сервера, видимо, в ответ на наши действия и поскольку такие вещи происходят
// асинхронно, связать их с конкретными нашими действиями довольно сложно.
@@ -90,7 +89,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// IQ-сообщение - пинг, понг, что-то ещё...
case xmpp.IQ:
// По правилам IQ обязательно должна содержать ID, причём не пустой
// По правилам IQ обязательно должна содержать ID, причём не пустой.
if v.ID == "" {
log.Info("Got an IQ stanza with empty id, discarding")
@@ -114,8 +113,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
switch iqStruct.Xmlns { //nolint:wsl,whitespace
// Запрос номера версии приложения
// Запрос номера версии приложения.
case "jabber:iq:version":
log.Infof("Got IQ get request for version from %s", v.From)
@@ -138,7 +136,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
// Нам прислали попингуй
// Нам прислали попингуй.
case "urn:xmpp:ping":
log.Infof("Got IQ get request for pong from %s", v.From)
@@ -175,11 +173,12 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
// Запрос на список поддерживаемых фич - версия, локальное время, итд
// Запрос на список поддерживаемых фич - версия, локальное время, итд.
case xmpp.XMPPNS_DISCO_INFO:
log.Infof("Got IQ get disco#info request from %s", v.From)
answer := "<query xmlns=\"http://jabber.org/protocol/disco#info\">"
answer += "<feature var=\"jabber:iq:version\" />"
answer += "<feature var=\"urn:xmpp:time\" />"
answer += "<feature var=\"urn:xmpp:ping\" />"
@@ -209,7 +208,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
// Спрашивают список команд, чтобы поуправлять этим клиентом (xep-0030)
// Спрашивают список команд, чтобы поуправлять этим клиентом (xep-0030).
case xmpp.XMPPNS_DISCO_ITEMS:
log.Infof("Got IQ get disco#items request from %s, answer service unavailable", v.From)
@@ -231,7 +230,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
// Запрашивают что-то, о чём мы не имеем представления
// Запрашивают что-то, о чём мы не имеем представления.
default:
log.Info("Got an unknown IQ get request, discarding")
log.Info(spew.Sdump(e))
@@ -242,7 +241,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = true
}
// Попробуем распарсить входящий запрос как urn:xmpp:time
// Попробуем распарсить входящий запрос как urn:xmpp:time.
if parseError {
var iqStruct TimeIqGetQuery
@@ -276,7 +275,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Попробуем распарсить входящий запрос как http://jabber.org/protocol/pubsub
// Попробуем распарсить входящий запрос как http://jabber.org/protocol/pubsub.
if parseError {
var iqStruct PubsubIQGetQuery
@@ -305,6 +304,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
default:
log.Info("Got unknown IQ get pubsub something request, discarding")
log.Info(spew.Sdump(e))
parseError = true //nolint:wsl
}
} else {
@@ -312,7 +312,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Попробуем распарсить входящий запрос как urn:xmpp:ping он приходит при MUC Self-Ping (Schrödinger's Chat)
// Попробуем распарсить входящий запрос как urn:xmpp:ping он приходит при MUC Self-Ping (Schrödinger's Chat).
// Предполагается, что такие респонсы должны приходить только для пинга без серверной оптимизации.
// Хотя идейно мы не поддерживаем работу без серверной оптимизации, но на пинг ответим, нам несложно.
if parseError {
@@ -337,7 +337,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
}
// Не знаю, как парсить... залоггируем это дело и пойдём дальше
// Не знаю, как парсить... залоггируем это дело и пойдём дальше.
if parseError {
log.Infof("Does not look like parsable via iqStruct")
log.Info(spew.Sdump(e))
@@ -351,9 +351,10 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
switch {
// Похоже на pong от сервера (по стандарту в ответе нету query, но go-xmpp нам подсовывает это)
// Похоже на pong от сервера (по стандарту в ответе нету query, но go-xmpp нам подсовывает это).
case v.From == j.C.Jabber.Server && v.To == j.Talk.JID() && string(v.Query) == "<XMLElement></XMLElement>":
log.Debugf("Got S2C pong answer from %s to %s", v.From, v.To)
j.ServerPingTimestampRx = time.Now().Unix() //nolint:wsl
// Похоже на понг второй стадии xep-0410 MUC-Ping-а, который у нас не реализован.
@@ -378,13 +379,13 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
if mucNickMatch {
log.Debugf("Got 2-nd stage MUC pong answer (xep-0410) from %s to %s", v.From, v.To)
} else {
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ.
log.Infof("Got unknown pong from %s to %s", v.From, v.To)
log.Debug(spew.Sdump(e))
}
}
// Подтверждение бана
// Подтверждение бана.
case v.To == j.Talk.JID() && v.ID == "ban1":
mucNickMatch := false
@@ -402,15 +403,15 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Формально, ответ должен парситься как пустой result и совпадать с типом jabberSimpleIqGetQuery
// Формально, ответ должен парситься как пустой result и совпадать с типом jabberSimpleIqGetQuery.
// Ответ приходит с 2 xmlns, похоже, он парсится неправильно в go-xmpp.
// TODO: после исправления go-xmpp, надо исправить это тут
// TODO: после исправления go-xmpp, надо исправить это тут.
var iqStruct SimpleIqGetQuery
if err := xml.Unmarshal(v.Query, &iqStruct); err == nil {
if iqStruct.Xmlns == "http://jabber.org/protocol/muc#admin" && iqStruct.Text == "" {
if mucNickMatch {
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ
// Поскольку никакой логики у нас на этот счёт не предусмотрено, то просто пропускаем ответ.
log.Infof("Got ban successful from %s to %s", v.From, v.To)
} else {
log.Infof("Got ban successful from %s to %s, from room we are not in", v.From, v.To)
@@ -465,7 +466,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Debug(spew.Sdump(e))
}
// Этот бот не управляется со стороны сервера, поэтому все попытки порулить игнорируем
// Этот бот не управляется со стороны сервера, поэтому все попытки порулить игнорируем.
case xmpp.IQTypeSet:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
if slices.Contains(j.RoomsConnected, muc) {
@@ -493,7 +494,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Debug(spew.Sdump(e))
// Нам прилетело сообщение об ошибке
// Нам прилетело сообщение об ошибке.
case xmpp.IQTypeError:
// Если сервер не хочет пинговаться и отвечает ошибкой на пинг, то наверно он не умеет в пинги,
// хотя если мы его пингуем, значит он анонсировал такой capability. Вот, засранец!
@@ -506,6 +507,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
if iqPingStruct.Xmlns == "urn:xmpp:ping" {
if v.From == j.C.Jabber.Server {
msg := "Server announced that it can answer c2s ping, but gives us an error to such query, "
msg += "fallback to keepalive whitespace pings"
log.Error(msg)
@@ -521,7 +523,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
parseError = false
}
// Это у нас пинг xep-0410 и мы не в комнате, предполагается, что надо бы заджойниться
// Это у нас пинг xep-0410 и мы не в комнате, предполагается, что надо бы заджойниться.
if parseError {
var iqErrorCancelNotAcceptable IqErrorCancelNotAcceptable
@@ -572,13 +574,13 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
log.Error("Unhandled IQ Error message")
log.Error(spew.Sdump(e))
}
// Нам прилетело что-то неизвестное из семейства IQ stanza
// Нам прилетело что-то неизвестное из семейства IQ stanza.
default:
log.Info("Got an unknown IQ request. Dunno how deal with it, discarding")
log.Info(spew.Sdump(e))
}
// Смена статуса участника
// Смена статуса участника.
case xmpp.Presence:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
if slices.Contains(j.RoomsConnected, muc) {
@@ -593,13 +595,21 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
// клиента забанят из-за спама "вошёл-вышел".
// Однако, это не значит, что такую ситуацию мы не должны корректным образом обрабатывать.
if v.Type == "unavailable" {
// Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть
// Считаем, что мы больше не в комнате, поэтому не знаем, кто там есть.
j.RoomPresences.Delete(v.From)
log.Error("Presence notification - looks like another instance of client leaves room")
if slices.Contains(j.RoomsConnected, v.From) {
go j.JoinMuc(v.From)
j.GTomb.Go(
func() error {
if err := j.JoinMuc(v.From); err != nil {
return fmt.Errorf("unable to join MUC %s: %w", v.From, err)
}
return nil
},
)
}
} else {
log.Errorf("Presence notification, Type: %s, From: %s, Show: %s, Status: %s",
@@ -621,18 +631,19 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
return
}
// Это наш собственный Presence
// Это наш собственный Presence.
if v.Show == "" && v.Status == "" {
if nick == j.GetBotNickFromRoomConfig(room) {
j.RoomsConnected = append(j.RoomsConnected, room)
// На всякий случай дедуплицируем список комнат, к которым мы заджойнились.
sort.Strings(j.RoomsConnected)
slices.Compact(j.RoomsConnected)
j.RoomsConnected = slices.Compact(j.RoomsConnected)
}
}
switch v.Role {
// Участник ушёл
// Участник ушёл.
case "none":
if presenceJSONInterface, present := j.RoomPresences.Get(room); present {
presenceJSONStrings := InterfaceToStringSlice(presenceJSONInterface)
@@ -641,6 +652,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
for _, presenceJSONstring := range presenceJSONStrings {
var p xmpp.Presence
_ = json.Unmarshal([]byte(presenceJSONstring), &p)
if p.From == v.From {
@@ -652,7 +664,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
j.RoomPresences.Set(room, newPresenceJSONStrings)
}
// Участник пришёл
// Участник пришёл.
default:
var (
presenceJSONStrings []string
@@ -666,6 +678,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
for _, presenceJSONString := range presenceJSONStrings {
var p xmpp.Presence
_ = json.Unmarshal([]byte(presenceJSONString), &p)
// Если находим, что у нас уже есть клиент с таким же From, то есть полным nick-ом (для groupchat)
@@ -696,7 +709,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Ответ на запрос поддерживаемых фич, который "http://jabber.org/protocol/disco#info"
// Ответ на запрос поддерживаемых фич, который "http://jabber.org/protocol/disco#info".
case xmpp.DiscoResult:
if muc, _ := strings.CutSuffix(v.To, "/"); muc != "" {
if slices.Contains(j.RoomsConnected, muc) {
@@ -704,12 +717,12 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Я видел 2 типа disco result и они отличались только []identities. Попробуем вытащить известный identity
// TODO: проверять адресата v.To
// Я видел 2 типа disco result и они отличались только []identities. Попробуем вытащить известный identity.
// TODO: проверять адресата v.To.
for _, ident := range v.Identities {
switch ident.Category {
case "server":
// Конкретно сейчас нас интересует только поддержка c2s ping
// Конкретно сейчас нас интересует только поддержка c2s ping.
for _, feature := range v.Features {
log.Debugf("Server %s announced that it supports feature: %s", v.From, feature)
j.ServerCapsList.Set(feature, true)
@@ -722,6 +735,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
for _, feature := range v.Features {
log.Debugf("MUC %s announced that it supports feature: %s", v.From, feature)
mucCaps[feature] = true //nolint:wsl
}
@@ -736,7 +750,7 @@ func (j *Jabber) ParseEvent(e interface{}) { //nolint:maintidx,gocognit,gocyclo
}
}
// Это что-то неизвестное, подампим событие в лог
// Это что-то неизвестное, подампим событие в лог.
default:
log.Info(spew.Sdump(e))
}