init
This commit is contained in:
commit
40ef257672
16 changed files with 552 additions and 0 deletions
8
.ci/check-gofmt
Executable file
8
.ci/check-gofmt
Executable file
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
result="$(gofmt -s -l . | grep -v '^vendor/' )"
|
||||||
|
if [ -n "$result" ]; then
|
||||||
|
echo "Go code is not formatted, run 'gofmt -s -w .'" >&2
|
||||||
|
echo "$result"
|
||||||
|
exit 1
|
||||||
|
fi
|
25
.ci/check-testfiles
Executable file
25
.ci/check-testfiles
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# checks if every desired package has test files
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
source_re = re.compile(".*\.go")
|
||||||
|
test_re = re.compile(".*_test\.go")
|
||||||
|
missing = False
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk("."):
|
||||||
|
# ignore some paths
|
||||||
|
if root == "." or root.startswith("./vendor") or root.startswith("./."):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# source files but not test files?
|
||||||
|
if len(filter(source_re.match, files)) > 0 and len(filter(test_re.match, files)) == 0:
|
||||||
|
print("no test files for {}".format(root))
|
||||||
|
missing = True
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print("every package has test files")
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
config.conf
|
53
.gitlab-ci.yml
Normal file
53
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
image: golang:latest
|
||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- mkdir -p "/go/src/dev.sum7.eu/$CI_PROJECT_NAMESPACE/"
|
||||||
|
- cp -R "$CI_PROJECT_DIR" "/go/src/dev.sum7.eu/$CI_PROJECT_NAMESPACE/"
|
||||||
|
- cd "/go/src/dev.sum7.eu/$CI_PROJECT_PATH"
|
||||||
|
- go get -d -t ./...
|
||||||
|
|
||||||
|
build-my-project:
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- mkdir "$CI_PROJECT_DIR/bin/"
|
||||||
|
- go install "dev.sum7.eu/$CI_PROJECT_PATH"
|
||||||
|
- mv "/go/bin/$CI_PROJECT_NAME" "$CI_PROJECT_DIR/bin/$CI_PROJECT_NAME"
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- "bin/$CI_PROJECT_NAME"
|
||||||
|
- config_example.toml
|
||||||
|
|
||||||
|
test-my-project:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- go get github.com/client9/misspell/cmd/misspell
|
||||||
|
- misspell -error .
|
||||||
|
- ./.ci/check-gofmt
|
||||||
|
- ./.ci/check-testfiles
|
||||||
|
- go test $(go list ./... | grep -v /vendor/) -v -coverprofile .testCoverage.txt
|
||||||
|
- go tool cover -func=.testCoverage.txt
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- .testCoverage.txt
|
||||||
|
|
||||||
|
test-race-my-project:
|
||||||
|
stage: test
|
||||||
|
script:
|
||||||
|
- go test -race ./...
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
stage: deploy
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
script:
|
||||||
|
- go install "dev.sum7.eu/$CI_PROJECT_PATH"
|
||||||
|
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
|
||||||
|
- eval $(ssh-agent -s)
|
||||||
|
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
|
||||||
|
- ssh -o StrictHostKeyChecking=no -p $SSH_PORT "$CI_PROJECT_NAME@$SSH_HOST" sudo /usr/bin/systemctl stop $CI_PROJECT_NAME
|
||||||
|
- scp -o StrictHostKeyChecking=no -P $SSH_PORT "/go/bin/$CI_PROJECT_NAME" "$CI_PROJECT_NAME@$SSH_HOST":/opt/$CI_PROJECT_NAME/bin
|
||||||
|
- ssh -o StrictHostKeyChecking=no -p $SSH_PORT "$CI_PROJECT_NAME@$SSH_HOST" sudo /usr/bin/systemctl start $CI_PROJECT_NAME
|
32
.test-coverage
Executable file
32
.test-coverage
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Issue: https://github.com/mattn/goveralls/issues/20
|
||||||
|
# Source: https://github.com/uber/go-torch/blob/63da5d33a225c195fea84610e2456d5f722f3963/.test-cover.sh
|
||||||
|
CI=$1
|
||||||
|
echo "run for $CI"
|
||||||
|
|
||||||
|
if [ "$CI" == "circle-ci" ]; then
|
||||||
|
cd ${GOPATH}/src/github.com/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "mode: count" > profile.cov
|
||||||
|
FAIL=0
|
||||||
|
|
||||||
|
# Standard go tooling behavior is to ignore dirs with leading underscors
|
||||||
|
for dir in $(find . -maxdepth 10 -not -path './vendor/*' -not -path './.git*' -not -path '*/_*' -type d);
|
||||||
|
do
|
||||||
|
if ls $dir/*.go &> /dev/null; then
|
||||||
|
go test -v -covermode=count -coverprofile=profile.tmp $dir || FAIL=$?
|
||||||
|
if [ -f profile.tmp ]
|
||||||
|
then
|
||||||
|
tail -n +2 < profile.tmp >> profile.cov
|
||||||
|
rm profile.tmp
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Failures have incomplete results, so don't send
|
||||||
|
if [ "$FAIL" -eq 0 ]; then
|
||||||
|
goveralls -v -coverprofile=profile.cov -service=$CI -repotoken=$COVERALLS_REPO_TOKEN
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $FAIL
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 genofire
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
52
README.md
Normal file
52
README.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# hook2xmpp
|
||||||
|
|
||||||
|
|
||||||
|
[![pipeline status](https://dev.sum7.eu/genofire/hook2xmpp/badges/master/pipeline.svg)](https://dev.sum7.eu/genofire/hook2xmpp/pipelines)
|
||||||
|
[![coverage report](https://dev.sum7.eu/genofire/hook2xmpp/badges/master/coverage.svg)](https://dev.sum7.eu/genofire/hook2xmpp/pipelines)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/dev.sum7.eu/genofire/hook2xmpp)](https://goreportcard.com/report/dev.sum7.eu/genofire/hook2xmpp)
|
||||||
|
[![GoDoc](https://godoc.org/dev.sum7.eu/genofire/hook2xmpp?status.svg)](https://godoc.org/dev.sum7.eu/genofire/hook2xmpp)
|
||||||
|
|
||||||
|
|
||||||
|
## Get hook2xmpp
|
||||||
|
|
||||||
|
#### Download
|
||||||
|
|
||||||
|
Latest Build binary from ci here:
|
||||||
|
|
||||||
|
[Download All](https://dev.sum7.eu/genofire/hook2xmpp/-/jobs/artifacts/master/download/?job=build-my-project) (with config example)
|
||||||
|
|
||||||
|
[Download Binary](https://dev.sum7.eu/genofire/hook2xmpp/-/jobs/artifacts/master/raw/bin/hook2xmpp?inline=false&job=build-my-project)
|
||||||
|
|
||||||
|
#### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u dev.sum7.eu/genofire/hook2xmpp
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configure
|
||||||
|
|
||||||
|
see `config_example.toml`
|
||||||
|
|
||||||
|
## Start / Boot
|
||||||
|
|
||||||
|
_/lib/systemd/system/hook2xmpp.service_ :
|
||||||
|
```
|
||||||
|
[Unit]
|
||||||
|
Description=hook2xmpp
|
||||||
|
After=network.target
|
||||||
|
# After=ejabberd.service
|
||||||
|
# After=prosody.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
# User=notRoot
|
||||||
|
ExecStart=/opt/go/bin/hook2xmpp --config /etc/hook2xmpp.conf
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5sec
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
Start: `systemctl start hook2xmpp`
|
||||||
|
Autostart: `systemctl enable hook2xmpp`
|
19
config.go
Normal file
19
config.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bdlm/std/logger"
|
||||||
|
|
||||||
|
"dev.sum7.eu/ccchb/ccchatbot/schalter"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
LogLevel logger.Level `toml:"log_level"`
|
||||||
|
|
||||||
|
XMPP struct {
|
||||||
|
Host string `toml:"host"`
|
||||||
|
JID string `toml:"jid"`
|
||||||
|
Password string `toml:"password"`
|
||||||
|
} `toml:"xmpp"`
|
||||||
|
|
||||||
|
Schalter schalter.Schalter `toml:"schalter"`
|
||||||
|
}
|
11
config.toml
Normal file
11
config.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
log_level = 50
|
||||||
|
|
||||||
|
|
||||||
|
[xmpp]
|
||||||
|
jid = "fluxxmpp@chat.sum7.eu"
|
||||||
|
password = "test"
|
||||||
|
|
||||||
|
[schalter]
|
||||||
|
url = "https://schalter.ccchb.de/spaceapi.json"
|
||||||
|
|
||||||
|
muc = ["ffhb_events@conference.chat.sum7.eu","#ccchb@irc.hackint.org"]
|
64
config_example.toml
Normal file
64
config_example.toml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
log_level = 50
|
||||||
|
webserver_bind = ":8080"
|
||||||
|
|
||||||
|
startup_notify_user = ["user@fireorbit.de"]
|
||||||
|
startup_notify_muc = []
|
||||||
|
|
||||||
|
nickname = "logbot"
|
||||||
|
|
||||||
|
[xmpp]
|
||||||
|
address = "fireorbit.de"
|
||||||
|
jid = "bot@fireorbit.de"
|
||||||
|
password = "example"
|
||||||
|
|
||||||
|
# suported hooks are, which could be declared multiple times with different `secrets` (see [[hooks.grafana]]):
|
||||||
|
[[hooks.grafana]]
|
||||||
|
[[hooks.prometheus]]
|
||||||
|
[[hooks.git]]
|
||||||
|
[[hooks.gitlab]]
|
||||||
|
[[hooks.circleci]]
|
||||||
|
|
||||||
|
# every hook could have following attributes:
|
||||||
|
secret = ""
|
||||||
|
notify_muc = []
|
||||||
|
notify_user = []
|
||||||
|
|
||||||
|
# for handling webhooks from prometheus alertmanager
|
||||||
|
|
||||||
|
[[hooks.prometheus]]
|
||||||
|
|
||||||
|
# for handling webhooks from grafana
|
||||||
|
# at http://localhost:8080/grafana
|
||||||
|
# for image support you have to enable `external_image_storage` (e.g. `provider = local`)
|
||||||
|
# see more at http://docs.grafana.org/installation/configuration/#external-image-storage
|
||||||
|
[[hooks.grafana]]
|
||||||
|
secret = "dev.sum7.eu-aShared-Secret"
|
||||||
|
notify_muc = ["monitoring@conference.chat.sum7.eu"]
|
||||||
|
|
||||||
|
[[hooks.grafana]]
|
||||||
|
secret = "dev.sum7.eu-aShared-Secret-for important messages"
|
||||||
|
notify_user = ["user@fireorbit.de"]
|
||||||
|
|
||||||
|
|
||||||
|
# for handling webhooks from git software (e.g. gitea, gogs, github)
|
||||||
|
# at http://localhost:8080/git
|
||||||
|
[[hooks.git]]
|
||||||
|
secret = "github-FreifunkBremen-yanic-aShared-Secret"
|
||||||
|
notify_muc = []
|
||||||
|
notify_user = ["user@fireorbit.de"]
|
||||||
|
|
||||||
|
# for handling webhooks from gitlab
|
||||||
|
# at http://localhost:8080/gitlab
|
||||||
|
[[hooks.gitlab]]
|
||||||
|
secret = "dev.sum7.eu-aShared-Secret"
|
||||||
|
notify_muc = []
|
||||||
|
notify_user = ["user@fireorbit.de"]
|
||||||
|
|
||||||
|
# for handling webhooks from circleci
|
||||||
|
# at http://localhost:8080/circleci
|
||||||
|
[[hooks.circleci]]
|
||||||
|
secret = "dev.sum7.eu-aShared-Secret"
|
||||||
|
notify_muc = []
|
||||||
|
notify_user = ["user@fireorbit.de"]
|
||||||
|
|
||||||
|
|
70
main.go
Normal file
70
main.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"dev.sum7.eu/genofire/golang-lib/file"
|
||||||
|
"github.com/bdlm/log"
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
|
||||||
|
"dev.sum7.eu/ccchb/ccchatbot/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var config = Config{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
configFile := "config.toml"
|
||||||
|
flag.StringVar(&configFile, "config", configFile, "path of configuration file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if err := file.ReadTOML(configFile, &config); err != nil {
|
||||||
|
log.WithField("tip", "maybe call me with: ccchatbot --config /etc/ccchatbot.conf").Panicf("error on read config: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.SetLevel(config.LogLevel)
|
||||||
|
|
||||||
|
router := xmpp.NewRouter()
|
||||||
|
router.HandleFunc("presence", handlePresence)
|
||||||
|
router.HandleFunc("message", func(s xmpp.Sender, p stanza.Packet) {
|
||||||
|
msg, ok := p.(stanza.Message)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("ignoring wrong routed packet: %T", p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := config.Schalter.HandleBotMessage(s, msg); err != nil {
|
||||||
|
log.Debugf("bot could not handle message: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
var err error
|
||||||
|
client, err := xmpp.NewClient(xmpp.Config{
|
||||||
|
Address: config.XMPP.Host,
|
||||||
|
Jid: config.XMPP.JID,
|
||||||
|
Password: config.XMPP.Password,
|
||||||
|
}, router)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("error on startup xmpp client: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cm := xmpp.NewStreamManager(client, func(s xmpp.Sender) {
|
||||||
|
config.Schalter.Run(s)
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
err := cm.Run()
|
||||||
|
log.Panic("closed connection:", err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for system signal
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
sig := <-sigs
|
||||||
|
|
||||||
|
runtime.LeaveAllMUCs(client)
|
||||||
|
|
||||||
|
log.Infof("closed by receiving: %s", sig)
|
||||||
|
}
|
41
runtime/muc.go
Normal file
41
runtime/muc.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bdlm/log"
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mucs []string
|
||||||
|
|
||||||
|
func JoinMUC(c xmpp.Sender, to, nick string) error {
|
||||||
|
|
||||||
|
toJID, err := xmpp.NewJid(to)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
toJID.Resource = nick
|
||||||
|
jid := toJID.Full()
|
||||||
|
|
||||||
|
mucs = append(mucs, jid)
|
||||||
|
|
||||||
|
return c.Send(stanza.Presence{Attrs: stanza.Attrs{To: jid},
|
||||||
|
Extensions: []stanza.PresExtension{
|
||||||
|
stanza.MucPresence{
|
||||||
|
History: stanza.History{MaxStanzas: stanza.NewNullableInt(0)},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func LeaveAllMUCs(c xmpp.Sender) {
|
||||||
|
|
||||||
|
for _, muc := range mucs {
|
||||||
|
if err := c.Send(stanza.Presence{Attrs: stanza.Attrs{
|
||||||
|
To: muc,
|
||||||
|
Type: stanza.PresenceTypeUnavailable,
|
||||||
|
}}); err != nil {
|
||||||
|
log.WithField("muc", muc).Errorf("error on leaving muc: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
runtime/send.go
Normal file
70
runtime/send.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bdlm/log"
|
||||||
|
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SendImage(client xmpp.Sender, users, mucs []string, url, desc string) {
|
||||||
|
msg := stanza.Message{
|
||||||
|
Attrs: stanza.Attrs{Type: stanza.MessageTypeGroupchat},
|
||||||
|
Body: url,
|
||||||
|
Extensions: []stanza.MsgExtension{
|
||||||
|
stanza.OOB{URL: url, Desc: desc},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, muc := range mucs {
|
||||||
|
msg.To = muc
|
||||||
|
if err := client.Send(msg); err != nil {
|
||||||
|
log.WithFields(map[string]interface{}{
|
||||||
|
"muc": muc,
|
||||||
|
"url": url,
|
||||||
|
}).Errorf("error on image notify: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Type = stanza.MessageTypeChat
|
||||||
|
for _, user := range users {
|
||||||
|
msg.To = user
|
||||||
|
if err := client.Send(msg); err != nil {
|
||||||
|
log.WithFields(map[string]interface{}{
|
||||||
|
"user": user,
|
||||||
|
"url": url,
|
||||||
|
}).Errorf("error on image notify: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendText(client xmpp.Sender, users, mucs []string, text, html string) {
|
||||||
|
msg := stanza.Message{
|
||||||
|
Attrs: stanza.Attrs{Type: stanza.MessageTypeGroupchat},
|
||||||
|
Body: text,
|
||||||
|
Extensions: []stanza.MsgExtension{
|
||||||
|
stanza.HTML{Body: stanza.HTMLBody{InnerXML: html}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, muc := range mucs {
|
||||||
|
msg.To = muc
|
||||||
|
if err := client.Send(msg); err != nil {
|
||||||
|
log.WithFields(map[string]interface{}{
|
||||||
|
"muc": muc,
|
||||||
|
"text": text,
|
||||||
|
}).Errorf("error on notify: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Type = stanza.MessageTypeChat
|
||||||
|
for _, user := range users {
|
||||||
|
msg.To = user
|
||||||
|
if err := client.Send(msg); err != nil {
|
||||||
|
log.WithFields(map[string]interface{}{
|
||||||
|
"user": user,
|
||||||
|
"text": text,
|
||||||
|
}).Errorf("error on notify: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
runtime/xmpp_test.go
Normal file
1
runtime/xmpp_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package runtime
|
26
schalter/bot.go
Normal file
26
schalter/bot.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package schalter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Schalter) HandleBotMessage(c xmpp.Sender, msg stanza.Message) error {
|
||||||
|
if msg.Body == ".status" {
|
||||||
|
jid, _ := xmpp.NewJid(msg.From)
|
||||||
|
reply := stanza.Message{
|
||||||
|
Attrs: stanza.Attrs{Type: msg.Type,
|
||||||
|
To: msg.From,
|
||||||
|
},
|
||||||
|
Body: s.StateString(),
|
||||||
|
}
|
||||||
|
if msg.Type == stanza.MessageTypeGroupchat {
|
||||||
|
reply.To = jid.Bare()
|
||||||
|
reply.Body = fmt.Sprintf("%s: %s", jid.Resource, reply.Body)
|
||||||
|
}
|
||||||
|
return c.Send(reply)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("not handled by this bot: %v", msg)
|
||||||
|
}
|
58
xmpp.go
Normal file
58
xmpp.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bdlm/log"
|
||||||
|
"gosrc.io/xmpp"
|
||||||
|
"gosrc.io/xmpp/stanza"
|
||||||
|
)
|
||||||
|
|
||||||
|
func handlePresence(s xmpp.Sender, p stanza.Packet) {
|
||||||
|
pres, ok := p.(stanza.Presence)
|
||||||
|
if !ok {
|
||||||
|
log.Errorf("blame gosrc.io/xmpp for routing: %s", p)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
from, err := xmpp.NewJid(pres.From)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("blame gosrc.io/xmpp for jid encoding: %s", pres.From)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fromBare := from.Bare()
|
||||||
|
logPres := log.WithField("from", from)
|
||||||
|
|
||||||
|
switch pres.Type {
|
||||||
|
case stanza.PresenceTypeSubscribe:
|
||||||
|
logPres.Debugf("recv presence subscribe")
|
||||||
|
if err := s.Send(stanza.Presence{Attrs: stanza.Attrs{
|
||||||
|
Type: stanza.PresenceTypeSubscribed,
|
||||||
|
To: fromBare,
|
||||||
|
Id: pres.Id,
|
||||||
|
}}); err != nil {
|
||||||
|
logPres.WithField("user", pres.From).Errorf("answer of subscribe not send: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logPres.Debugf("accept new subscribe")
|
||||||
|
|
||||||
|
if err := s.Send(stanza.Presence{Attrs: stanza.Attrs{
|
||||||
|
Type: stanza.PresenceTypeSubscribe,
|
||||||
|
To: fromBare,
|
||||||
|
}}); err != nil {
|
||||||
|
logPres.WithField("user", pres.From).Errorf("request of subscribe not send: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logPres.Info("request also subscribe")
|
||||||
|
case stanza.PresenceTypeSubscribed:
|
||||||
|
logPres.Info("recv presence accepted subscribe")
|
||||||
|
case stanza.PresenceTypeUnsubscribe:
|
||||||
|
logPres.Info("recv presence remove subscribe")
|
||||||
|
case stanza.PresenceTypeUnsubscribed:
|
||||||
|
logPres.Info("recv presence removed subscribe")
|
||||||
|
case stanza.PresenceTypeUnavailable:
|
||||||
|
logPres.Debug("recv presence unavailable")
|
||||||
|
case "":
|
||||||
|
logPres.Debug("recv empty presence, maybe from joining muc")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
logPres.Warnf("recv presence unsupported: %s -> %v", pres.Type, pres)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue