120 lines
3.4 KiB
Go
Executable File
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
|
|
}
|