websocket -> json -> multi struct or multi websocket

294 views
Skip to first unread message

RoboTamer

unread,
Nov 29, 2013, 11:37:16 AM11/29/13
to golan...@googlegroups.com
I have to receive different type of data in json form / struct's from the client and was wondering if it would be better to create multiple websocket connections for each struct with the client, or is there a way to identify what struct a json string belongs to.
If there is no better way I am planning on checking the json string if it contains the expected struct fields.  

Jason Del Ponte

unread,
Nov 29, 2013, 1:24:58 PM11/29/13
to golan...@googlegroups.com
 The way I solved this for a websocket project i did a while ago was to create a single structure that contained all possible command/update messages as references.  When the JSON object was parsed it would fill one, or more of the command/update message fields within the message structure.  My code when then detect if that field had a reference, and if so it meant that the received message contained that command/update.

Example of the message structure: https://github.com/jasondelponte/Apollo/blob/master/messages.go  Sorry for the variable naming this was before i knew about `json:"<jsonname>"` way of naming variables for (de)encoding.  My solution broke down the message into categories, and allowed them to be handled off to handlers that understood those categories, and commands/message fields that were nil were not provided in the original json message.

type MessageIn struct {
        ReqId string
        Act *MsgPlayerAction
}

type MsgPlayerAction struct {
        W *MsgPartActionWorld
        G *MsgPartActionGame
}


Looking back on this now using something like a MessageId might of simplified checking which message was received instead of comparing if a fields reference wasn't nil, but I still think the fields as pointer references was the way to go in my case.  If that sub object in the JSON didn't exist the reference would be nil.

RoboTamer

unread,
Nov 29, 2013, 2:23:33 PM11/29/13
to golan...@googlegroups.com
I am glad I asked, good idea, one struct for all. Thank you.

RoboTamer

unread,
Nov 29, 2013, 2:45:28 PM11/29/13
to golan...@googlegroups.com

Is there a reason why you didn't do something like this?

type json struct {
        M MessageIn
        A MsgPlayerAction
}

Jason Del Ponte

unread,
Nov 29, 2013, 4:20:09 PM11/29/13
to golan...@googlegroups.com
type json struct {
        M MessageIn
        A MsgPlayerAction
}

Would always have values for M and A. Even if they were not provided in the JSON object received
If the field is not a pointer reference then the json decoder will populate the field's value
with its defaults, and you would need another system other than checking for nil to know if
a specific message category was received.

The following would work though. MessageIn wasn't the best example since there was only one type of
message category that could be received.
type json struct {
        M *MessageIn
        A *MsgPlayerAction
}

MessageGameUpdate might be a little better example since it shows multiple items that could
be populated. https://github.com/jasondelponte/Apollo/blob/master/messages.go#L58.
Once the MessageGameUpdate is encoded to JSON only the fields that aren't nil will
be present in the JSON object when its received.

I've been thinking of a couple other ideas, but they seem to all to start to get a bit
hacky and fragile. Like custom message format where the message id is outside of the json blob.
ex: MsgId:<json>:MsgTerm. Could be useful for really long messages or poor network connection
since websocket is streaming

If you really have no idea what kind of message you'll be receiving like when using a third party
client/api a map[string]interface{} might be the easiest solution to determine the message received.
So that it can parsed a second time using a more specific structure.

RoboTamer

unread,
Dec 1, 2013, 6:55:28 AM12/1/13
to golan...@googlegroups.com

You are right, map[string]interface{} sounds like to cleanest solution.

Could look something like following?


    type message struct {
        Type, Text string
    }
    var m = make(map[string]interface{})
    m["message"] = message{"error","You can't do that!"}

aburs...@gmail.com

unread,
Dec 1, 2013, 7:35:21 AM12/1/13
to golan...@googlegroups.com
It's not perfect, but you might want to check out mapstructure.  It doesn't support pointers in structs, but it might suit your needs and can do some pretty handy type conversions if your input is originating from a weakly typed language.


On Friday, November 29, 2013 8:37:16 AM UTC-8, RoboTamer wrote:

RoboTamer

unread,
Dec 3, 2013, 8:13:49 PM12/3/13
to golan...@googlegroups.com, aburs...@gmail.com

Thank you but there is no need for reflection
Here is how I did this:


package main
import(
    "fmt"
    "log"
    "encoding/json"
)
type Envelop struct {
    Usr *User
    Msg *Message
}
type Message struct {
    Type, Text string
}
type User struct {
    Username, Password, Email string
}
func main(){
    var m = new(Envelop)
    m.Msg = &Message{"error","You can't do that!"}
    j, err := json.Marshal(&m)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("Struct: %s\n", m)
    fmt.Printf("JsonIn: %s\n", j)
    var mm Envelop
    err = json.Unmarshal(j, &mm)
    if err != nil {
        fmt.Println(err)
    }
        
    if mm.Msg != nil {
        var m *Message
        m = mm.Msg
        log.Printf("%s: %s", m.Type, m.Text)
    } 
}
Reply all
Reply to author
Forward
0 new messages