tcp.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package rcli
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "log"
  9. "net"
  10. )
  11. // Connect to a remote endpoint using protocol `proto` and address `addr`,
  12. // issue a single call, and return the result.
  13. // `proto` may be "tcp", "unix", etc. See the `net` package for available protocols.
  14. func Call(proto, addr string, args ...string) (*net.TCPConn, error) {
  15. cmd, err := json.Marshal(args)
  16. if err != nil {
  17. return nil, err
  18. }
  19. conn, err := net.Dial(proto, addr)
  20. if err != nil {
  21. return nil, err
  22. }
  23. if _, err := fmt.Fprintln(conn, string(cmd)); err != nil {
  24. return nil, err
  25. }
  26. return conn.(*net.TCPConn), nil
  27. }
  28. // Listen on `addr`, using protocol `proto`, for incoming rcli calls,
  29. // and pass them to `service`.
  30. func ListenAndServe(proto, addr string, service Service) error {
  31. listener, err := net.Listen(proto, addr)
  32. if err != nil {
  33. return err
  34. }
  35. log.Printf("Listening for RCLI/%s on %s\n", proto, addr)
  36. defer listener.Close()
  37. for {
  38. if conn, err := listener.Accept(); err != nil {
  39. return err
  40. } else {
  41. go func() {
  42. if err := Serve(conn, service); err != nil {
  43. log.Printf("Error: " + err.Error() + "\n")
  44. fmt.Fprintf(conn, "Error: "+err.Error()+"\n")
  45. }
  46. conn.Close()
  47. }()
  48. }
  49. }
  50. return nil
  51. }
  52. // Parse an rcli call on a new connection, and pass it to `service` if it
  53. // is valid.
  54. func Serve(conn io.ReadWriter, service Service) error {
  55. r := bufio.NewReader(conn)
  56. var args []string
  57. if line, err := r.ReadString('\n'); err != nil {
  58. return err
  59. } else if err := json.Unmarshal([]byte(line), &args); err != nil {
  60. return err
  61. } else {
  62. return call(service, ioutil.NopCloser(r), conn, args...)
  63. }
  64. return nil
  65. }