Browse Source

В общем то функциональная версия для запуска в тмуксе

Всё работает, тестируем
Надо сделать полноценный демон, и поглядеть, что там с алертером
А еще добавить полезных комманд.
master
Mikhail Grebenkin 6 years ago
parent
commit
5f04c8370e
5 changed files with 293 additions and 16 deletions
  1. +142
    -0
      events_alerter/events_alerter.go
  2. BIN
      goqdpmbot
  3. +10
    -0
      goqdpmbot.ini
  4. +95
    -16
      main.go
  5. +46
    -0
      works/works.go

+ 142
- 0
events_alerter/events_alerter.go View File

@ -0,0 +1,142 @@
package events_alerter
import (
"database/sql"
"fmt"
"strings"
"time"
)
import _ "github.com/go-sql-driver/mysql"
type MsgStr struct {
remote string
message string
}
func (msg MsgStr) Remote() string {
return msg.remote
}
func (msg MsgStr) Message() string {
return msg.message
}
type MsgInt interface {
Remote() string
Message() string
}
type DbRequester struct {
login string
pass string
host string
database string
}
func (dbStruct *DbRequester) ReqPrepare(sqlStr ...string) string {
if len(sqlStr) > 1 {
values := make([]interface{}, len(sqlStr)-1)
for i, _ := range sqlStr[1:] {
k := i + 1
values[i] = sqlStr[k]
}
return fmt.Sprintf(sqlStr[0], values...)
} else {
return sqlStr[0]
}
}
func (dbStruct *DbRequester) Requester(sqlStr string) (allResult [][]string, err error) {
connStr := fmt.Sprintf("%v:%v@tcp(%v)/%v", dbStruct.login, dbStruct.pass, dbStruct.host, dbStruct.database)
db, err := sql.Open("mysql", connStr)
if err != nil {
return
}
defer db.Close()
err = db.Ping()
if err != nil {
return
}
req, err := db.Prepare(sqlStr)
if err != nil {
return
}
defer req.Close()
rows, err := req.Query() //пыщим запросий
if err != nil {
return
}
cols, err := rows.Columns() // получаем слайс стрингов с названиями колонок
if err != nil {
return
}
rawResult := make([][]byte, len(cols)) // слайс слайсов байт, это одна строка выхлопа сырая
dest := make([]interface{}, len(cols)) // слайс пустых интерфейсов
for i, _ := range rawResult {
dest[i] = &rawResult[i] // Put pointers to each string in the interface slice
}
for rows.Next() {
err = rows.Scan(dest...)
if err != nil {
return
}
result := make([]string, len(cols)) // слайс строк, одна строка выхлопа, которую надо добавить в общий выхлоп
for i, raw := range rawResult {
if raw == nil {
result[i] = "Null"
} else {
result[i] = string(raw)
}
}
allResult = append(allResult, result)
}
return
}
func BuildAlert() (msgSl []MsgInt) {
msgTpl := `Вспомни! %v время для важного!
Задача '%v' ждет тебя,
Лови ссыль:
https://pm.constanta-smt.ru/index.php/tasksComments?tasks_id=%v&projects_id=%v`
dbuser := DbRequester{
login: "bot",
pass: "z68puEFJhEBtS",
host: "10.176.120.51",
database: "qdpm",
}
createdFormat := "2006-01-02 15:04"
t := time.Now()
sqlTpl := `select extra_fields_list.value, tasks.projects_id as pid, tasks.id as tid, name tname, tasks.assigned_to as users
from extra_fields_list, tasks
where extra_fields_list.extra_fields_id = 10 and extra_fields_list.value = '%v' and extra_fields_list.bind_id = tasks.id ;`
//sqlTpl := `select extra_fields_list.value, tasks.projects_id as pid, tasks.id as tid, name tname, tasks.assigned_to as users
//from extra_fields_list, tasks
//where extra_fields_list.extra_fields_id = 10 and extra_fields_list.value <> '' and extra_fields_list.bind_id = tasks.id ;`
fmt.Println(dbuser.ReqPrepare(sqlTpl, t.Format(createdFormat)))
res, err := dbuser.Requester(dbuser.ReqPrepare(sqlTpl, t.Format(createdFormat)))
fmt.Printf("%#v, %#v\n", res, err)
if len(res) > 0 { // обработка запроса, если найдено больше 0 строк
for _, v := range res {
fmt.Println(v)
msgStr := fmt.Sprintf(msgTpl, v[0], v[3], v[2], v[1])
uidSl := strings.Split(v[4], ",")
jidSl := make([]string, len(uidSl))
for _, uid := range uidSl {
sqlTpl = "select value from qdpm.extra_fields_list where extra_fields_id = 11 and bind_id = '%v';"
jid, _ := dbuser.Requester(dbuser.ReqPrepare(sqlTpl, uid))
if len(jid) > 0 {
tmpJid := jid[0][0]
jidSl = append(jidSl, tmpJid)
fmt.Printf("%v\n", tmpJid)
tmpMsg := MsgStr{remote: tmpJid, message: msgStr}
msgSl = append(msgSl, tmpMsg)
}
}
}
fmt.Println(msgSl)
}
return
}

BIN
goqdpmbot View File


+ 10
- 0
goqdpmbot.ini View File

@ -0,0 +1,10 @@
#сервер:порт
server=jabber.constanta-smt.ru:5222
#имя пользователя, полный jabber id
username=zabbix@jabber.constanta-smt.ru
# пароль
password=ciw2kahZ
# не врубать шифрование. Для внутренней сети - всегда true
notls=true
# тот, кому не повезло получать алерты по умолчанию
dest=grebenkin@jabber.constanta-smt.ru

+ 95
- 16
main.go View File

@ -4,10 +4,16 @@ import (
"crypto/tls"
"flag"
"fmt"
"goqdpmbot/events_alerter"
"goqdpmbot/works"
"os"
"path"
"path/filepath"
// "runtime"
// "strconv"
"strings"
"sync"
"time"
"github.com/mattn/go-xmpp"
@ -22,6 +28,11 @@ type cfgStruct struct {
notls bool
}
type commandMsg struct {
remote string
message string
}
func serverName(host string) string {
return strings.Split(host, ":")[0]
}
@ -96,32 +107,100 @@ func jabberClient(cfg cfgStruct) *xmpp.Client {
return talk
}
func jabberReader(talk *xmpp.Client, in <-chan int) {
// читаем из джаббера и отправляем в канал
func jabberReader(talk *xmpp.Client, command chan<- commandMsg, in <-chan int) {
for {
_, err := talk.Recv()
chat, err := talk.Recv()
if err != nil {
fmt.Println(err)
}
switch v := chat.(type) {
case xmpp.Chat:
com := commandMsg{remote: v.Remote, message: v.Text}
command <- com
//case xmpp.Presence:
// com := commandMsg{remote: v.From, message: v.Show}
// command <- com
}
}
}
// отправляем ответы из канала
func jabberSender(talk *xmpp.Client, msgChan <-chan commandMsg) {
for {
msg := <-msgChan
remote := strings.Split(msg.remote, "/")[0]
talk.Send(xmpp.Chat{Remote: remote, Type: "chat", Text: msg.message})
}
}
// воркер
func worker(workerNum int, msgChan <-chan commandMsg, readerClose chan int, ansChan chan<- commandMsg) {
for {
message := <-msgChan
fmt.Println("Worker = ", workerNum, "message= ", message.message)
cmd := strings.Split(message.message, " ")
workMap := works.Works()
_, workExists := workMap[cmd[0]]
if workExists {
work, _ := workMap[cmd[0]]
ans, err := work.(func(...string) (string, error))(cmd[1:]...)
if err != nil {
ansChan <- commandMsg{remote: message.remote, message: err.Error()}
} else {
ansChan <- commandMsg{remote: message.remote, message: ans}
}
} else if len(message.message) > 0 {
ans := "неизвестная комманда"
ansChan <- commandMsg{remote: message.remote, message: ans}
}
}
}
func main() {
readerClose := make(chan int, 1)
cfg := cfgRead("goxmppalert.ini")
var send_remote string
var send_text string
if len(os.Args) == 3 {
send_remote = os.Args[1]
send_text = os.Args[2]
} else {
send_remote = cfg.dest
send_text = os.Args[1]
//нопоминальщик
func reminder(readerClose chan int, ansChan chan<- commandMsg) {
for {
msgSl := events_alerter.BuildAlert()
fmt.Println("alerter works")
fmt.Println(msgSl)
for _, msgInt := range msgSl {
tmpMsg := commandMsg{remote: msgInt.Remote(), message: msgInt.Message()}
fmt.Println(tmpMsg)
ansChan <- tmpMsg
}
time.Sleep(60 * time.Second)
}
}
func main() {
cfg := cfgRead("goqdpmbot.ini") // читаем конфигу
goroutinesNum := 5 // количество потоков
wg := &sync.WaitGroup{} // ожидаем интеррапта
signal_channel := make(chan os.Signal, 1)
readerClose := make(chan int, 1) // для закрытия всего зоопарка воркеров
// каналы обмена инфой
comChan := make(chan commandMsg, 5)
ansChan := make(chan commandMsg, 5)
// запускаем клиента
talk := jabberClient(cfg)
go jabberReader(talk, readerClose)
go talk.Send(xmpp.Chat{Remote: send_remote, Type: "chat", Text: send_text})
time.Sleep(1 * time.Second)
go jabberReader(talk, comChan, readerClose)
go jabberSender(talk, ansChan)
// и воркеров
for i := 0; i < goroutinesNum; i++ {
go worker(i, comChan, readerClose, ansChan)
fmt.Println("worker started", i)
}
go reminder(readerClose, ansChan)
// ожидаем выхода
wg.Add(1)
go func() {
<-signal_channel
wg.Done()
}()
wg.Wait()
close(readerClose)
time.Sleep(1 * time.Second)
fmt.Println("interrupt")
talk.Close()
}

+ 46
- 0
works/works.go View File

@ -0,0 +1,46 @@
package works
import (
"bytes"
"os/exec"
"time"
)
func Uname(param ...string) (string, error) {
//var cmdParam string
unameCmd := exec.Command("uname")
if len(param) != 0 {
//for _, p := range param {
// cmdParam += p
//}
unameCmd = exec.Command("uname", param...)
}
var out bytes.Buffer
unameCmd.Stdout = &out
err := unameCmd.Run()
if err != nil {
return "", err
}
return out.String(), err
}
func Wait(param ...string) (string, error) {
time.Sleep(10 * time.Second)
return "worker sleep 10s", nil
}
func Echo(param ...string) (string, error) {
var out string
for _, v := range param {
out += v + " "
}
return out, nil
}
func Works() map[string]interface{} {
return map[string]interface{}{
"uname": Uname,
"wait": Wait,
"echo": Echo,
}
}

Loading…
Cancel
Save

Powered by TurnKey Linux.