From d928a681f9c1caf2a9e49b45dd1a586a903b6f62 Mon Sep 17 00:00:00 2001 From: marko Date: Thu, 3 Oct 2024 15:52:06 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + chatbot/chatbot.go | 114 ++++++++++++++++++++++++++++++++++++++++ chatbot/chatbot_test.go | 96 +++++++++++++++++++++++++++++++++ config.ini.example | 6 +++ go.mod | 13 +++++ go.sum | 16 ++++++ main.go | 14 +++++ ping/ping.go | 68 ++++++++++++++++++++++++ 8 files changed, 328 insertions(+) create mode 100644 chatbot/chatbot.go create mode 100644 chatbot/chatbot_test.go create mode 100644 config.ini.example create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 ping/ping.go diff --git a/.gitignore b/.gitignore index adf8f72..2bb745e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Go workspace file go.work +config.ini diff --git a/chatbot/chatbot.go b/chatbot/chatbot.go new file mode 100644 index 0000000..1872d9b --- /dev/null +++ b/chatbot/chatbot.go @@ -0,0 +1,114 @@ +package chatbot + +import ( + "fmt" + "log" + "regexp" + "strings" + "time" + + "github.com/xmppo/go-xmpp" + "gopkg.in/ini.v1" + + "gitea.dmz.rs/bauljamic123arlijam/neko-u-krovu-bot/ping" +) + +type NekoUKrovuBot struct { + cl *xmpp.Client + host string + user string + mcuJid string + nick string +} + +func NewNekoUKrovuBot() (*NekoUKrovuBot, error) { + cfg, err := ini.Load("config.ini") + if err != nil { + log.Fatalf("Failed to load INI file: %v", err) + } + + host := cfg.Section("credentials").Key("HOST").String() + user := cfg.Section("credentials").Key("JID").String() + passwd := cfg.Section("credentials").Key("PASSWORD").String() + mcuJid := cfg.Section("credentials").Key("ROOM").String() + nick := cfg.Section("credentials").Key("NICK").String() + + cl, err := xmpp.NewClientNoTLS(host, user, passwd, false) + if err != nil { + return &NekoUKrovuBot{}, err + } + + n, err := cl.JoinMUCNoHistory(mcuJid, nick) + if err != nil { + return &NekoUKrovuBot{}, err + } + + _ = n + + return &NekoUKrovuBot{cl: cl, + host: host, + user: user, + mcuJid: mcuJid, + nick: nick}, nil +} + +func (nkbot *NekoUKrovuBot) Listen() { + for { + msg, err := nkbot.cl.Recv() + + if err != nil { + log.Print(err) + continue + } + + switch m := msg.(type) { + case xmpp.Chat: + nkbot.handleChat(&m) + default: + continue + } + } +} + +func (nkbot *NekoUKrovuBot) handleChat(ch *xmpp.Chat) { + src := ch.Remote + txt := ch.Text + + if src == "sdsads" { + return + } + + if nkbot.checkForJelNekoUKrovu(txt) { + n := ping.Run() + nkbot.answer(fmt.Sprintf("%v uredjaja povezano", n)) + } +} + +func (nkbot *NekoUKrovuBot) checkForJelNekoUKrovu(txt string) bool { + normalizedText := strings.ToLower(txt) + + pattern := `(?i)^(?:\S+\s+){2,}\b(jel|el|ima li|ima|neko|koga|nekoga|je l)?\s*(neko|koga|nekoga)?\s*(u)?\s*(krovu|krov|vkro)\b` + matched, err := regexp.MatchString(pattern, normalizedText) + if err != nil { + fmt.Println("Error compiling regex:", err) + return false + } + + return matched +} + +func (nkbot *NekoUKrovuBot) answer(ans string) { + chat := xmpp.Chat{ + Remote: "chatbottest@conference.dmz.rs", + Type: "groupchat", + Text: ans, + Stamp: time.Now(), + } + + n, err := nkbot.cl.Send(chat) + if err != nil { + log.Print(err) + } + + _ = n +} diff --git a/chatbot/chatbot_test.go b/chatbot/chatbot_test.go new file mode 100644 index 0000000..28f12b7 --- /dev/null +++ b/chatbot/chatbot_test.go @@ -0,0 +1,96 @@ +package chatbot + +import ( + "testing" +) + +func TestNekoUKrovuBot_checkForJelNekoUKrovu(t *testing.T) { + type args struct { + txt string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "matches 'jel neko u krovu'", + args: args{ + txt: "jel neko u krovu", + }, + want: true, + }, + { + name: "matches 'ima li koga na krovu'", + args: args{ + txt: "ima li koga na krovu", + }, + want: true, + }, + { + name: "does not match 'nema nikoga'", + args: args{ + txt: "nema nikoga", + }, + want: false, + }, + { + name: "matches 'koga ima na krovu'", + args: args{ + txt: "koga ima na krovu", + }, + want: true, + }, + { + name: "matches 'neko u krov'", + args: args{ + txt: "neko u krov", + }, + want: true, + }, + { + name: "case insensitive match 'EL NEKO krov'", + args: args{ + txt: "EL NEKO krov", + }, + want: true, + }, + { + name: "case insensitive match 'jel neko jebeno u krovu'", + args: args{ + txt: "jel neko jebeno u krovu", + }, + want: true, + }, + { + name: "case insensitive match 'buraz jel neko jebeno u krovu'", + args: args{ + txt: "buraz jel neko jebeno u krovu", + }, + want: true, + }, + { + name: "case insensitive match 'neko u krovu?'", + args: args{ + txt: "neko u krovu?", + }, + want: true, + }, + { + name: "case insensitive match 'u krovu?'", + args: args{ + txt: "u krovu?", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + nkbot := &NekoUKrovuBot{ + } + if got := nkbot.checkForJelNekoUKrovu(tt.args.txt); got != tt.want { + t.Errorf("NekoUKrovuBot.checkForJelNekoUKrovu() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/config.ini.example b/config.ini.example new file mode 100644 index 0000000..0b5e4c2 --- /dev/null +++ b/config.ini.example @@ -0,0 +1,6 @@ +[credentials] +JID = botusername@example.org +PASSWORD = bot_password +NICK = chatbot +ROOM = room_jid@example.org +HOST = example.org \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a4eac71 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module gitea.dmz.rs/bauljamic123arlijam/neko-u-krovu-bot + +go 1.23.1 + +require github.com/xmppo/go-xmpp v0.2.1 + +require github.com/stretchr/testify v1.9.0 // indirect + +require ( + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/net v0.25.0 // indirect + gopkg.in/ini.v1 v1.67.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1b5befa --- /dev/null +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xmppo/go-xmpp v0.2.1 h1:8Bw6W6RNGTq6ajgMiKxn0iJKYt6Atef5Y0A5AkGWn9Q= +github.com/xmppo/go-xmpp v0.2.1/go.mod h1:H46WSy/5uHW1SWsyJYI6fRZqFrK326qWmFRpVJ2Wwhs= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..bb31b7c --- /dev/null +++ b/main.go @@ -0,0 +1,14 @@ +package main + +import ( + "log" + "gitea.dmz.rs/bauljamic123arlijam/neko-u-krovu-bot/chatbot" +) + +func main() { + nkbot, err := chatbot.NewNekoUKrovuBot() + if err != nil { + log.Fatal(err) + } + nkbot.Listen() +} diff --git a/ping/ping.go b/ping/ping.go new file mode 100644 index 0000000..5df9879 --- /dev/null +++ b/ping/ping.go @@ -0,0 +1,68 @@ +package ping + +import ( + "fmt" + "net" + "os/exec" + "sync" +) + +func Run() int { + localIP, err := getLocalIP() + if err != nil { + fmt.Println("Error getting local IP:", err) + return 0 + } + + network := getNetworkPrefix(localIP) + + var wg sync.WaitGroup + deviceCount := 0 + mu := &sync.Mutex{} + + for i := 1; i < 255; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + addr := fmt.Sprintf("%s.%d", network[:len(network)-2], i) + + if ping(addr) { + mu.Lock() + deviceCount++ + mu.Unlock() + } + }(i) + } + + wg.Wait() + return deviceCount +} + +func getLocalIP() (net.IP, error) { + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil, err + } + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.IsGlobalUnicast() { + return ipnet.IP, nil + } + } + return nil, fmt.Errorf("local IP not found") +} + +func getNetworkPrefix(ip net.IP) string { + ip = ip.To4() + return fmt.Sprintf("%d.%d.%d.0", ip[0], ip[1], ip[2]) +} + + +func ping(ip string) bool { + output, err := exec.Command("ping", "-c", "1", "-W", "1", ip).CombinedOutput() + + if err != nil { + return false + } + _ = output + return true +} \ No newline at end of file