qmp-testing-suite/golang-producer-consumer/vendor/gitlab-app.eng.qops.net/golang/qmp/qsl/writer.go

120 lines
3.4 KiB
Go
Executable File

package qsl
import (
"fmt"
"os"
"time"
uuid "github.com/satori/go.uuid"
"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"
)
const hostName = "HOSTNAME"
const defaultHost = "unknown"
// qmWriter implements the qsl's Writer interface.
// It creates writing Messages.
type qmWriter struct {
schemaID string
writerSchemaSpec string
writerApp string
manager writerSchemaManager
}
type writerSchemaManager interface {
Get(string) (string, error)
}
// newWriter creats a new Message writer generator for a schema.
func newWriter(writerSchemaSpec, schemaID, writerApp string, schemaManager writerSchemaManager) *qmWriter {
return &qmWriter{
writerSchemaSpec: writerSchemaSpec,
manager: schemaManager,
writerApp: writerApp,
schemaID: schemaID,
}
}
// NewFromMessage creates a new Message from a reading Message
// with the Writer's schema.
func (q *qmWriter) NewFromMessage(msg Message) (Message, error) {
if err := schema.IsCompatible(q.writerSchemaSpec, msg.GetWriterSchema()); err != nil {
return nil, err
}
originalBytes, err := msg.GetOriginalBytes()
if err != nil {
return nil, err
}
qMsg, err := qm.NewReadingMessage(msg.GetWriterSchema(), q.writerSchemaSpec, originalBytes)
if err != nil {
return nil, err
}
qMsg.UseOriginalBytes(false)
qMsg.SetWriterSchema(q.schemaID, q.writerSchemaSpec)
return qMsg, nil
}
// NewMessage attempts to create a new Message for writing using
// the qmWriter's schema.
func (q *qmWriter) NewMessage() (Message, error) {
writerHost := os.Getenv(hostName)
if writerHost == "" {
writerHost = defaultHost
}
messageID := uuid.NewV4().String()
return qm.NewWritingMessage(q.writerSchemaSpec, q.schemaID, messageID, makeTimestamp(), writerHost, q.writerApp)
}
// NewFromObject attempts to create a new Message for writing using
// the given initialized object, checking if it is compatible with the Writer's
// schema.
func (q *qmWriter) NewFromObject(avroObject map[string]interface{}) (Message, error) {
objSchema, schemaID, err := schemaIfCompatible(avroObject, q.manager, q.writerSchemaSpec)
if err != nil {
return nil, err
}
writerHost := os.Getenv(hostName)
if writerHost == "" {
writerHost = defaultHost
}
messageID := uuid.NewV4().String()
qMsg, err := qm.NewWritingMessage(objSchema, schemaID, messageID, makeTimestamp(), writerHost, q.writerApp)
if err != nil {
return nil, err
}
qMsg.SetWriterSchema(q.schemaID, q.writerSchemaSpec)
for k, v := range avroObject {
qMsg.GetAvroObject()[k] = v
}
if _, err := qMsg.GetSerializedBytes(); err != nil {
return nil, err
}
return qMsg, nil
}
func makeTimestamp() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}
func schemaIfCompatible(avroObject map[string]interface{}, manager writerSchemaManager, readerSchemaSpec string) (string, string, error) {
schemaIDValue, ok := avroObject[registry.SchemaID]
if !ok {
return "", "", fmt.Errorf("avro object does not have %q", registry.SchemaID)
}
schemaID, ok := schemaIDValue.(string)
if !ok {
return "", "", fmt.Errorf("avro object has non-string %q", registry.SchemaID)
}
writerSchemaSpec, err := manager.Get(schemaID)
if err != nil {
return "", "", err
}
if err = schema.IsCompatible(writerSchemaSpec, readerSchemaSpec); err != nil {
return "", "", err
}
return writerSchemaSpec, schemaID, nil
}