client updates

master
Jordan Orelli 10 years ago
parent 3fac9f5caf
commit 292313ad13

@ -1,12 +1,16 @@
package main package main
import ( import (
"bufio"
"code.google.com/p/go.crypto/ssh/terminal" "code.google.com/p/go.crypto/ssh/terminal"
"crypto/rsa" "crypto/rsa"
"fmt" "fmt"
"io" "io"
"net" "net"
"os" "os"
"strings"
"sync"
"unicode"
) )
type Auth struct { type Auth struct {
@ -24,24 +28,34 @@ 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{}
mu sync.Mutex
prompt string
line []rune
prev *terminal.State
} }
func (c *Client) dial() error { func (c *Client) dial() error {
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", c.host, c.port)) addr := fmt.Sprintf("%s:%d", c.host, c.port)
c.info("dialing %s", addr)
conn, err := net.Dial("tcp", addr)
if err != nil { if err != nil {
return fmt.Errorf("client unable to connect: %v", err) return fmt.Errorf("client unable to connect: %v", err)
} }
c.info("connected to %s", addr)
c.conn = conn c.conn = conn
c.prompt = fmt.Sprintf("%s> ", addr)
return nil return nil
} }
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)
return c.sendRequest(r) return c.sendRequest(r)
} }
@ -49,7 +63,33 @@ func (c *Client) sendRequest(r request) error {
return writeRequest(c.conn, r) return writeRequest(c.conn, r)
} }
func (c *Client) info(template string, args ...interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
c.trunc()
fmt.Print("\033[90m# ")
fmt.Printf(template, args...)
if !strings.HasSuffix(template, "\n") {
fmt.Print("\n")
}
fmt.Printf("\033[0m")
c.renderLine()
}
func (c *Client) trunc() {
fmt.Print("\r")
}
func (c *Client) err(template string, args ...interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
fmt.Printf(template, args...)
}
func (c *Client) run() { func (c *Client) run() {
go c.term()
if err := c.dial(); err != nil { if err := c.dial(); err != nil {
exit(1, "%v", err) exit(1, "%v", err)
} }
@ -57,7 +97,47 @@ func (c *Client) run() {
if err := c.handshake(); err != nil { if err := c.handshake(); err != nil {
exit(1, "%v", err) exit(1, "%v", err)
} }
c.term() <-c.done
if c.prev != nil {
terminal.Restore(0, c.prev)
}
}
func (c *Client) renderLine() {
fmt.Printf("\r%s%s", c.prompt, string(c.line))
}
func (c *Client) control(r rune) {
switch r {
case 13: // enter
c.enter()
case 12: // ctrl+l
c.clear()
case 3: // ctrl+c
c.eof()
case 4: // EOF
c.eof()
default:
c.info("control: %v %d %c", r, r, r)
}
}
func (c *Client) enter() {
fmt.Print("\n")
c.line = make([]rune, 0, 32)
c.renderLine()
}
func (c *Client) eof() {
fmt.Print("\r")
c.done <- 1
}
func (c *Client) clear() {
fmt.Print("\033[2J") // clear the screen
fmt.Print("\033[0;0f") // move to 0, 0
c.renderLine()
} }
func (c *Client) term() { func (c *Client) term() {
@ -65,19 +145,26 @@ func (c *Client) term() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
defer terminal.Restore(0, old) c.prev = old
defer close(c.done)
r := &ReadWriter{Reader: os.Stdin, Writer: os.Stdout} in := bufio.NewReader(os.Stdin)
term := terminal.NewTerminal(r, "> ") for {
r, _, err := in.ReadRune()
switch err {
case io.EOF:
return
case nil:
default:
c.err("error reading rune: %v", err)
}
line, err := term.ReadLine() if unicode.IsGraphic(r) {
switch err { c.line = append(c.line, r)
case io.EOF: c.renderLine()
return } else {
case nil: c.control(r)
fmt.Println(line) }
default:
exit(1, "error on line read: %v", err)
} }
} }
@ -96,6 +183,8 @@ func connect() {
host: options.host, host: options.host,
port: options.port, port: options.port,
nick: options.nick, nick: options.nick,
done: make(chan interface{}),
line: make([]rune, 0, 32),
} }
client.run() client.run()
} }

@ -41,6 +41,7 @@ func serve() {
if err != nil { if err != nil {
exit(1, "couldn't open tcp port for listening: %v", err) exit(1, "couldn't open tcp port for listening: %v", err)
} }
info_log.Printf("server listening: %s:%d", options.host, options.port)
for { for {
conn, err := listener.Accept() conn, err := listener.Accept()
if err != nil { if err != nil {

Loading…
Cancel
Save