avro-registered-schema-decoder 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/avro-registered-schema-decoder.rb +1 -0
- data/lib/avro/registered_schema_decoder.rb +97 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d490a609d6c3b2d0d1ecceba3019d1392021b7c6
|
4
|
+
data.tar.gz: 6e10f76246cabc413f8a1e602bf0f10ae0e9d1e2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c87c293bd4b20094cf66105e0cf09db28bae70e8c0609f66ebc3025d7058ab25d186887f05928e36a2add66c38bbf322c5e467bf153edaeb04d9abf78930489c
|
7
|
+
data.tar.gz: 3918b0ed6311532def01d253db08c71c4a5e3921a735bf5cd9fc704d3210adb56769bb640df618d1274133cc81e98de8438b6764b8e3049ca3a4aff1306efa2b
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'avro', 'registered_schema_decoder')
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'avro'
|
2
|
+
require 'schema_registry'
|
3
|
+
|
4
|
+
module Avro
|
5
|
+
class RegisteredSchemaDecoder
|
6
|
+
class Error < StandardError
|
7
|
+
attr_reader :cause
|
8
|
+
def initialize(message, cause = $!)
|
9
|
+
super(message)
|
10
|
+
@cause = cause
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"#{super}#{" (caused by: #{cause})" if cause}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(registry_url, logger: nil)
|
19
|
+
@registry = SchemaRegistry::Client.new(registry_url)
|
20
|
+
@logger = logger
|
21
|
+
@readers = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def decode_key(key_bytes)
|
25
|
+
_, key = decode_key_with_schema(key_bytes)
|
26
|
+
key
|
27
|
+
end
|
28
|
+
|
29
|
+
def decode_key_with_schema(key_bytes)
|
30
|
+
# expected for unkeyed messages
|
31
|
+
return if key_bytes.nil?
|
32
|
+
|
33
|
+
decode_message(key_bytes)
|
34
|
+
end
|
35
|
+
|
36
|
+
def decode_value(value_bytes)
|
37
|
+
_, value = decode_value_with_schema(value_bytes)
|
38
|
+
value
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_value_with_schema(value_bytes)
|
42
|
+
# expected, used to signify record deletion
|
43
|
+
return if value_bytes.nil?
|
44
|
+
# handle producers using older versions of librdkafka, which sent zero-
|
45
|
+
# length messages instead of null messages:
|
46
|
+
# see https://github.com/confluentinc/bottledwater-pg/pull/33
|
47
|
+
return if value_bytes.empty?
|
48
|
+
|
49
|
+
decode_message(value_bytes)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
# message format:
|
54
|
+
#
|
55
|
+
# Every message sent to Kafka is Avro-encoded, and prefixed with five
|
56
|
+
# bytes:
|
57
|
+
# - The first byte is always 0, and reserved for future use.
|
58
|
+
# - The next four bytes are the schema ID in big-endian byte order.
|
59
|
+
#
|
60
|
+
# per https://github.com/confluentinc/bottledwater-pg/blob/8a11825/kafka/registry.c#L6-L8
|
61
|
+
def decode_message(bytes)
|
62
|
+
raise "Empty message" if bytes.empty?
|
63
|
+
reserved, schema_id, avro = bytes.unpack('cNa*')
|
64
|
+
raise "Reserved byte #{reserved.inspect} in message header (expected 0)!\nmessage: #{bytes.inspect}" unless 0 == reserved
|
65
|
+
|
66
|
+
reader = reader_for(schema_id)
|
67
|
+
decoder = Avro::IO::BinaryDecoder.new(StringIO.new(avro))
|
68
|
+
|
69
|
+
wrap_error "parsing message with schema #{schema_id}" do
|
70
|
+
[reader.writers_schema, reader.read(decoder)]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def reader_for(schema_id)
|
75
|
+
if @readers.key?(schema_id)
|
76
|
+
return @readers[schema_id]
|
77
|
+
end
|
78
|
+
|
79
|
+
@logger.debug("Fetching schema #{schema_id}") if @logger
|
80
|
+
schema = nil
|
81
|
+
wrap_error "fetching schema #{schema_id}" do
|
82
|
+
schema_json = @registry.schema(schema_id)
|
83
|
+
schema = Avro::Schema.parse(schema_json)
|
84
|
+
end
|
85
|
+
|
86
|
+
Avro::IO::DatumReader.new(schema).tap do |reader|
|
87
|
+
@readers[schema_id] = reader
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def wrap_error(doing_what)
|
92
|
+
yield
|
93
|
+
rescue
|
94
|
+
raise Error, "error #{doing_what}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: avro-registered-schema-decoder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Stokes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: avro
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: schema_registry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |
|
84
|
+
Provides a decoder for messages encoded as "prefixed Avro", where the binary
|
85
|
+
Avro encoding is prefixed with a schema id referring to a schema stored in a
|
86
|
+
Confluent Schema Registry
|
87
|
+
(http://docs.confluent.io/1.0/schema-registry/docs/intro.html).
|
88
|
+
email:
|
89
|
+
- me@samstokes.co.uk
|
90
|
+
executables: []
|
91
|
+
extensions: []
|
92
|
+
extra_rdoc_files: []
|
93
|
+
files:
|
94
|
+
- lib/avro-registered-schema-decoder.rb
|
95
|
+
- lib/avro/registered_schema_decoder.rb
|
96
|
+
homepage: https://github.com/samstokes/avro-registered-schema-decoder
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.4.5.1
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Decodes messages encoded as prefixed Avro, looking up schemas in a schema
|
120
|
+
registry
|
121
|
+
test_files: []
|