The Codec type

The Message and JSON objects are both instances of the type Codec. This type is defined by

  1. type Codec struct {
  2. Marshal func(v interface{}) (data []byte, payloadType byte, err error)
  3. Unmarshal func(data []byte, payloadType byte, v interface{}) (err error)
  4. }

The type Codec implements the Send and Receive methods used earlier.

It is likely that websockets will also be used to exchange XML data. We can build an XML Codec object by wrapping the XML marshal and unmarshal methods discussed in Chapter 12: XML to give a suitable Codec object.

We can create a XMLCodec package in this way:

  1. package xmlcodec
  2. import (
  3. "encoding/xml"
  4. "golang.org/x/net/websocket"
  5. )
  6. func xmlMarshal(v interface{}) (msg []byte, payloadType byte, err error) {
  7. //buff := &bytes.Buffer{}
  8. msg, err = xml.Marshal(v)
  9. //msgRet := buff.Bytes()
  10. return msg, websocket.TextFrame, nil
  11. }
  12. func xmlUnmarshal(msg []byte, payloadType byte, v interface{}) (err error) {
  13. // r := bytes.NewBuffer(msg)
  14. err = xml.Unmarshal(msg, v)
  15. return err
  16. }
  17. var XMLCodec = websocket.Codec{xmlMarshal, xmlUnmarshal}

We can then serialise Go objects such as a Person into an XML document and send it from a client to a server by

  1. /* PersonClientXML
  2. */
  3. package main
  4. import (
  5. "golang.org/x/net/websocket"
  6. "fmt"
  7. "os"
  8. "xmlcodec"
  9. )
  10. type Person struct {
  11. Name string
  12. Emails []string
  13. }
  14. func main() {
  15. if len(os.Args) != 2 {
  16. fmt.Println("Usage: ", os.Args[0], "ws://host:port")
  17. os.Exit(1)
  18. }
  19. service := os.Args[1]
  20. conn, err := websocket.Dial(service, "", "http://localhost")
  21. checkError(err)
  22. person := Person{Name: "Jan",
  23. Emails: []string{"ja@newmarch.name", "jan.newmarch@gmail.com"},
  24. }
  25. err = xmlcodec.XMLCodec.Send(conn, person)
  26. if err != nil {
  27. fmt.Println("Couldn't send msg " + err.Error())
  28. }
  29. os.Exit(0)
  30. }
  31. func checkError(err error) {
  32. if err != nil {
  33. fmt.Println("Fatal error ", err.Error())
  34. os.Exit(1)
  35. }
  36. }

A server which receives this and just prints information to the console is

  1. /* PersonServerXML
  2. */
  3. package main
  4. import (
  5. "golang.org/x/net/websocket"
  6. "fmt"
  7. "net/http"
  8. "os"
  9. "xmlcodec"
  10. )
  11. type Person struct {
  12. Name string
  13. Emails []string
  14. }
  15. func ReceivePerson(ws *websocket.Conn) {
  16. var person Person
  17. err := xmlcodec.XMLCodec.Receive(ws, &person)
  18. if err != nil {
  19. fmt.Println("Can't receive")
  20. } else {
  21. fmt.Println("Name: " + person.Name)
  22. for _, e := range person.Emails {
  23. fmt.Println("An email: " + e)
  24. }
  25. }
  26. }
  27. func main() {
  28. http.Handle("/", websocket.Handler(ReceivePerson))
  29. err := http.ListenAndServe(":12345", nil)
  30. checkError(err)
  31. }
  32. func checkError(err error) {
  33. if err != nil {
  34. fmt.Println("Fatal error ", err.Error())
  35. os.Exit(1)
  36. }
  37. }