Вдохновлённый постом «Простой диспетчер задач с веб-интерфейсом, написанный на языке GO для Unix-систем включая Android», языком Go и утилитой simple status, я решил написать в качестве забавного эксперимента чат-бота для социальной сети Vkontakte со схожим функционалом.
Почему выбор пал на чат-бота и социальную сеть? Кроме очевидного just for fun имеются и практические выкладки:
- Не нужны дополнительные телодвижения для доступа к приложению, запущенном на компьютере с динамическим ip или находящимся за роутером.
- Доступ к Вконтактике есть практически везде – достаточно иметь при себе телефон с доступом в интернет.
- Вопрос о реализации аутентификации на уровне конечного приложения практически отпадает.
Утилита представляет собой простого чат бота, реагирующего на текстовые команды. Пишем в VK сообщение самому себе, утилита с некоторой периодичностью опрашивает VK API и получает список сообщений. Дальше только остаётся сопоставить введённое сообщение со списком предопределённых текстовых команд.
Ничего сложного, правда есть некоторые нюансы, которые надо знать про VK API.
Во-первых, для доступа к личным сообщениям надо регистрировать VK приложение как desktop. И при запросе access token выставить права на доступ к личным сообщениям и «бланковую» страницу для callback.
Адрес для получения access token будет выглядеть примерно так:
https://oauth.vk.com/authorize?client_id=#####&scope=offline,messages&redirect_uri=https%3A%2F%2Foauth.vk.com%2Fblank.html&display=page&v=5.28&response_type=token
Во-вторых, есть ограничение по количеству запросов в секунду, поэтому получение сообщений происходит с таймером в 2 секунды.
c := time.Tick(2 * time.Second)
lastMsgId := int64(0)
for _ = range c {
msgs, err := getMsgs(lastMsgId)
if err != nil {
fmt.Println(err)
} else {
if len(msgs.Response.Items) > 0 {
lastMsgId = msgs.Response.Items[0].Id
}
for _, msg := range msgs.Response.Items {
msgBody := strings.Trim(msg.Body, "")
if checkVkId(msg.UserId) && checkTime(msg.Date) && checkResultPrefix(msgBody) {
go doCmd(msgBody)
}
}
}
}
Разбор входящего сообщения и отправка результата исполнения команды:
func doSysCmd(msg string) {
switch true {
case strings.HasPrefix(msg, "@sys/host"):
sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetHost()))
case strings.HasPrefix(msg, "@sys/disk"):
sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetDisk("/")))
case strings.HasPrefix(msg, "@sys/load"):
sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetLoad()))
case strings.HasPrefix(msg, "@sys/ram"):
sendMsg(*vk_id, fmt.Sprintf("%+v", sysstat.GetRam()))
case strings.HasPrefix(msg, "@sys"):
sendMsg(*vk_id, fmt.Sprintf("n%+v", sysstat.GetSystem("/")))
case strings.HasPrefix(msg, "@sh"):
args := strings.SplitN(msg, " ", 2)
if len(args) < 2 {
return
}
fmt.Println("exec: ", args[1])
sendMsg(*vk_id, fmt.Sprintf(" %+v", sysstat.ExecShell(args[1])))
}
}
Кроме получения текущего статуса системы в качестве бонуса можно сохранять произвольные заметки командами:
!list – вывод сохраненного списка с номерами id
!add [текст] – добавить новую запись
!del [номер] – удалить запись с указанным id
Заметки сохраняются исключительно в памяти.
Защита от краха приложения не предусмотрена, я взял за практику запускать подобные вещи под супервизором, который сам перезапускает приложение, если возникнет критическая ошибка. Потребление ОЗУ для go программ традиционно минимально и колеблется в районе 10 МБ, ещё столько же отнимает супервизор.
Исходники на github.
Автор: ZurgInq