package qsl import ( "fmt" "strings" "github.com/linkedin/goavro" "gitlab-app.eng.qops.net/golang/qmp/qsl/internal/qm" "gitlab-app.eng.qops.net/golang/qmp/qsl/internal/schema" "gitlab-app.eng.qops.net/golang/qmp/qsl/internal/schema/registry" ) // qmReader implements the qsl.Reader interface. type qmReader struct { readerSchemaSpec string manager readerSchemaManager } type readerSchemaManager interface { Get(string) (string, error) } // newReader creats a new Message reader generator. func newReader(readerSchemaSpec string, schemaManager readerSchemaManager) *qmReader { return &qmReader{ readerSchemaSpec: readerSchemaSpec, manager: schemaManager, } } // NewMessage creates a new Message from the input // avro binary using the qmReader's schema. func (q *qmReader) NewMessage(encodedAvroValue []byte) (Message, error) { // get short envelope schema spec to extract the encodedAvroValue's schema ID envelopeSchema, err := q.manager.Get(schema.EnvelopeSchemaID) if err != nil { return nil, err } codec, err := goavro.NewCodec(envelopeSchema) if err != nil { return nil, err } var envelopeNative interface{} // If the schema spec is a union (complex schema with declarations), the // first bit is the index of the union. Remove that so we can get the // schema spec ID. if s := strings.TrimSpace(q.readerSchemaSpec); s != "" && s[0] == '[' && len(encodedAvroValue) > 0 { envelopeNative, _, err = codec.NativeFromBinary(encodedAvroValue[1:]) } else { envelopeNative, _, err = codec.NativeFromBinary(encodedAvroValue) } if err != nil { return nil, err } envelopeMap, ok := envelopeNative.(map[string]interface{}) if !ok { return nil, fmt.Errorf("standard %s schema spec didn't parse bytes as a map", schema.EnvelopeSchemaID) } schemaIDValue, ok := envelopeMap[registry.SchemaID] if !ok { return nil, fmt.Errorf("standard %s schema spec didn't parse %s from bytes", schema.EnvelopeSchemaID, registry.SchemaID) } schemaID, ok := schemaIDValue.(string) if !ok { return nil, fmt.Errorf("standard %s schema spec parsed %s as non-string", schema.EnvelopeSchemaID, registry.SchemaID) } // fetch writer schema spec from schemaID named in encodedAvroValue writerSchemaSpec, err := q.manager.Get(schemaID) if err != nil { return nil, err } return qm.NewReadingMessage(writerSchemaSpec, q.readerSchemaSpec, encodedAvroValue) }