Initial commit
This commit is contained in:
commit
fec3bad50e
|
@ -0,0 +1,2 @@
|
|||
cscsysbot
|
||||
ENV
|
|
@ -0,0 +1,27 @@
|
|||
# IRC Configuration
|
||||
export IRC_SERVER=chat.freenode.net
|
||||
export IRC_PORT=6697
|
||||
export IRC_CHANNELS="#channel"
|
||||
export IRC_USER=user
|
||||
export IRC_NICK=nick
|
||||
export IRC_PASSWORD=password
|
||||
|
||||
# Set this variable to enable debug
|
||||
export IRC_DEBUG
|
||||
|
||||
# Background Messages
|
||||
export SYSCOM_CHANNELS="#channel"
|
||||
|
||||
# Twitter Configuration
|
||||
export TWITTER_CONSUMER_KEY=""
|
||||
export TWITTER_CONSUMER_SECRET=""
|
||||
export TWITTER_ACCESS_TOKEN=""
|
||||
export TWITTER_ACCESS_SECRET=""
|
||||
export TWITTER_USERS="UWNetworkAlert"
|
||||
|
||||
# Uptime Robot
|
||||
export UPTIME_ROBOT_API_KEY=""
|
||||
|
||||
# UPS
|
||||
export UPSES=""
|
||||
export UPS_COMMUNITY_STRING=""
|
|
@ -0,0 +1,38 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-chat-bot/bot/irc"
|
||||
|
||||
// Plugins
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/hello"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/url"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/ups"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/member"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/club"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/ping"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/greetings"
|
||||
|
||||
// Backgrounds tasks
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/background"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/tweets"
|
||||
_ "git.uwaterloo.ca/csc/cscsysbot/plugins/uptimerobot"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, debug := os.LookupEnv("IRC_DEBUG")
|
||||
|
||||
irc.Run(&irc.Config{
|
||||
Server: fmt.Sprintf("%s:%s", os.Getenv("IRC_SERVER"), os.Getenv("IRC_PORT")),
|
||||
Channels: strings.Split(os.Getenv("IRC_CHANNELS"), ","),
|
||||
User: os.Getenv("IRC_USER"),
|
||||
Nick: os.Getenv("IRC_NICK"),
|
||||
Password: os.Getenv("IRC_PASSWORD"),
|
||||
UseTLS: true,
|
||||
TLSServerName: os.Getenv("IRC_SERVER"),
|
||||
Debug: debug,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package background
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
)
|
||||
|
||||
var Messages chan string = make(chan string, 100)
|
||||
func processMessages(channel string) (string, error) {
|
||||
select {
|
||||
case message, _ := <- Messages:
|
||||
return message, nil
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
channels := strings.Split(os.Getenv("SYSCOM_CHANNELS"), ",")
|
||||
|
||||
if len(channels) > 0 {
|
||||
config := bot.PeriodicConfig{
|
||||
CronSpec: "@every 3s",
|
||||
Channels: channels,
|
||||
CmdFunc: processMessages,
|
||||
}
|
||||
bot.RegisterPeriodicCommand("background_messages", config)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package club
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sort"
|
||||
|
||||
"git.uwaterloo.ca/csc/cscsysbot/utils"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
ldapServer = "ldap-master.csclub.uwaterloo.ca"
|
||||
)
|
||||
|
||||
type ByTerm []string
|
||||
func (s ByTerm) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s ByTerm) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s ByTerm) Less(i, j int) bool {
|
||||
a := s[i]
|
||||
b := s[j]
|
||||
|
||||
ya, _ := strconv.ParseInt(a[1:5], 10, 32)
|
||||
yb, _ := strconv.ParseInt(b[1:5], 10, 32)
|
||||
|
||||
if (ya == yb) {
|
||||
// w, s, f (happens to be in reverse order)
|
||||
return a[0] > b[0]
|
||||
}
|
||||
|
||||
return ya < yb
|
||||
}
|
||||
|
||||
func club(command *bot.Cmd) (string, error) {
|
||||
var lines []string
|
||||
|
||||
if len(command.Args) != 1 {
|
||||
return "An invalid number of arguments was provided. Usage is: !club userid", nil
|
||||
}
|
||||
|
||||
authorized, _ := utils.SyscomNicks()
|
||||
if (!utils.InList(authorized, command.User.Nick)) {
|
||||
return "Sorry, you are not authorized to request membership information from me.", nil
|
||||
}
|
||||
|
||||
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, 636), &tls.Config{
|
||||
ServerName: ldapServer,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
req := ldap.NewSearchRequest("ou=People,dc=csclub,dc=uwaterloo,dc=ca", ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(uid=%s)(objectClass=club))", command.Args[0]),
|
||||
[]string{"*"}, nil)
|
||||
|
||||
res, err := l.Search(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(res.Entries) == 0 {
|
||||
lines = append(lines, fmt.Sprintf("No clubs matched userid %q", command.Args[0]))
|
||||
} else {
|
||||
entry := res.Entries[0]
|
||||
lines = append(lines, fmt.Sprintf("Club: %s (%s) -- %s",
|
||||
entry.GetAttributeValue("uid"),
|
||||
entry.GetAttributeValue("uidNumber"),
|
||||
entry.GetAttributeValue("cn")))
|
||||
|
||||
lines = append(lines, fmt.Sprintf("Login Shell: %s, Home Directory: %s", entry.GetAttributeValue("loginShell"), entry.GetAttributeValue("homeDirectory")))
|
||||
}
|
||||
|
||||
// Get members
|
||||
req = ldap.NewSearchRequest("ou=Group,dc=csclub,dc=uwaterloo,dc=ca", ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(cn=%s)(objectClass=posixGroup))", command.Args[0]),
|
||||
[]string{"*"}, nil)
|
||||
res, err = l.Search(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(res.Entries) == 0 {
|
||||
lines = append(lines, fmt.Sprintf("No groups matched name %q", command.Args[0]))
|
||||
} else {
|
||||
entry := res.Entries[0]
|
||||
|
||||
lines = append(lines, fmt.Sprintf("Group: %s (%s)", entry.GetAttributeValue("cn"), entry.GetAttributeValue("gidNumber")))
|
||||
|
||||
members := entry.GetAttributeValues("uniqueMember")
|
||||
memberUids := make([]string, len(members))
|
||||
for i, member := range members {
|
||||
memberUids[i] = strings.Replace(strings.Replace(member, "uid=", "", -1), ",ou=People,dc=csclub,dc=uwaterloo,dc=ca", "", -1)
|
||||
}
|
||||
|
||||
smemberUids := sort.StringSlice(memberUids[0:])
|
||||
sort.Sort(smemberUids)
|
||||
lines = append(lines, fmt.Sprintf("Members: %s", strings.Join(smemberUids, ", ")))
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n"), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterCommand(
|
||||
"club",
|
||||
"Prints club information",
|
||||
"userid",
|
||||
club)
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package greetings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.uwaterloo.ca/csc/cscsysbot/utils/uptimerobot"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
)
|
||||
|
||||
func goodMorning(channel string) (string, error) {
|
||||
var lines []string
|
||||
|
||||
lines = append(lines, fmt.Sprintf("Good morning, %s!", channel))
|
||||
|
||||
// Get UptimeRobot status
|
||||
monitors, err := uptimerobot.GetMonitors()
|
||||
if err == nil {
|
||||
statuses := make(map[uptimerobot.MonitorStatus]int)
|
||||
for _, mon := range monitors.Monitors {
|
||||
_, ok := statuses[mon.Status]
|
||||
if !ok {
|
||||
statuses[mon.Status] = 1
|
||||
} else {
|
||||
statuses[mon.Status] += 1
|
||||
}
|
||||
}
|
||||
|
||||
var sts []string
|
||||
for status, num := range statuses {
|
||||
sts = append(sts, fmt.Sprintf("%d %s", num, strings.ToLower(status.String())))
|
||||
}
|
||||
|
||||
lines = append(lines, fmt.Sprintf("Uptime Robot Monitors: %s", strings.Join(sts, ", ")))
|
||||
} else {
|
||||
lines = append(lines, "Unable to get Uptime Robot information")
|
||||
}
|
||||
|
||||
return strings.Join(lines, "\n"), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
channels := strings.Split(os.Getenv("SYSCOM_CHANNELS"), ",")
|
||||
|
||||
if len(channels) > 0 {
|
||||
config := bot.PeriodicConfig{
|
||||
CronSpec: "0 0 8 * * *",
|
||||
Channels: channels,
|
||||
CmdFunc: goodMorning,
|
||||
}
|
||||
bot.RegisterPeriodicCommand("good_morning", config)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package hello
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
)
|
||||
|
||||
func hello(command *bot.Cmd) (msg string, err error) {
|
||||
msg = fmt.Sprintf("Hello %s", command.User.Nick)
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterCommand(
|
||||
"hello",
|
||||
"Sends a 'Hello' message to you on the channel.",
|
||||
"",
|
||||
hello)
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package member
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"git.uwaterloo.ca/csc/cscsysbot/utils"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
ldapServer = "ldap-master.csclub.uwaterloo.ca"
|
||||
)
|
||||
|
||||
type ByTerm []string
|
||||
func (s ByTerm) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s ByTerm) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s ByTerm) Less(i, j int) bool {
|
||||
a := s[i]
|
||||
b := s[j]
|
||||
|
||||
ya, _ := strconv.ParseInt(a[1:5], 10, 32)
|
||||
yb, _ := strconv.ParseInt(b[1:5], 10, 32)
|
||||
|
||||
if (ya == yb) {
|
||||
// w, s, f (happens to be in reverse order)
|
||||
return a[0] > b[0]
|
||||
}
|
||||
|
||||
return ya < yb
|
||||
}
|
||||
|
||||
func member(command *bot.Cmd) (string, error) {
|
||||
var lines []string
|
||||
|
||||
if len(command.Args) != 1 {
|
||||
return "An invalid number of arguments was provided. Usage is: !member userid", nil
|
||||
}
|
||||
|
||||
authorized, _ := utils.SyscomNicks()
|
||||
if (!utils.InList(authorized, command.User.Nick)) {
|
||||
return "Sorry, you are not authorized to request membership information from me.", nil
|
||||
}
|
||||
|
||||
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, 636), &tls.Config{
|
||||
ServerName: ldapServer,
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
req := ldap.NewSearchRequest("ou=People,dc=csclub,dc=uwaterloo,dc=ca", ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(uid=%s)(objectClass=member))", command.Args[0]),
|
||||
[]string{"*"}, nil)
|
||||
|
||||
res, err := l.Search(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(res.Entries) == 0 {
|
||||
return fmt.Sprintf("No members matched userid %q", command.Args[0]), nil
|
||||
}
|
||||
|
||||
entry := res.Entries[0]
|
||||
lines = append(lines, fmt.Sprintf("%s (%s) -- %s",
|
||||
entry.GetAttributeValue("uid"),
|
||||
entry.GetAttributeValue("uidNumber"),
|
||||
entry.GetAttributeValue("cn")))
|
||||
lines = append(lines, entry.GetAttributeValue("program"))
|
||||
|
||||
positions := sort.StringSlice(entry.GetAttributeValues("position")[0:])
|
||||
positions.Sort()
|
||||
if len(positions) > 0 {
|
||||
lines = append(lines, fmt.Sprintf("Position: %s", strings.Join(positions, ", ")))
|
||||
}
|
||||
|
||||
// Get groups
|
||||
groupReq := ldap.NewSearchRequest("ou=Group,dc=csclub,dc=uwaterloo,dc=ca", ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(uniqueMember=%s)(objectClass=group))", entry.DN),
|
||||
[]string{"*"}, nil)
|
||||
groupRes, err := l.Search(groupReq)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(groupRes.Entries) > 0 {
|
||||
groups := make([]string, len(groupRes.Entries))
|
||||
for i, entry := range groupRes.Entries {
|
||||
groups[i] = entry.GetAttributeValue("cn")
|
||||
}
|
||||
|
||||
sgroups := sort.StringSlice(groups[0:])
|
||||
sort.Sort(sgroups)
|
||||
lines = append(lines, fmt.Sprintf("Clubs/Groups: %s", strings.Join(sgroups, ", ")))
|
||||
}
|
||||
|
||||
terms := entry.GetAttributeValues("term")
|
||||
sort.Sort(ByTerm(terms))
|
||||
if len(terms) > 0 {
|
||||
lines = append(lines, fmt.Sprintf("Terms: %s", strings.Join(terms, ", ")))
|
||||
}
|
||||
|
||||
nonMemberTerms := entry.GetAttributeValues("nonMemberTerm")
|
||||
sort.Sort(ByTerm(terms))
|
||||
if len(nonMemberTerms) > 0 {
|
||||
lines = append(lines, fmt.Sprintf("Non Member Terms: %s", strings.Join(nonMemberTerms, ", ")))
|
||||
}
|
||||
|
||||
lines = append(lines, fmt.Sprintf("Login Shell: %s, Home Directory: %s", entry.GetAttributeValue("loginShell"), entry.GetAttributeValue("homeDirectory")))
|
||||
|
||||
return strings.Join(lines, "\n"), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterCommand(
|
||||
"member",
|
||||
"Prints member information",
|
||||
"userid",
|
||||
member)
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package club
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.uwaterloo.ca/csc/cscsysbot/utils"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
)
|
||||
|
||||
type InsensitiveSlice []string
|
||||
func (s InsensitiveSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s InsensitiveSlice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s InsensitiveSlice) Less(i, j int) bool {
|
||||
a := strings.ToLower(s[i])
|
||||
b := strings.ToLower(s[j])
|
||||
|
||||
return a < b
|
||||
}
|
||||
|
||||
func ping(command *bot.Cmd) (string, error) {
|
||||
nicks, _ := utils.SyscomNicks()
|
||||
nicksStr := strings.Join(nicks, ", ")
|
||||
if len(command.RawArgs) > 0 && len(command.RawArgs) + len(nicksStr) < 400 {
|
||||
return fmt.Sprintf("%s (attn: %s)", command.RawArgs, nicksStr), nil
|
||||
} else if len(command.RawArgs) > 0 {
|
||||
return fmt.Sprintf("%s\n^ %s", command.RawArgs, nicksStr), nil
|
||||
} else {
|
||||
return fmt.Sprintf("Ping %s", nicksStr), nil
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterCommand(
|
||||
"ping",
|
||||
"Highlights all Syscom members.",
|
||||
"Optionally a message to prepend the list of syscom members.",
|
||||
ping)
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package tweets
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"git.uwaterloo.ca/csc/cscsysbot/plugins/background"
|
||||
|
||||
"github.com/dghubble/go-twitter/twitter"
|
||||
"github.com/dghubble/oauth1"
|
||||
)
|
||||
|
||||
func lookup(tw *twitter.Client, sn string) (*twitter.User, error) {
|
||||
params := &twitter.UserLookupParams{
|
||||
ScreenName: []string{sn},
|
||||
}
|
||||
users, _, err := tw.Users.Lookup(params)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(users) > 0 {
|
||||
return &users[0], nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func userInList(users []*twitter.User, user *twitter.User) bool {
|
||||
for _, u := range users {
|
||||
if u.ID == user.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Start Twitter stream
|
||||
authConfig := oauth1.NewConfig(os.Getenv("TWITTER_CONSUMER_KEY"), os.Getenv("TWITTER_CONSUMER_SECRET"))
|
||||
authToken := oauth1.NewToken(os.Getenv("TWITTER_ACCESS_TOKEN"), os.Getenv("TWITTER_ACCESS_SECRET"))
|
||||
|
||||
httpClient := authConfig.Client(oauth1.NoContext, authToken)
|
||||
tw := twitter.NewClient(httpClient)
|
||||
|
||||
watchScreenames := strings.Split(os.Getenv("TWITTER_USERS"), ",")
|
||||
var users []*twitter.User
|
||||
for _, screename := range watchScreenames {
|
||||
user, err := lookup(tw, screename)
|
||||
if err != nil {
|
||||
log.Println("Unable to get Twitter user", screename, err)
|
||||
continue
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
demux := twitter.NewSwitchDemux()
|
||||
demux.Tweet = func(tweet *twitter.Tweet) {
|
||||
if userInList(users, tweet.User) {
|
||||
background.Messages <- fmt.Sprintf("%s: %s", tweet.User.Name, strings.Replace(tweet.Text, "\n", " ", -1))
|
||||
}
|
||||
}
|
||||
demux.StreamDisconnect = func(disconnect *twitter.StreamDisconnect) {
|
||||
log.Println("Stream disconnected", disconnect)
|
||||
}
|
||||
|
||||
userIds := make([]string, len(users))
|
||||
for i, user := range users {
|
||||
userIds[i] = user.IDStr
|
||||
}
|
||||
params := &twitter.StreamFilterParams{
|
||||
Follow: userIds,
|
||||
StallWarnings: twitter.Bool(true),
|
||||
}
|
||||
stream, err := tw.Streams.Filter(params)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go demux.HandleChan(stream.Messages)
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ups
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"os"
|
||||
|
||||
"github.com/go-chat-bot/bot"
|
||||
)
|
||||
|
||||
func ups(command *bot.Cmd) (msg string, err error) {
|
||||
upses := strings.Split(os.Getenv("UPSES"), ",")
|
||||
|
||||
var messages []string
|
||||
for _, upsName := range upses {
|
||||
ups := UPSStatus(upsName, os.Getenv("UPS_COMMUNITY_STRING"))
|
||||
messages = append(messages, fmt.Sprintf("[%s] Runtime: %s, Status: %s, Battery: %s - %s\n", strings.Split(ups.Name, ".")[0], ups.EstimatedRuntime, ups.OutputStatus, ups.BatteryStatus, ups.BatteryReplaceIndicator))
|
||||
}
|
||||
|
||||
msg = strings.Join(messages, "\n")
|
||||
return
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterCommand(
|
||||
"ups",
|
||||
"Prints current UPS status information. (Note: this command may take some time to execute)",
|
||||
"",
|
||||
ups)
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
package ups
|
||||
|
||||
import(
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/alouca/gosnmp"
|
||||
)
|
||||
|
||||
type BatteryStatus int
|
||||
const (
|
||||
BatteryStatusUnknown BatteryStatus = 1
|
||||
BatteryStatusNormal BatteryStatus = 2
|
||||
BatteryStatusLow BatteryStatus = 3
|
||||
BatteryStatusFault BatteryStatus = 4
|
||||
)
|
||||
|
||||
func (st BatteryStatus) String() string {
|
||||
str := "Invalid"
|
||||
switch(st) {
|
||||
case BatteryStatusUnknown:
|
||||
str = "Unknown"
|
||||
case BatteryStatusNormal:
|
||||
str = "Normal"
|
||||
case BatteryStatusLow:
|
||||
str = "Low"
|
||||
case BatteryStatusFault:
|
||||
str = "Fault"
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
type BatteryReplaceIndicator int
|
||||
const (
|
||||
BatteryReplaceIndicatorOK BatteryReplaceIndicator = 1
|
||||
BatteryReplaceIndicatorReplace BatteryReplaceIndicator = 2
|
||||
)
|
||||
|
||||
func (st BatteryReplaceIndicator) String() string {
|
||||
str := "Invalid"
|
||||
switch(st) {
|
||||
case BatteryReplaceIndicatorOK:
|
||||
str = "Ok"
|
||||
case BatteryReplaceIndicatorReplace:
|
||||
str = "Replace"
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
type OutputStatus int
|
||||
const (
|
||||
OutputStatusUnknown OutputStatus = 1
|
||||
OutputStatusOnLine OutputStatus = 2
|
||||
OutputStatusOnBattery OutputStatus = 3
|
||||
OutputStatusOnSmartBoost OutputStatus = 4
|
||||
OutputStatusTimedSleeping OutputStatus = 5
|
||||
OutputStatusSoftwareBypass OutputStatus = 6
|
||||
OutputStatusOff OutputStatus = 7
|
||||
OutputStatusRebooting OutputStatus = 8
|
||||
OutputStatusSwitchedBypass OutputStatus = 9
|
||||
OutputStatusHardwareFailureBypass OutputStatus = 10
|
||||
OutputStatusSleepingUntilPowerReturn OutputStatus = 11
|
||||
OutputStatusOnSmartTrim OutputStatus = 12
|
||||
)
|
||||
|
||||
func (st OutputStatus) String() string {
|
||||
str := "Invalid"
|
||||
switch(st) {
|
||||
case OutputStatusUnknown:
|
||||
str = "Unknown"
|
||||
case OutputStatusOnLine:
|
||||
str = "On Line"
|
||||
case OutputStatusOnBattery:
|
||||
str = "On Battery"
|
||||
case OutputStatusOnSmartBoost:
|
||||
str = "On Smart Boost"
|
||||
case OutputStatusTimedSleeping:
|
||||
str = "Timed Sleeping"
|
||||
case OutputStatusSoftwareBypass:
|
||||
str = "Software Bypass"
|
||||
case OutputStatusOff:
|
||||
str = "Off"
|
||||
case OutputStatusRebooting:
|
||||
str = "Rebooting"
|
||||
case OutputStatusSwitchedBypass:
|
||||
str = "Switched Bypass"
|
||||
case OutputStatusHardwareFailureBypass:
|
||||
str = "Hardware Failure Bypass"
|
||||
case OutputStatusSleepingUntilPowerReturn:
|
||||
str = "Sleeping Until Power Return"
|
||||
case OutputStatusOnSmartTrim:
|
||||
str = "On Smart Trim"
|
||||
}
|
||||
|
||||
return str
|
||||
}
|
||||
|
||||
func getRuntime(s *gosnmp.GoSNMP) (* time.Duration, error) {
|
||||
resp, err := s.Get("1.3.6.1.4.1.318.1.1.1.2.2.3.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Variables) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
time, _ := time.ParseDuration(fmt.Sprintf("%dm", resp.Variables[0].Value.(int) / 60/ 100))
|
||||
return &time, nil
|
||||
}
|
||||
|
||||
func getBatteryStatus(s *gosnmp.GoSNMP) (* BatteryStatus, error) {
|
||||
resp, err := s.Get("1.3.6.1.4.1.318.1.1.1.2.1.1.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Variables) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
status := BatteryStatus(resp.Variables[0].Value.(int))
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func getBatteryReplaceIndicator(s *gosnmp.GoSNMP) (* BatteryReplaceIndicator, error) {
|
||||
resp, err := s.Get("1.3.6.1.4.1.318.1.1.1.2.2.4.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Variables) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
status := BatteryReplaceIndicator(resp.Variables[0].Value.(int))
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
func getOutputStatus(s *gosnmp.GoSNMP) (* OutputStatus, error) {
|
||||
resp, err := s.Get("1.3.6.1.4.1.318.1.1.1.4.1.1.0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(resp.Variables) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
status := OutputStatus(resp.Variables[0].Value.(int))
|
||||
return &status, nil
|
||||
}
|
||||
|
||||
type UPS struct {
|
||||
Name string
|
||||
EstimatedRuntime *time.Duration
|
||||
BatteryStatus *BatteryStatus
|
||||
BatteryReplaceIndicator *BatteryReplaceIndicator
|
||||
OutputStatus *OutputStatus
|
||||
}
|
||||
|
||||
func UPSStatus(name string, community string) *UPS {
|
||||
ups := &UPS{
|
||||
Name: name,
|
||||
EstimatedRuntime: nil,
|
||||
BatteryStatus: nil,
|
||||
BatteryReplaceIndicator: nil,
|
||||
OutputStatus: nil,
|
||||
}
|
||||
|
||||
// Get UPS status
|
||||
snmp, _ := gosnmp.NewGoSNMP(name, community, gosnmp.Version1, 2)
|
||||
|
||||
ups.EstimatedRuntime, _ = getRuntime(snmp)
|
||||
ups.BatteryStatus, _ = getBatteryStatus(snmp)
|
||||
ups.BatteryReplaceIndicator, _ = getBatteryReplaceIndicator(snmp)
|
||||
ups.OutputStatus, _ = getOutputStatus(snmp)
|
||||
|
||||
return ups
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package uptimerobot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
ur "git.uwaterloo.ca/csc/cscsysbot/utils/uptimerobot"
|
||||
"git.uwaterloo.ca/csc/cscsysbot/plugins/background"
|
||||
)
|
||||
|
||||
func uptimeRobot() {
|
||||
lastStatuses := make(map[int]ur.MonitorStatus)
|
||||
|
||||
for {
|
||||
monitors, err := ur.GetMonitors()
|
||||
if err != nil {
|
||||
time.Sleep(time.Minute * 1)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, mon := range monitors.Monitors {
|
||||
lastStatus, ok := lastStatuses[mon.ID]
|
||||
lastStatuses[mon.ID] = mon.Status
|
||||
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if lastStatus != mon.Status {
|
||||
if (mon.Type == ur.MonitorTypePort) {
|
||||
background.Messages <- fmt.Sprintf("Uptime Robot: %s -> %s, %s:%d (%s)\n", lastStatus, mon.Status, mon.URL, mon.Type, int(mon.Port.(float64)))
|
||||
} else {
|
||||
background.Messages <- fmt.Sprintf("Uptime Robot: %s -> %s, %s (%s)\n", lastStatus, mon.Status, mon.URL, mon.Type)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
time.Sleep(time.Minute * 1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
go uptimeRobot()
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Based on https://github.com/go-chat-bot/plugins/blob/master/url/url.go
|
||||
// Copyright (c) 2014 Fábio Gomes
|
||||
// The MIT License (MIT)
|
||||
|
||||
package url
|
||||
|
||||
import (
|
||||
"github.com/go-chat-bot/bot"
|
||||
"github.com/go-chat-bot/plugins/web"
|
||||
"html"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
minDomainLength = 3
|
||||
)
|
||||
|
||||
var (
|
||||
re = regexp.MustCompile("<title>\\n*?(.*?)\\n*?<\\/title>")
|
||||
)
|
||||
|
||||
func canBeURLWithoutProtocol(text string) bool {
|
||||
return len(text) > minDomainLength &&
|
||||
!strings.HasPrefix(text, "http") &&
|
||||
strings.Contains(text, ".")
|
||||
}
|
||||
|
||||
func extractURL(text string) string {
|
||||
extractedURL := ""
|
||||
for _, value := range strings.Split(text, " ") {
|
||||
if canBeURLWithoutProtocol(value) {
|
||||
value = "http://" + value
|
||||
}
|
||||
|
||||
parsedURL, err := url.Parse(value)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(parsedURL.Scheme, "http") {
|
||||
extractedURL = parsedURL.String()
|
||||
break
|
||||
}
|
||||
}
|
||||
return extractedURL
|
||||
}
|
||||
|
||||
func urlTitle(cmd *bot.PassiveCmd) (string, error) {
|
||||
URL := extractURL(cmd.Raw)
|
||||
|
||||
if URL == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
body, err := web.GetBody(URL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
title := re.FindString(string(body))
|
||||
if title == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
title = strings.Replace(title, "\n", "", -1)
|
||||
title = title[strings.Index(title, ">")+1 : strings.LastIndex(title, "<")]
|
||||
|
||||
return fmt.Sprintf("%q", html.UnescapeString(title)), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
bot.RegisterPassiveCommand(
|
||||
"url",
|
||||
urlTitle)
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package utils
|
||||
|
||||
func InList(l []string, s string) bool {
|
||||
for _, i := range l {
|
||||
if i == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package utils
|
||||
|
||||
import(
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sort"
|
||||
|
||||
"gopkg.in/ldap.v2"
|
||||
)
|
||||
|
||||
type InsensitiveSlice []string
|
||||
func (s InsensitiveSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s InsensitiveSlice) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s InsensitiveSlice) Less(i, j int) bool {
|
||||
a := strings.ToLower(s[i])
|
||||
b := strings.ToLower(s[j])
|
||||
|
||||
return a < b
|
||||
}
|
||||
|
||||
const (
|
||||
ldapServer = "ldap-master.csclub.uwaterloo.ca"
|
||||
)
|
||||
|
||||
func SyscomNicks() ([]string, error) {
|
||||
l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, 636), &tls.Config{
|
||||
ServerName: ldapServer,
|
||||
})
|
||||
if err != nil {
|
||||
return make([]string, 0), err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Get members
|
||||
req := ldap.NewSearchRequest("ou=Group,dc=csclub,dc=uwaterloo,dc=ca", ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(cn=syscom)(objectClass=posixGroup))",
|
||||
[]string{"*"}, nil)
|
||||
res, err := l.Search(req)
|
||||
if err != nil {
|
||||
return make([]string, 0), err
|
||||
}
|
||||
|
||||
if len(res.Entries) > 0 {
|
||||
entry := res.Entries[0]
|
||||
|
||||
members := entry.GetAttributeValues("uniqueMember")
|
||||
memberUids := make([]string, len(members))
|
||||
for i, member := range members {
|
||||
memberUids[i] = strings.Replace(strings.Replace(member, "uid=", "", -1),
|
||||
",ou=People,dc=csclub,dc=uwaterloo,dc=ca", "", -1)
|
||||
|
||||
// Exceptions: some use different nicks
|
||||
switch memberUids[i] {
|
||||
case "ztseguin":
|
||||
memberUids[i] = "zseguin"
|
||||
case "nablack":
|
||||
memberUids[i] = "Na"
|
||||
case "laden":
|
||||
memberUids[i] = "Luqman"
|
||||
}
|
||||
}
|
||||
|
||||
smemberUids := InsensitiveSlice(memberUids[0:])
|
||||
sort.Sort(smemberUids)
|
||||
return []string(smemberUids), nil
|
||||
}
|
||||
|
||||
return make([]string, 0), nil
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package uptimerobot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
"encoding/json"
|
||||
"time"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Really basic, no pagination support
|
||||
type Monitors struct {
|
||||
Monitors []Monitor `json:"monitors"`
|
||||
}
|
||||
|
||||
type Monitor struct {
|
||||
ID int `json:"id"`
|
||||
FriendlyName string `json:"friendly_name"`
|
||||
URL string `json:"url"`
|
||||
Type MonitorType `json:"type"`
|
||||
Status MonitorStatus `json:"status"`
|
||||
|
||||
// Type specifc properties
|
||||
Port interface{} `json:"port"`
|
||||
}
|
||||
|
||||
type MonitorType int
|
||||
const (
|
||||
_ MonitorType = iota
|
||||
MonitorTypeHTTP
|
||||
MonitorTypeKeyword
|
||||
MonitorTypePing
|
||||
MonitorTypePort
|
||||
)
|
||||
|
||||
func (t MonitorType) String() string {
|
||||
switch t {
|
||||
case MonitorTypeHTTP:
|
||||
return "HTTP"
|
||||
case MonitorTypeKeyword:
|
||||
return "HTTP Keyword"
|
||||
case MonitorTypePing:
|
||||
return "Ping"
|
||||
case MonitorTypePort:
|
||||
return "Port"
|
||||
}
|
||||
|
||||
return "Invalid"
|
||||
}
|
||||
|
||||
type MonitorStatus int
|
||||
const (
|
||||
MonitorStatusPaused MonitorStatus = 0
|
||||
MonitorStatusNotCheckedYet = 1
|
||||
MonitorStatusUp = 2
|
||||
MonitorStatusSeemsDown = 8
|
||||
MonitorStatusDown = 9
|
||||
)
|
||||
|
||||
func (s MonitorStatus) String() string {
|
||||
switch s {
|
||||
case MonitorStatusPaused:
|
||||
return "Paused"
|
||||
case MonitorStatusNotCheckedYet:
|
||||
return "Not Checked Yet"
|
||||
case MonitorStatusUp:
|
||||
return "Up"
|
||||
case MonitorStatusSeemsDown:
|
||||
return "Seems Down"
|
||||
case MonitorStatusDown:
|
||||
return "Down"
|
||||
}
|
||||
|
||||
return "Invalid"
|
||||
}
|
||||
|
||||
func GetMonitors() (Monitors, error) {
|
||||
var monitors Monitors
|
||||
|
||||
transport := &http.Transport{
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: time.Second * 10,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: time.Second * 10,
|
||||
}
|
||||
net := http.Client{
|
||||
Timeout: time.Second * 10,
|
||||
Transport: transport,
|
||||
}
|
||||
url := "https://api.uptimerobot.com/v2/getMonitors"
|
||||
payload := strings.NewReader(fmt.Sprintf("api_key=%s&format=json", os.Getenv("UPTIME_ROBOT_API_KEY")))
|
||||
req, err := http.NewRequest("POST", url, payload)
|
||||
if err != nil {
|
||||
return monitors, err
|
||||
}
|
||||
|
||||
req.Header.Add("content-type", "application/x-www-form-urlencoded")
|
||||
req.Header.Add("cache-control", "no-cache")
|
||||
|
||||
res, err := net.Do(req)
|
||||
if err != nil {
|
||||
return monitors, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return monitors, err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &monitors)
|
||||
if err != nil {
|
||||
return monitors, err
|
||||
}
|
||||
|
||||
return monitors, nil
|
||||
}
|
Loading…
Reference in New Issue