]> git.lizzy.rs Git - go-anidb.git/blob - udp.go
anidb: Initial attempt at high level AniDB library
[go-anidb.git] / udp.go
1 package anidb
2
3 import (
4         "github.com/Kovensky/go-anidb/udp"
5         "sync"
6         "time"
7 )
8
9 var banTime time.Time
10 var banTimeLock sync.Mutex
11
12 const banDuration = 30*time.Minute + 1*time.Second
13
14 // Returns whether the last UDP API access returned a 555 BANNED message.
15 func Banned() bool {
16         banTimeLock.Lock()
17         banTimeLock.Unlock()
18
19         return _banned()
20 }
21
22 func _banned() bool {
23         return time.Now().Sub(banTime) > banDuration
24 }
25
26 type paramSet struct {
27         cmd    string
28         params paramMap
29         ch     chan udpapi.APIReply
30 }
31
32 type udpWrap struct {
33         *udpapi.AniDBUDP
34
35         sendQueueCh chan paramSet
36
37         credentials *credentials
38         connected   bool
39 }
40
41 func newUDPWrap() *udpWrap {
42         u := &udpWrap{
43                 AniDBUDP:    udpapi.NewAniDBUDP(),
44                 sendQueueCh: make(chan paramSet, 10),
45         }
46         go u.sendQueue()
47         return u
48 }
49
50 type paramMap udpapi.ParamMap // shortcut
51
52 type bannedAPIReply struct {
53         udpapi.APIReply
54 }
55
56 func (r *bannedAPIReply) Code() int {
57         return 555
58 }
59 func (r *bannedAPIReply) Text() string {
60         return "BANNED"
61 }
62 func (r *bannedAPIReply) Error() error {
63         return &udpapi.APIError{Code: 555, Desc: "BANNED"}
64 }
65
66 var bannedReply udpapi.APIReply = &bannedAPIReply{}
67
68 func (udp *udpWrap) sendQueue() {
69         for set := range udp.sendQueueCh {
70                 reply := <-udp.AniDBUDP.SendRecv(set.cmd, udpapi.ParamMap(set.params))
71
72                 if reply.Error() == udpapi.TimeoutError {
73                         // retry
74                         go func(set paramSet) { udp.sendQueueCh <- set }(set)
75                         continue
76                 }
77
78                 switch reply.Code() {
79                 case 403, 501, 506: // not logged in, or session expired
80                         if err := udp.ReAuth(); err == nil {
81                                 // retry
82                                 go func(set paramSet) { udp.sendQueueCh <- set }(set)
83                                 continue
84                         }
85                 case 503, 504: // client library rejected
86                         panic(reply.Error())
87                 case 555: // IP (and user, possibly client) temporarily banned
88                         banTimeLock.Lock()
89
90                         banTime = time.Now()
91
92                         banTimeLock.Unlock()
93                 }
94                 set.ch <- reply
95                 close(set.ch)
96         }
97 }
98
99 func (udp *udpWrap) SendRecv(cmd string, params paramMap) <-chan udpapi.APIReply {
100         ch := make(chan udpapi.APIReply, 1)
101
102         banTimeLock.Lock()
103         defer banTimeLock.Unlock()
104         if _banned() {
105                 banTime = time.Time{}
106         } else {
107                 ch <- bannedReply
108                 close(ch)
109                 return ch
110         }
111
112         udp.sendQueueCh <- paramSet{
113                 cmd:    cmd,
114                 params: params,
115                 ch:     ch,
116         }
117
118         return ch
119 }