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 {
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()
}

@ -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,
}

@ -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 {

Loading…
Cancel
Save