irc-medialink/manager/parser.go

89 lines
1.8 KiB
Go
Raw Normal View History

package manager
import (
"errors"
"log"
"net/url"
"reflect"
"github.com/icedream/irc-medialink/parsers"
)
var (
ErrAlreadyLoaded = errors.New("Already loaded.")
)
type Parser interface {
Init() error
Name() string
Parse(u *url.URL, referer *url.URL) parsers.ParseResult
}
func (m *Manager) GetParsers() []Parser {
m.stateLock.RLock()
defer m.stateLock.RUnlock()
result := make([]Parser, len(m.registeredParsers))
copy(result, m.registeredParsers)
return result
}
func (m *Manager) RegisterParser(parser Parser) error {
m.stateLock.Lock()
defer m.stateLock.Unlock()
// Make sure that parser hasn't already been loaded in some way or another
t := reflect.TypeOf(parser)
for _, p := range m.registeredParsers {
if reflect.TypeOf(p) == t {
return ErrAlreadyLoaded
}
}
// Initialize parser
log.Printf("Initializing %s parser...", parser.Name())
if err := parser.Init(); err != nil {
return err
}
m.registeredParsers = append(m.registeredParsers, parser)
log.Printf("Registered %s parser!", parser.Name())
return nil
}
func (m *Manager) Parse(u *url.URL) (string, parsers.ParseResult) {
var oldU *url.URL
attempt := 0
followLoop:
for u != nil {
log.Printf("Parsing %s (referer %s)...", u, oldU)
attempt++
if attempt > 15 {
log.Printf("WARNING: Potential infinite loop for url %s, abort parsing", u)
break
}
for _, p := range m.GetParsers() {
r := p.Parse(u, oldU)
if r.Ignored {
continue
}
if r.FollowUrl != nil {
if *u == *r.FollowUrl {
log.Printf("WARNING: Ignoring request to follow to same URL, ignoring.")
break followLoop
}
oldU, u = u, r.FollowUrl
continue followLoop
}
return p.Name(), r
}
u = nil
}
// No parser matches, link ignored
return "", parsers.ParseResult{
Ignored: true,
}
}