89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
|
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,
|
||
|
}
|
||
|
}
|