Home > Software engineering >  Getting values inside an unmarshalled interface
Getting values inside an unmarshalled interface

Time:06-14

I have a websocket client that receives multiple data types. A function unmarshals json received from the server into different structs depending on the data received. The struct is then returned as an interface through a channel to my main file. Since i receive multiple data types from the server, I am not able to specify the exact return value of my parsing function.

With the data in my main file, I would like to have a way to be able to then go through the different values in the data. Since I am returning an interface, this seems impossible to do. Whenever i try to index the interface, I receive an error saying c.VALUE undefined (type interface{} has no field or method VALUE).

I feel like I'm not doing something right here. The 2 solutions I've thought about so far are:

  1. having my channel value be a generic and my listen & JSON decoder funcs (these are all put below) all return a generic or
  2. create an interface with methods. My channel would be of this type and again, my listen & JSON decoder funcs would return this interface.

I'm not sure if either of these ways would actually solve my issue, though. I also don't know if there is one way that would be more performant compared to other ways.

Here is my code to better understand the issue

func main() {
    // check if in production or testing mode
    var testing bool = true // default to testing
    args := os.Args
    isTesting(args, &testing, &stored_data.Base_currency)

    // go routine handler
    comms := make(chan os.Signal, 1)
    signal.Notify(comms, os.Interrupt, syscall.SIGTERM)
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    var wg sync.WaitGroup

    // set ohlc interval and pairs
    OHLCinterval := 5
    pairs := []string{"BTC/"   stored_data.Base_currency, "EOS/"   stored_data.Base_currency}

    // create ws connections
    pubSocket, err := ws_client.ConnectToServer("public", testing)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    // create websocket channels
    pubCh := make(chan interface{})
    defer close(pubCh)

    // listen to websocket connections
    wg.Add(1)
    go pubSocket.PubListen(ctx, &wg, pubCh, testing)

    // connect to data streams
    pubSocket.SubscribeToOHLC(pairs, OHLCinterval)

    // listen to public socket
    go func() {
        for c := range pubCh {
            fmt.Println(c) // This is where I would like to be able to go through my data more thoroughly
        }
    }()

    <-comms
    cancel()
    wg.Wait()
}

Here is what happens in the PubListen function and my JSON decoding function

func (socket *Socket) PubListen(ctx context.Context, wg *sync.WaitGroup, ch chan interface{}, testing bool) {
    defer wg.Done()
    defer socket.Close()
    var res interface{}

    socket.OnTextMessage = func(message string, socket Socket) {
        res = pubJsonDecoder(message, testing)
        ch <- res
    }
    <-ctx.Done()
    log.Println("closing public socket")
    return
}

func pubJsonDecoder(response string, testing bool) interface{} {
    var resp interface{}
    byteResponse := []byte(response)

    resp, err := ohlcResponseDecoder(byteResponse, testing)
    if err != nil {
        resp, err = heartBeatResponseDecoder(byteResponse, testing)
        if err != nil {
            resp, err = serverConnectionStatusResponseDecoder(byteResponse, testing)
            if err != nil {
                resp, err = ohlcSubscriptionResponseDecoder(byteResponse, testing)
            }
        }
    }
    return resp
}

Thanks for any help you may have

CodePudding user response:

Since you seem to control the complete list of types which can be unesrialized, you can use a type swicth :

swich v := c.(type) {
case *ohlcResponse:
   // in this block, v is a *ohlcRrsponse
case *heartBeatResponse:
   // in this block, v is a *heartBeatResponse
case *serverConnectionStatusResponse:
   // in this block, v is a *serverConnectionStatus
case *ohlcSubscriptionResponse:
   // in this block, v is a *ohlcSubscriptionResponse

default:
   // choose some way to report unhandled types:
   log.Fatalf("unhandled response type: %T", c)
}
  • Related