tcp.go 1.8 KB

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