From 4a7b05be36b96134b4dae3ca385e9bfbb797d531 Mon Sep 17 00:00:00 2001 From: "Andrew Gallant (Ocelot)" Date: Sat, 5 May 2012 02:56:15 -0400 Subject: oh momma. a lot of modifications and it appears to be working. w00t. --- nexgb/cookie.go | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 nexgb/cookie.go (limited to 'nexgb/cookie.go') diff --git a/nexgb/cookie.go b/nexgb/cookie.go new file mode 100644 index 0000000..502ccbf --- /dev/null +++ b/nexgb/cookie.go @@ -0,0 +1,111 @@ +package xgb + +import ( + "errors" +) + +type cookie struct { + Sequence uint16 + replyChan chan []byte + errorChan chan error + pingChan chan bool +} + +func (c *Conn) newCookie(checked, reply bool) cookie { + cookie := cookie{ + Sequence: c.newSequenceId(), + replyChan: nil, + errorChan: nil, + pingChan: nil, + } + + // There are four different kinds of cookies: + // Checked requests with replies get a reply channel and an error channel. + // Unchecked requests with replies get a reply channel and a ping channel. + // Checked requests w/o replies get a ping channel and an error channel. + // Unchecked requests w/o replies get no channels. + // The reply channel is used to send reply data. + // The error channel is used to send error data. + // The ping channel is used when one of the 'reply' or 'error' channels + // is missing but the other is present. The ping channel is way to force + // the blocking to stop and basically say "the error has been received + // in the main event loop" (when the ping channel is coupled with a reply + // channel) or "the request you made that has no reply was successful" + // (when the ping channel is coupled with an error channel). + if checked { + cookie.errorChan = make(chan error, 1) + if !reply { + cookie.pingChan = make(chan bool, 1) + } + } + if reply { + cookie.replyChan = make(chan []byte, 1) + if !checked { + cookie.pingChan = make(chan bool, 1) + } + } + + return cookie +} + +func (c cookie) reply() ([]byte, error) { + // checked + if c.errorChan != nil { + return c.replyChecked() + } + return c.replyUnchecked() +} + +func (c cookie) replyChecked() ([]byte, error) { + if c.replyChan == nil { + return nil, errors.New("Cannot call 'replyChecked' on a cookie that " + + "is not expecting a *reply* or an error.") + } + if c.errorChan == nil { + return nil, errors.New("Cannot call 'replyChecked' on a cookie that " + + "is not expecting a reply or an *error*.") + } + + select { + case reply := <-c.replyChan: + return reply, nil + case err := <-c.errorChan: + return nil, err + } + panic("unreachable") +} + +func (c cookie) replyUnchecked() ([]byte, error) { + if c.replyChan == nil { + return nil, errors.New("Cannot call 'replyUnchecked' on a cookie " + + "that is not expecting a *reply*.") + } + + select { + case reply := <-c.replyChan: + return reply, nil + case <-c.pingChan: + return nil, nil + } + panic("unreachable") +} + +func (c cookie) Check() error { + if c.replyChan != nil { + return errors.New("Cannot call 'Check' on a cookie that is " + + "expecting a *reply*. Use 'Reply' instead.") + } + if c.errorChan == nil { + return errors.New("Cannot call 'Check' on a cookie that is " + + "not expecting a possible *error*.") + } + + select { + case err := <-c.errorChan: + return err + case <-c.pingChan: + return nil + } + panic("unreachable") +} + -- cgit v1.2.3-70-g09d2