client can now block waiting for responses

master
Jordan Orelli 10 years ago
parent 83f5585c10
commit 7d8c23038f

@ -33,17 +33,19 @@ type ReadWriter struct {
} }
type Client struct { type Client struct {
key *rsa.PrivateKey key *rsa.PrivateKey
host string host string
port int port int
nick string nick string
conn net.Conn conn net.Conn
done chan interface{} done chan interface{}
mu sync.Mutex mu sync.Mutex
prompt string prompt string
line []rune line []rune
prev *terminal.State prev *terminal.State
keyStore map[string]rsa.PublicKey keyStore map[string]rsa.PublicKey
requestCount int
outstanding map[int]chan Envelope
} }
// establishes a connection to the server // establishes a connection to the server
@ -83,27 +85,14 @@ func (c *Client) handleMessages() {
// handle a message received from the server // handle a message received from the server
func (c *Client) handleMessage(m Envelope) error { func (c *Client) handleMessage(m Envelope) error {
switch m.Kind { res, ok := c.outstanding[m.Id]
case "meta": if !ok {
return c.handleMeta(m.Body) c.info("%v", m)
case "note": c.err("received message corresponding to no known request id: %d", m.Id)
return c.handleNote(m.Body) return fmt.Errorf("no such id: %d", m.Id)
case "list-notes": }
return c.handleListNotes(m.Body) res <- m
case "key-response": close(res)
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)
return nil return nil
} }
@ -173,23 +162,28 @@ func (c *Client) handleListNotes(raw json.RawMessage) error {
func (c *Client) handshake() error { func (c *Client) handshake() error {
r := &Auth{Nick: c.nick, Key: c.key.PublicKey} r := &Auth{Nick: c.nick, Key: c.key.PublicKey}
c.info("authenticating as %s", c.nick) c.info("authenticating as %s", c.nick)
return c.sendRequest(r) _, err := c.sendRequest(r)
return err
} }
func (c *Client) sendRequest(r request) error { func (c *Client) sendRequest(r request) (chan Envelope, error) {
e, err := wrapRequest(r) e, err := wrapRequest(c.requestCount, r)
if err != nil { if err != nil {
return err return nil, err
} }
b, err := json.Marshal(e) b, err := json.Marshal(e)
if err != nil { 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) c.info("sending json request: %s", b)
if _, err := c.conn.Write(b); err != nil { 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{}) { func (c *Client) info(template string, args ...interface{}) {
@ -315,7 +309,7 @@ func (c *Client) createNote(args []string) {
c.err("%v", err) c.err("%v", err)
return return
} }
if err := c.sendRequest(note); err != nil { if _, err := c.sendRequest(note); err != nil {
c.err("error sending note: %v", err) 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) c.err("that doesn't look like an int: %v", err)
return 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) c.err("couldn't request note: %v", err)
return return
} }
e := <-res
c.handleNote(e.Body)
} }
func (c *Client) listNotes(args []string) { func (c *Client) listNotes(args []string) {
r := &ListNotes{N: 10} 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) { func (c *Client) encryptNote(title string, message []rune) (*EncryptedNote, error) {
@ -390,10 +392,13 @@ func (c *Client) getKey(args []string) {
return return
} }
req := KeyRequest(args[0]) 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) c.err("couldn't send key request: %v", err)
return return
} }
e := <-res
c.handleKeyResponse(e.Body)
} }
func (c *Client) saveKey(nick string, key rsa.PublicKey) { func (c *Client) saveKey(nick string, key rsa.PublicKey) {
@ -571,12 +576,14 @@ func connect() {
} }
client := &Client{ client := &Client{
key: key, key: key,
host: options.host, host: options.host,
port: options.port, port: options.port,
nick: options.nick, nick: options.nick,
done: make(chan interface{}), done: make(chan interface{}),
line: make([]rune, 0, 32), line: make([]rune, 0, 32),
keyStore: make(map[string]rsa.PublicKey, 8),
outstanding: make(map[int]chan Envelope),
} }
client.run() client.run()
} }

@ -8,6 +8,7 @@ import (
) )
type Envelope struct { type Envelope struct {
Id int
Kind string Kind string
Body json.RawMessage Body json.RawMessage
} }
@ -16,24 +17,26 @@ type request interface {
Kind() string Kind() string
} }
func wrapRequest(r request) (*Envelope, error) { func wrapRequest(id int, r request) (*Envelope, error) {
b, err := json.Marshal(r) b, err := json.Marshal(r)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to wrap request: %v", err) return nil, fmt.Errorf("unable to wrap request: %v", err)
} }
return &Envelope{ return &Envelope{
Id: id,
Kind: r.Kind(), Kind: r.Kind(),
Body: b, Body: b,
}, nil }, nil
} }
func writeRequest(w io.Writer, r request) error { func writeRequest(w io.Writer, id int, r request) error {
b, err := json.Marshal(r) b, err := json.Marshal(r)
if err != nil { if err != nil {
return fmt.Errorf("unable to marshal request: %v", err) return fmt.Errorf("unable to marshal request: %v", err)
} }
msg := json.RawMessage(b) msg := json.RawMessage(b)
e := &Envelope{ e := &Envelope{
Id: id,
Kind: r.Kind(), Kind: r.Kind(),
Body: msg, Body: msg,
} }

@ -35,42 +35,36 @@ type serverConnection struct {
db *userdb db *userdb
} }
func (s *serverConnection) sendMeta(template string, args ...interface{}) { func (s *serverConnection) sendResponse(id int, r request) error {
m := Meta(fmt.Sprintf(template, args...)) return writeRequest(s.conn, id, r)
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) handleRequest(request Envelope) error { func (s *serverConnection) handleRequest(request Envelope) error {
info_log.Printf("handle request #%d", request.Id)
switch request.Kind { switch request.Kind {
case "auth": case "auth":
return s.handleAuthRequest(request.Body) return s.handleAuthRequest(request.Id, request.Body)
case "note": case "note":
return s.handleNoteRequest(request.Body) return s.handleNoteRequest(request.Id, request.Body)
case "get-note": case "get-note":
return s.handleGetNoteRequest(request.Body) return s.handleGetNoteRequest(request.Id, request.Body)
case "list-notes": case "list-notes":
return s.handleListNotesRequest(request.Body) return s.handleListNotesRequest(request.Id, request.Body)
case "key": case "key":
return s.handleKeyRequest(request.Body) return s.handleKeyRequest(request.Id, request.Body)
default: default:
return fmt.Errorf("no such request type: %v", request.Kind) 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 var auth Auth
if err := json.Unmarshal(body, &auth); err != nil { if err := json.Unmarshal(body, &auth); err != nil {
return fmt.Errorf("bad auth request: %v", err) return fmt.Errorf("bad auth request: %v", err)
} }
s.nick = auth.Nick s.nick = auth.Nick
s.key = auth.Key s.key = auth.Key
s.sendMeta("hello, %s", auth.Nick) // s.sendMeta("hello, %s", auth.Nick)
if err := s.openDB(); err != nil { if err := s.openDB(); err != nil {
error_log.Printf("failed to open database: %v", err) error_log.Printf("failed to open database: %v", err)
} }
@ -112,7 +106,7 @@ func (s *serverConnection) handleAuthRequest(body json.RawMessage) error {
return nil 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/")) r := util.BytesPrefix([]byte("notes/"))
it := s.db.NewIterator(r, nil) it := s.db.NewIterator(r, nil)
defer it.Release() defer it.Release()
@ -135,7 +129,7 @@ func (s *serverConnection) handleNoteRequest(body json.RawMessage) error {
return nil return nil
} }
func (s *serverConnection) handleGetNoteRequest(body json.RawMessage) error { func (s *serverConnection) handleGetNoteRequest(requestId int, body json.RawMessage) error {
var req GetNoteRequest var req GetNoteRequest
if err := json.Unmarshal(body, &req); err != nil { if err := json.Unmarshal(body, &req); err != nil {
return fmt.Errorf("bad getnote request: %v", err) return fmt.Errorf("bad getnote request: %v", err)
@ -155,7 +149,7 @@ func (s *serverConnection) handleGetNoteRequest(body json.RawMessage) error {
return nil 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/")) r := util.BytesPrefix([]byte("notes/"))
it := s.db.NewIterator(r, nil) it := s.db.NewIterator(r, nil)
@ -193,10 +187,10 @@ func (s *serverConnection) handleListNotesRequest(body json.RawMessage) error {
if err := it.Error(); err != nil { if err := it.Error(); err != nil {
return fmt.Errorf("error reading listnotes from db: %v", err) 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 var req KeyRequest
if err := json.Unmarshal(body, &req); err != nil { if err := json.Unmarshal(body, &req); err != nil {
error_log.Printf("unable to read key request: %v", err) 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(), Nick: req.Nick(),
Key: *key, Key: *key,
} }
return s.sendRequest(res) return s.sendResponse(requestId, res)
} }
func (s *serverConnection) openDB() error { func (s *serverConnection) openDB() error {

Loading…
Cancel
Save