Browse Source

initial commit

master
Brett Langdon 11 years ago
commit
29f3fe463b
7 changed files with 292 additions and 0 deletions
  1. +1
    -0
      .gitignore
  2. +4
    -0
      README.md
  3. +23
    -0
      main.go
  4. +8
    -0
      plugins/plugin.go
  5. +111
    -0
      plugins/sqwiggle/sqwiggle.go
  6. +81
    -0
      server/server.go
  7. +64
    -0
      slack/api.go

+ 1
- 0
.gitignore View File

@ -0,0 +1 @@
slackbot

+ 4
- 0
README.md View File

@ -0,0 +1,4 @@
slackbot
========
A slackbot written in go.

+ 23
- 0
main.go View File

@ -0,0 +1,23 @@
package main
import (
"flag"
"log"
"github.com/brettlangdon/slackbot/plugins/sqwiggle"
"github.com/brettlangdon/slackbot/server"
)
var bind string
func main() {
flag.StringVar(&bind, "bind", "127.0.0.1:8000", "which address to bind to [defualt: 127.0.0.1:8000]")
flag.Parse()
s := server.NewServer()
s.AddPlugin(sqwiggle.NewSqwiggle())
s.SetListenAddress(bind)
log.Fatal(s.Start())
}

+ 8
- 0
plugins/plugin.go View File

@ -0,0 +1,8 @@
package plugins
import "github.com/brettlangdon/slackbot/slack"
type Plugin interface {
GetName() string
HandleRequest(slack.APIRequest, []string) (slack.APIResponse, error)
}

+ 111
- 0
plugins/sqwiggle/sqwiggle.go View File

@ -0,0 +1,111 @@
package sqwiggle
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"github.com/brettlangdon/slackbot/slack"
)
type SqwiggleResponse struct {
Snapshot string `json:"snapshot"`
Status string `json:"status"`
Name string `json:"name"`
EMail string `json:"email"`
TimeZone string `json:"time_zone"`
Avatar string `json:"avatar"`
Message string `json:"message"`
SnapshotInterval int `json:"snapshot_interval"`
}
type Sqwiggle struct {
name string
}
func NewSqwiggle() Sqwiggle {
return Sqwiggle{
name: "sqwiggle",
}
}
func (this Sqwiggle) GetName() string {
return this.name
}
func (this Sqwiggle) SetName(name string) {
this.name = name
}
func (this Sqwiggle) callSqwiggle(token string) (response []SqwiggleResponse, err error) {
client := &http.Client{}
request, err := http.NewRequest("GET", "https://api.sqwiggle.com/users", nil)
if err != nil {
return response, err
}
request.SetBasicAuth(token, "slackbot")
sqwiggleResponse, err := client.Do(request)
if err != nil || sqwiggleResponse.StatusCode != 200 {
err = errors.New(fmt.Sprintf("API call to sqwiggle with token %s failed", token))
return response, err
}
defer sqwiggleResponse.Body.Close()
contents, err := ioutil.ReadAll(sqwiggleResponse.Body)
if err != nil {
err = errors.New("Could not read sqwiggle api response")
return response, err
}
err = json.Unmarshal(contents, &response)
if err != nil {
err = errors.New(fmt.Sprintf("Could not parse sqwiggle api response: %s", string(contents)))
return response, err
}
return response, nil
}
func (this Sqwiggle) HandleRequest(request slack.APIRequest, args []string) (response slack.APIResponse, err error) {
if request.Text != "#sqwiggle" {
err := errors.New(fmt.Sprintf("Incorrect trigger text: %s", request.Text))
return response, err
}
if len(args) <= 1 {
err := errors.New("Missing sqwiggle token argument")
return response, err
}
users, err := this.callSqwiggle(args[1])
if err != nil {
return response, err
}
response.Text = "Sqwiggle Time"
for _, user := range users {
attachment := slack.Attachment{}
switch user.Status {
case "offline":
attachment.Color = "#000000"
case "available":
attachment.Color = "#00CC33"
case "busy":
attachment.Color = "#FF3333"
}
attachment.Title = user.Name
attachment.TitleLink = user.Snapshot
attachment.ImageUrl = user.Snapshot
attachment.Fallback = user.Snapshot + "#.jpg"
response.Attachments = append(response.Attachments, attachment)
}
return response, err
}

+ 81
- 0
server/server.go View File

@ -0,0 +1,81 @@
package server
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"github.com/brettlangdon/slackbot/plugins"
"github.com/brettlangdon/slackbot/slack"
)
type Server struct {
plugs map[string]plugins.Plugin
address string
server *http.Server
}
func NewServer() *Server {
server := &Server{
address: "0.0.0.0:80",
}
server.plugs = make(map[string]plugins.Plugin)
return server
}
func (this *Server) SetListenAddress(address string) {
this.address = address
}
func (this *Server) AddPlugin(plug plugins.Plugin) {
this.plugs[strings.ToLower(plug.GetName())] = plug
}
func (this *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// we always want to write back something
defer fmt.Fprintf(w, "")
path := strings.Trim(r.URL.Path, "/")
if path == "" {
log.Println("Empty path given")
return
}
args := strings.Split(path, "/")
name := strings.ToLower(args[0])
var plug plugins.Plugin
var ok bool
if plug, ok = this.plugs[name]; !ok {
log.Println("No plugin gin found with name: ", name)
return
}
apiRequest := slack.ParseAPIRequest(r)
apiResponse, err := plug.HandleRequest(apiRequest, args)
if err != nil {
log.Println(err)
return
}
content, err := json.Marshal(apiResponse)
if err != nil {
log.Println(err)
return
}
fmt.Fprintf(w, "%s", content)
}
func (this *Server) Start() error {
this.server = &http.Server{
Addr: this.address,
Handler: this,
}
log.Println("Listening to: ", this.address)
return this.server.ListenAndServe()
}

+ 64
- 0
slack/api.go View File

@ -0,0 +1,64 @@
package slack
import (
"net/http"
"strconv"
)
type APIRequest struct {
Token string
TeamId string
TeamDomain string
ChannelId string
ChannelName string
Timestamp float64
UserId string
UserName string
Text string
TriggerWord string
}
func ParseAPIRequest(httpReq *http.Request) (response APIRequest) {
response.Token = httpReq.PostFormValue("token")
response.TeamId = httpReq.PostFormValue("team_id")
response.TeamDomain = httpReq.PostFormValue("team_domain")
response.ChannelId = httpReq.PostFormValue("channel_id")
response.ChannelName = httpReq.PostFormValue("channel_name")
ts := httpReq.PostFormValue("timestamp")
response.Timestamp, _ = strconv.ParseFloat(ts, 32)
response.UserId = httpReq.PostFormValue("user_id")
response.UserName = httpReq.PostFormValue("user_name")
response.Text = httpReq.PostFormValue("text")
response.TriggerWord = httpReq.PostFormValue("trigger_word")
return response
}
type APIResponse struct {
Text string `json:"text,omitempty"`
Attachments []Attachment `json:"attachments,omitempty"`
UserName string `json:"user_name,omitempty"`
IconEmoji string `json:"icon_emoji,omitempty"`
Channel string `json:"channel,omitempty"`
Markdown bool `json:"mrkdwn,omitempty"`
}
type Attachment struct {
AuthorIcon string `json:"author_icon,omitempty"`
AuthorLink string `json:"author_link,omitempty"`
AuthorName string `json:"author_name,omitempty"`
Color string `json:"color,omitempty"`
Fallback string `json:"fallback,omitempty"`
Fields []Fields `json:"fields,omitempty"`
ImageUrl string `json:"image_url,omitempty"`
MarkdownIn string `json:"mrkdwn_in,omitempty"`
Pretext string `json:"pretext,omitempty"`
Title string `json:"title,omitempty"`
TitleLink string `json:"title_link,omitempty"`
}
type Fields struct {
Title string `json:"title,omitempty"`
Value string `json:"value,omitempty"`
Short bool `json:"short,omitempty"`
}

Loading…
Cancel
Save