From 7d8c23038f55c95370a93a98ef89644decefde6e Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Fri, 26 Dec 2014 23:48:40 -0500 Subject: [PATCH] client can now block waiting for responses --- client.go | 105 ++++++++++++++++++++++++++++------------------------- request.go | 7 +++- server.go | 38 ++++++++----------- 3 files changed, 77 insertions(+), 73 deletions(-) diff --git a/client.go b/client.go index 90a209a..1b77f35 100644 --- a/client.go +++ b/client.go @@ -33,17 +33,19 @@ type ReadWriter struct { } type Client struct { - key *rsa.PrivateKey - host string - port int - nick string - conn net.Conn - done chan interface{} - mu sync.Mutex - prompt string - line []rune - prev *terminal.State - keyStore map[string]rsa.PublicKey + key *rsa.PrivateKey + host string + port int + nick string + conn net.Conn + done chan interface{} + mu sync.Mutex + prompt string + line []rune + prev *terminal.State + keyStore map[string]rsa.PublicKey + requestCount int + outstanding map[int]chan Envelope } // establishes a connection to the server @@ -83,27 +85,14 @@ func (c *Client) handleMessages() { // handle a message received from the server func (c *Client) handleMessage(m Envelope) error { - switch m.Kind { - case "meta": - return c.handleMeta(m.Body) - case "note": - return c.handleNote(m.Body) - case "list-notes": - return c.handleListNotes(m.Body) - case "key-response": - return c.handleKeyResponse(m.Body) - default: - return fmt.Errorf("received message of unsupported type: %v", m.Kind) - } -} - -// handles a meta message; that is, a message that is shown to the user -func (c *Client) handleMeta(body json.RawMessage) error { - var meta Meta - if err := json.Unmarshal(body, &meta); err != nil { - return fmt.Errorf("unable to unmarshal meta message: %v", err) - } - c.info("message from server: %v", meta) + res, ok := c.outstanding[m.Id] + if !ok { + c.info("%v", m) + c.err("received message corresponding to no known request id: %d", m.Id) + return fmt.Errorf("no such id: %d", m.Id) + } + res <- m + close(res) return nil } @@ -173,23 +162,28 @@ func (c *Client) handleListNotes(raw json.RawMessage) error { func (c *Client) handshake() error { r := &Auth{Nick: c.nick, Key: c.key.PublicKey} c.info("authenticating as %s", c.nick) - return c.sendRequest(r) + _, err := c.sendRequest(r) + return err } -func (c *Client) sendRequest(r request) error { - e, err := wrapRequest(r) +func (c *Client) sendRequest(r request) (chan Envelope, error) { + e, err := wrapRequest(c.requestCount, r) if err != nil { - return err + return nil, err } b, err := json.Marshal(e) if err != nil { - return err + return nil, err } + + res := make(chan Envelope, 1) + c.outstanding[c.requestCount] = res + c.requestCount++ c.info("sending json request: %s", b) if _, err := c.conn.Write(b); err != nil { - return err + return nil, err } - return nil + return res, nil } func (c *Client) info(template string, args ...interface{}) { @@ -315,7 +309,7 @@ func (c *Client) createNote(args []string) { c.err("%v", err) return } - if err := c.sendRequest(note); err != nil { + if _, err := c.sendRequest(note); err != nil { c.err("error sending note: %v", err) } } @@ -330,15 +324,23 @@ func (c *Client) getNote(args []string) { c.err("that doesn't look like an int: %v", err) return } - if err := c.sendRequest(GetNoteRequest(id)); err != nil { + res, err := c.sendRequest(GetNoteRequest(id)) + if err != nil { c.err("couldn't request note: %v", err) return } + e := <-res + c.handleNote(e.Body) } func (c *Client) listNotes(args []string) { r := &ListNotes{N: 10} - c.sendRequest(r) + res, err := c.sendRequest(r) + if err != nil { + c.err("%v", err) + } + e := <-res + c.handleListNotes(e.Body) } func (c *Client) encryptNote(title string, message []rune) (*EncryptedNote, error) { @@ -390,10 +392,13 @@ func (c *Client) getKey(args []string) { return } req := KeyRequest(args[0]) - if err := c.sendRequest(req); err != nil { + res, err := c.sendRequest(req) + if err != nil { c.err("couldn't send key request: %v", err) return } + e := <-res + c.handleKeyResponse(e.Body) } func (c *Client) saveKey(nick string, key rsa.PublicKey) { @@ -571,12 +576,14 @@ func connect() { } client := &Client{ - key: key, - host: options.host, - port: options.port, - nick: options.nick, - done: make(chan interface{}), - line: make([]rune, 0, 32), + key: key, + host: options.host, + port: options.port, + nick: options.nick, + done: make(chan interface{}), + line: make([]rune, 0, 32), + keyStore: make(map[string]rsa.PublicKey, 8), + outstanding: make(map[int]chan Envelope), } client.run() } diff --git a/request.go b/request.go index 5aabd68..72f3eca 100644 --- a/request.go +++ b/request.go @@ -8,6 +8,7 @@ import ( ) type Envelope struct { + Id int Kind string Body json.RawMessage } @@ -16,24 +17,26 @@ type request interface { Kind() string } -func wrapRequest(r request) (*Envelope, error) { +func wrapRequest(id int, r request) (*Envelope, error) { b, err := json.Marshal(r) if err != nil { return nil, fmt.Errorf("unable to wrap request: %v", err) } return &Envelope{ + Id: id, Kind: r.Kind(), Body: b, }, nil } -func writeRequest(w io.Writer, r request) error { +func writeRequest(w io.Writer, id int, r request) error { b, err := json.Marshal(r) if err != nil { return fmt.Errorf("unable to marshal request: %v", err) } msg := json.RawMessage(b) e := &Envelope{ + Id: id, Kind: r.Kind(), Body: msg, } diff --git a/server.go b/server.go index 8948fab..c86fec7 100644 --- a/server.go +++ b/server.go @@ -35,42 +35,36 @@ type serverConnection struct { db *userdb } -func (s *serverConnection) sendMeta(template string, args ...interface{}) { - m := Meta(fmt.Sprintf(template, args...)) - if err := s.sendRequest(m); err != nil { - error_log.Printf("error sending message to client: %v", err) - } -} - -func (s *serverConnection) sendRequest(r request) error { - return writeRequest(s.conn, r) +func (s *serverConnection) sendResponse(id int, r request) error { + return writeRequest(s.conn, id, r) } func (s *serverConnection) handleRequest(request Envelope) error { + info_log.Printf("handle request #%d", request.Id) switch request.Kind { case "auth": - return s.handleAuthRequest(request.Body) + return s.handleAuthRequest(request.Id, request.Body) case "note": - return s.handleNoteRequest(request.Body) + return s.handleNoteRequest(request.Id, request.Body) case "get-note": - return s.handleGetNoteRequest(request.Body) + return s.handleGetNoteRequest(request.Id, request.Body) case "list-notes": - return s.handleListNotesRequest(request.Body) + return s.handleListNotesRequest(request.Id, request.Body) case "key": - return s.handleKeyRequest(request.Body) + return s.handleKeyRequest(request.Id, request.Body) default: return fmt.Errorf("no such request type: %v", request.Kind) } } -func (s *serverConnection) handleAuthRequest(body json.RawMessage) error { +func (s *serverConnection) handleAuthRequest(requestId int, body json.RawMessage) error { var auth Auth if err := json.Unmarshal(body, &auth); err != nil { return fmt.Errorf("bad auth request: %v", err) } s.nick = auth.Nick s.key = auth.Key - s.sendMeta("hello, %s", auth.Nick) + // s.sendMeta("hello, %s", auth.Nick) if err := s.openDB(); err != nil { error_log.Printf("failed to open database: %v", err) } @@ -112,7 +106,7 @@ func (s *serverConnection) handleAuthRequest(body json.RawMessage) error { return nil } -func (s *serverConnection) handleNoteRequest(body json.RawMessage) error { +func (s *serverConnection) handleNoteRequest(requestId int, body json.RawMessage) error { r := util.BytesPrefix([]byte("notes/")) it := s.db.NewIterator(r, nil) defer it.Release() @@ -135,7 +129,7 @@ func (s *serverConnection) handleNoteRequest(body json.RawMessage) error { return nil } -func (s *serverConnection) handleGetNoteRequest(body json.RawMessage) error { +func (s *serverConnection) handleGetNoteRequest(requestId int, body json.RawMessage) error { var req GetNoteRequest if err := json.Unmarshal(body, &req); err != nil { return fmt.Errorf("bad getnote request: %v", err) @@ -155,7 +149,7 @@ func (s *serverConnection) handleGetNoteRequest(body json.RawMessage) error { return nil } -func (s *serverConnection) handleListNotesRequest(body json.RawMessage) error { +func (s *serverConnection) handleListNotesRequest(requestId int, body json.RawMessage) error { r := util.BytesPrefix([]byte("notes/")) it := s.db.NewIterator(r, nil) @@ -193,10 +187,10 @@ func (s *serverConnection) handleListNotesRequest(body json.RawMessage) error { if err := it.Error(); err != nil { return fmt.Errorf("error reading listnotes from db: %v", err) } - return s.sendRequest(notes) + return s.sendResponse(requestId, notes) } -func (s *serverConnection) handleKeyRequest(body json.RawMessage) error { +func (s *serverConnection) handleKeyRequest(requestId int, body json.RawMessage) error { var req KeyRequest if err := json.Unmarshal(body, &req); err != nil { error_log.Printf("unable to read key request: %v", err) @@ -211,7 +205,7 @@ func (s *serverConnection) handleKeyRequest(body json.RawMessage) error { Nick: req.Nick(), Key: *key, } - return s.sendRequest(res) + return s.sendResponse(requestId, res) } func (s *serverConnection) openDB() error {