Created
April 17, 2017 00:51
-
-
Save muesli/9aeaf4ae497624f1d2410fd3e7e12c7c to your computer and use it in GitHub Desktop.
GitterBee
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2017 Christian Muehlhaeuser | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU Affero General Public License as published | |
* by the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU Affero General Public License for more details. | |
* | |
* You should have received a copy of the GNU Affero General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* Authors: | |
* Nicolas Martin <[email protected]> | |
* Christian Muehlhaeuser <[email protected]> | |
*/ | |
// Package gitterbee is a Bee that can interface with Gitter | |
package gitterbee | |
import ( | |
gitter "github.com/sromku/go-gitter" | |
"github.com/muesli/beehive/bees" | |
) | |
// GitterBee is a Bee that can interface with Gitter | |
type GitterBee struct { | |
bees.Bee | |
eventChan chan bees.Event | |
client *gitter.Gitter | |
userID string | |
accessToken string | |
rooms []string | |
roomChans map[string]chan interface{} | |
} | |
// Action triggers the actions passed to it. | |
func (mod *GitterBee) Action(action bees.Action) []bees.Placeholder { | |
outs := []bees.Placeholder{} | |
switch action.Name { | |
case "send": | |
var room string | |
var message string | |
action.Options.Bind("room", &room) | |
action.Options.Bind("message", &message) | |
roomID, err := mod.client.GetRoomId(room) | |
if err != nil { | |
mod.LogErrorf("Failed to fetch room ID from uri:", err) | |
return outs | |
} | |
if err = mod.client.SendMessage(roomID, message); err != nil { | |
mod.LogErrorf("Failed to send message:", err) | |
return outs | |
} | |
case "join": | |
var room string | |
action.Options.Bind("room", &room) | |
mod.join(room) | |
case "leave": | |
var room string | |
action.Options.Bind("room", &room) | |
ch, ok := mod.roomChans[room] | |
if !ok { | |
mod.LogErrorf("Can't leave this room: %s", room) | |
return outs | |
} | |
mod.Logln("Closing room stream", room) | |
close(ch) | |
default: | |
panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) | |
} | |
return outs | |
} | |
// Run executes the Bee's event loop. | |
func (mod *GitterBee) Run(eventChan chan bees.Event) { | |
mod.eventChan = eventChan | |
mod.client = gitter.New(mod.accessToken) | |
user, err := mod.client.GetUser() | |
if err != nil { | |
mod.LogErrorf("Failed to fetch current user: %v", err) | |
return | |
} | |
mod.userID = user.ID | |
for _, room := range mod.rooms { | |
mod.join(room) | |
} | |
select { | |
case <-mod.SigChan: | |
for room, ch := range mod.roomChans { | |
mod.Logln("Closing room stream", room) | |
close(ch) | |
} | |
return | |
} | |
} | |
func (mod *GitterBee) join(room string) error { | |
mod.Logln("Joining room", room) | |
roomID, err := mod.client.GetRoomId(room) | |
if err != nil { | |
mod.LogErrorf("Failed to fetch room ID: %v", err) | |
return err | |
} | |
r, err := mod.client.JoinRoom(roomID, mod.userID) | |
if err != nil { | |
mod.LogErrorf("Failed to join room: %v", err) | |
return err | |
} | |
sigchan := make(chan interface{}) | |
mod.roomChans[room] = sigchan | |
stream := mod.client.Stream(r.ID) | |
defer stream.Close() | |
go mod.client.Listen(stream) | |
go func() { | |
for { | |
select { | |
case <-sigchan: | |
mod.Logln("Exiting", room) | |
return | |
case event := <-stream.Event: | |
switch ev := event.Data.(type) { | |
case *gitter.MessageReceived: | |
mod.handleMessage(room, &ev.Message) | |
case *gitter.GitterConnectionClosed: | |
// connection was closed | |
mod.LogErrorf("Connection closed") | |
go mod.join(room) | |
return | |
} | |
} | |
} | |
}() | |
return nil | |
} | |
func (mod *GitterBee) handleMessage(room string, v *gitter.Message) { | |
ev := bees.Event{ | |
Bee: mod.Name(), | |
Name: "message", | |
Options: []bees.Placeholder{ | |
{ | |
Name: "id", | |
Type: "string", | |
Value: v.ID, | |
}, | |
{ | |
Name: "text", | |
Type: "string", | |
Value: v.Text, | |
}, | |
{ | |
Name: "username", | |
Type: "string", | |
Value: v.From.Username, | |
}, | |
{ | |
Name: "room", | |
Type: "string", | |
Value: room, | |
}, | |
{ | |
Name: "read_by", | |
Type: "int", | |
Value: v.ReadBy, | |
}, | |
}, | |
} | |
mod.eventChan <- ev | |
} | |
// ReloadOptions parses the config options and initializes the Bee. | |
func (mod *GitterBee) ReloadOptions(options bees.BeeOptions) { | |
mod.SetOptions(options) | |
options.Bind("access_token", &mod.accessToken) | |
options.Bind("rooms", &mod.rooms) | |
mod.roomChans = make(map[string]chan interface{}) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2017 Christian Muehlhaeuser | |
* | |
* This program is free software: you can redistribute it and/or modify | |
* it under the terms of the GNU Affero General Public License as published | |
* by the Free Software Foundation, either version 3 of the License, or | |
* (at your option) any later version. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU Affero General Public License for more details. | |
* | |
* You should have received a copy of the GNU Affero General Public License | |
* along with this program. If not, see <http://www.gnu.org/licenses/>. | |
* | |
* Authors: | |
* Nicolas Martin <[email protected]> | |
* Christian Muehlhaeuser <[email protected]> | |
*/ | |
// Package gitterbee is a Bee that can interface with Gitter | |
package gitterbee | |
import ( | |
"github.com/muesli/beehive/bees" | |
) | |
// GitterBeeFactory is a factory for GitterBees | |
type GitterBeeFactory struct { | |
bees.BeeFactory | |
} | |
// New returns a new Bee instance configured with the supplied options. | |
func (factory *GitterBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { | |
bee := GitterBee{ | |
Bee: bees.NewBee(name, factory.ID(), description, options), | |
} | |
bee.ReloadOptions(options) | |
return &bee | |
} | |
// ID returns the ID of this Bee. | |
func (factory *GitterBeeFactory) ID() string { | |
return "gitterbee" | |
} | |
// Name returns the name of this Bee. | |
func (factory *GitterBeeFactory) Name() string { | |
return "Gitter" | |
} | |
// Description returns the desciption of this Bee. | |
func (factory *GitterBeeFactory) Description() string { | |
return "Interact with Gitter" | |
} | |
// Image returns the filename of an image for this Bee. | |
func (factory *GitterBeeFactory) Image() string { | |
return factory.ID() + ".png" | |
} | |
// LogoColor returns ther preferred logo background color (used by the admin interface). | |
func (factory *GitterBeeFactory) LogoColor() string { | |
return "#994499" | |
} | |
// Options returns the options available to configure this Bee. | |
func (factory *GitterBeeFactory) Options() []bees.BeeOptionDescriptor { | |
opts := []bees.BeeOptionDescriptor{ | |
{ | |
Name: "access_token", | |
Description: "Your Gitter access token", | |
Type: "string", | |
Mandatory: true, | |
}, | |
{ | |
Name: "rooms", | |
Description: "Rooms to join", | |
Type: "[]string", | |
Mandatory: false, | |
}, | |
} | |
return opts | |
} | |
// Events describes the available events provided by this Bee. | |
func (factory *GitterBeeFactory) Events() []bees.EventDescriptor { | |
events := []bees.EventDescriptor{ | |
{ | |
Namespace: factory.Name(), | |
Name: "message", | |
Description: "New message received", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "id", | |
Description: "ID of the message", | |
Type: "string", | |
}, | |
{ | |
Name: "text", | |
Description: "Text content of the message", | |
Type: "string", | |
}, | |
{ | |
Name: "username", | |
Description: "Username who sent the message", | |
Type: "string", | |
}, | |
{ | |
Name: "room", | |
Description: "Room the message was received in", | |
Type: "string", | |
}, | |
{ | |
Name: "read_by", | |
Description: "Number of users who have read the message", | |
Type: "int", | |
}, | |
}, | |
}, | |
/* { | |
Namespace: factory.Name(), | |
Name: "mention", | |
Description: "Mentions inside of a message", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "mention", | |
Description: "Username of the user who has been mentioned", | |
Type: "string", | |
}, | |
}, | |
}, | |
{ | |
Namespace: factory.Name(), | |
Name: "issue", | |
Description: "Issue referenced in a message", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "issue", | |
Description: "Number of the issue", | |
Type: "int", | |
}, | |
}, | |
},*/ | |
} | |
return events | |
} | |
// Actions describes the available actions provided by this Bee. | |
func (factory *GitterBeeFactory) Actions() []bees.ActionDescriptor { | |
actions := []bees.ActionDescriptor{ | |
{ | |
Namespace: factory.Name(), | |
Name: "send", | |
Description: "Sends a message into a room", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "room", | |
Description: "Which room to sent the message to", | |
Type: "string", | |
Mandatory: true, | |
}, | |
{ | |
Name: "message", | |
Description: "Message text", | |
Type: "string", | |
Mandatory: true, | |
}, | |
}, | |
}, | |
{ | |
Namespace: factory.Name(), | |
Name: "join", | |
Description: "Join a room on gitter", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "room", | |
Description: "Room to join", | |
Type: "string", | |
Mandatory: true, | |
}, | |
}, | |
}, | |
{ | |
Namespace: factory.Name(), | |
Name: "leave", | |
Description: "Leave a room on gitter", | |
Options: []bees.PlaceholderDescriptor{ | |
{ | |
Name: "room", | |
Description: "Room to leave", | |
Type: "string", | |
Mandatory: true, | |
}, | |
}, | |
}, | |
} | |
return actions | |
} | |
func init() { | |
f := GitterBeeFactory{} | |
bees.RegisterFactory(&f) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment