commit
fec3bad50e
17 changed files with 1107 additions and 0 deletions
@ -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