Skip to content
Extraits de code Groupes Projets
Valider 92e36e15 rédigé par Alexandre Morignot's avatar Alexandre Morignot
Parcourir les fichiers

First commit

parent
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
package bot
import (
"log"
"sync"
"github.com/mvdan/xurls"
)
type Bot interface {
Collection
ParseLine(author string, line string, contents chan Content) error
}
type PlayBot struct {
Collection
}
func NewPlayBot(source string, db Db) *PlayBot {
return &PlayBot{
Collection: &PlayBotCollection{
Source: source,
Db: db,
},
}
}
func (pb *PlayBot) ParseLine(author string, line string, contents chan Content) error {
urls := xurls.Strict.FindAllString(line, -1)
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go func(url string) {
defer wg.Done()
content, err := pb.Add(url)
if err != nil {
log.Print(err)
} else {
contents <- content
}
}(url)
}
wg.Wait()
close(contents)
return nil
}
package bot
import (
"log"
)
type Collection interface {
Add(url string) (Content, error)
Get()
}
type PlayBotCollection struct {
Source string
Db Db
}
func (pb *PlayBotCollection) Add(url string) (Content, error) {
log.Printf("%s: Add() %s", pb.Source, url)
content := Content{Title: url}
pb.Db.Create(content)
return Content{}, nil
}
func (*PlayBotCollection) Get() {
}
package bot
type Content struct {
Author string `gorm:"column:sender"`
Duration int
File string
Id int
IsBroken bool `gorm:"column:broken"`
IsCollection bool `gorm:"column:playlist"`
Source string `gorm:"column:type"`
SourceId string `gorm:"column:external_id"`
Title string
Url string
}
func (Content) Table() string {
return "playbot"
}
package bot
type DbParams struct {
Host string
Port string
User string
Password string
}
type Db interface {
Create(interface{}) Db
}
package bot
import (
"log"
)
type Factory interface {
GetBot(string) Bot
}
type playBotFactory struct{}
func NewPlayBotFactory(dbParams DbParams) *playBotFactory {
return &playBotFactory{}
}
func (*playBotFactory) GetBot(source string) Bot {
// give DB as arg
db := &DummyDb{}
return NewPlayBot(source, db)
}
type DummyDb struct{}
func (db *DummyDb) Create(value interface{}) Db {
log.Printf("Create(): %s", value)
return db
}
package bot
import (
"time"
)
type Post struct {
Id int
Date time.Time
Author string `gorm:"column:sender_irc"`
Source string `gorm:"column:chan"`
Content Content
Tag Tag
}
func (Post) TableName() string {
return "playbot_chan"
}
package bot
type Tag struct {
Tag string
ContentId int `gorm:"colmun:id"`
}
package main
import (
"flag"
"io/ioutil"
"log"
"gopkg.in/yaml.v2"
"git.iiens.net/morignot2011/playbot/bot"
"git.iiens.net/morignot2011/playbot/transport/irc"
)
type config struct {
Db bot.DbParams
Transport map[string]transportParams `yaml:"transports"`
}
type transportParams map[string]interface{}
func startTransport(name string, config transportParams, factory bot.Factory) chan bool {
transportType, ok := config["type"]
if !ok {
log.Fatalf("Missing type for transport %s", name)
}
c := make(chan bool)
switch transportType {
case "irc":
log.Printf("Start %s", name)
t, err := irc.New(name, config, factory, c)
if err != nil {
log.Fatalf("%s: %s", name, err)
}
if err := t.Run(); err != nil {
log.Fatalf("%s: %s", name, err)
}
}
return c
}
func main() {
var configFile = flag.String("config", "playbot.conf", "path to configuration file")
flag.Parse()
file, err := ioutil.ReadFile(*configFile)
if err != nil {
log.Fatal(err)
}
var config config
err = yaml.Unmarshal(file, &config)
quit := make(map[string](chan bool))
factory := bot.NewPlayBotFactory(config.Db)
for name, config := range config.Transport {
c := startTransport(name, config, factory)
quit[name] = c
}
for name, c := range quit {
<-c
log.Printf("%s has ended", name)
}
}
package test
import (
"reflect"
"sort"
"testing"
"git.iiens.net/morignot2011/playbot/bot"
)
func TestAdd(t *testing.T) {
db := &DummyDb{}
bot := bot.NewPlayBot("test", db)
content, err := bot.Add("http://www.youtube.com/watch?v=IiWapK6WQPg")
if err != nil {
t.Fatalf("Receive error %s", err)
}
if content.Author != "Delete" {
t.Error("invalid author")
}
if content.Duration != 286 {
t.Error("invalid duration")
}
// File
if content.Source != "youtube" {
t.Error("invalid source")
}
if content.SourceId != "IiWapK6WQPg" {
t.Error("invalid source id")
}
if content.Title != "Warface & Delete - The Truth" {
t.Error("invalid title")
}
if content.Url != "https://www.youtube.com/watch?v=IiWapK6WQPg" {
t.Error("invalid url")
}
if db.createCalls[0] != content {
t.Error("invalid call to db.Create")
}
}
func TestParseLine(t *testing.T) {
testCases := []struct {
msg string
expected []string
}{
{
msg: "this is a http://perdu.com test",
expected: []string{"http://perdu.com"},
},
{
msg: "nothing here",
expected: []string{},
},
{
msg: "some http://url.com #with #tags",
expected: []string{"http://url.com"},
},
{
msg: "http://two.com urls: http://second.com",
expected: []string{"http://second.com", "http://two.com"},
},
}
for _, c := range testCases {
fc := &FakeCollection{
AddCalls: []string{},
}
testBot := &bot.PlayBot{
Collection: fc,
}
contents := make(chan bot.Content)
go testBot.ParseLine("me", c.msg, contents)
for range contents {
}
sort.Strings(fc.AddCalls)
if !reflect.DeepEqual(fc.AddCalls, c.expected) {
t.Errorf("Expected %q but got %q", c.expected, fc.AddCalls)
}
}
}
package test
import (
"git.iiens.net/morignot2011/playbot/bot"
)
type DummyDb struct {
createCalls []bot.Content
}
func (db *DummyDb) Create(value interface{}) bot.Db {
db.createCalls = append(db.createCalls, value.(bot.Content))
return db
}
package test
import (
"git.iiens.net/morignot2011/playbot/bot"
)
type FakeCollection struct {
AddCalls []string
}
func (c *FakeCollection) Add(url string) (bot.Content, error) {
c.AddCalls = append(c.AddCalls, url)
return bot.Content{}, nil
}
func (*FakeCollection) Get() {
}
package transport
import (
"fmt"
)
type Error struct {
s string
}
func (e *Error) Error() string {
return e.s
}
type ConfigurationError struct {
field string
}
func NewConfigurationError(field string) *ConfigurationError {
return &ConfigurationError{field: field}
}
func (e *ConfigurationError) Error() string {
return fmt.Sprintf("Missing field %s", e.field)
}
type ConnectionError struct {
s string
}
func NewConnectionError(s string) *ConnectionError {
return &ConnectionError{s: s}
}
func (e *ConnectionError) Error() string {
return fmt.Sprintf("Connection error: %s", e.s)
}
package irc
import (
"git.iiens.net/morignot2011/playbot/bot"
irc "github.com/fluffle/goirc/client"
)
func (t *IrcTransport) connected(conn *irc.Conn, line *irc.Line) {
for _, channel := range t.channels {
t.Logger.Printf("Join %s", channel)
conn.Join(channel)
bot := t.botFactory.GetBot("irc.iiens.net")
t.bots[channel] = bot
bot.Add("lol.com")
}
}
func (t *IrcTransport) disconnected(conn *irc.Conn, line *irc.Line) {
t.quit <- true
}
func (t *IrcTransport) privmsg(conn *irc.Conn, line *irc.Line) {
channel := line.Target()
msg := line.Args[1]
b := t.bots[channel]
contents := make(chan bot.Content)
go b.ParseLine(line.Nick, msg, contents)
for content := range contents {
t.printContent(content)
}
}
package irc
import (
"crypto/tls"
"fmt"
"log"
"os"
"git.iiens.net/morignot2011/playbot/bot"
"git.iiens.net/morignot2011/playbot/transport"
irc "github.com/fluffle/goirc/client"
)
type IrcTransport struct {
transport.Base
bots map[string]bot.Bot
client *irc.Conn
channels []string
botFactory bot.Factory
quit chan bool
}
func New(name string, config map[string]interface{}, factory bot.Factory, quit chan bool) (transport.Transport, error) {
t := &IrcTransport{
bots: make(map[string]bot.Bot),
botFactory: factory,
quit: quit,
Base: transport.Base{
Logger: log.New(os.Stdout, name, log.LstdFlags),
Name: name,
},
}
cfg, err := t.newIrcConfig(config)
if err != nil {
return nil, err
}
t.client = irc.Client(cfg)
channels, ok := config["chans"]
if !ok {
return nil, transport.NewConfigurationError("chans")
}
for _, channel := range channels.([]interface{}) {
t.Logger.Print(channel)
t.channels = append(t.channels, channel.(string))
}
t.client.HandleFunc(irc.CONNECTED, t.connected)
t.client.HandleFunc(irc.DISCONNECTED, t.disconnected)
t.client.HandleFunc(irc.PRIVMSG, t.privmsg)
return t, nil
}
func (*IrcTransport) newIrcConfig(config map[string]interface{}) (*irc.Config, error) {
server, ok := config["server"]
if !ok {
return nil, transport.NewConfigurationError("server")
}
port, ok := config["port"]
if !ok {
return nil, transport.NewConfigurationError("port")
}
ssl, ok := config["ssl"]
if !ok {
ssl = false
}
insecure, ok := config["ssl_insecure"]
if !ok {
insecure = false
}
nick, ok := config["nick"]
if !ok {
nick = "PlayBot"
}
cfg := irc.NewConfig(nick.(string))
cfg.SSL = ssl.(bool)
if cfg.SSL {
cfg.SSLConfig = &tls.Config{
ServerName: server.(string),
InsecureSkipVerify: insecure.(bool),
}
}
cfg.Server = fmt.Sprintf("%s:%d", server, port)
cfg.NewNick = func(n string) string { return n + "_" }
return cfg, nil
}
func (t *IrcTransport) Run() error {
if err := t.client.Connect(); err != nil {
return transport.NewConnectionError(err.Error())
}
return nil
}
package irc
import (
"log"
"git.iiens.net/morignot2011/playbot/bot"
)
func (t *IrcTransport) printContent(content bot.Content) {
log.Printf("Print lol")
}
func (t *IrcTransport) printError(err error) {
log.Printf("Error: %s", err)
}
package transport
import (
"log"
)
type Transport interface {
Run() error
}
type Base struct {
Name string
Logger *log.Logger
}
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter