1818package internal
1919
2020import (
21+ "encoding/binary"
2122 "errors"
2223 "fmt"
2324 "net/url"
25+ "strings"
2426
2527 "google.golang.org/protobuf/proto"
2628
@@ -34,6 +36,16 @@ type LookupResult struct {
3436 PhysicalAddr * url.URL
3537}
3638
39+ // LookupSchema return lookup schema result
40+ // we need to define a LookupSchema struct as return type to avoid directly returning pulsar.Schema
41+ // in case we might meet importing cycle problem
42+ type LookupSchema struct {
43+ PbSchemaType int // pb binary cmd lookup return type schema index
44+ HTTPSchemaType string `json:"type"` // http lookup return type schema name
45+ Data string `json:"data"`
46+ Properties map [string ]string `json:"properties"`
47+ }
48+
3749// GetTopicsOfNamespaceMode for CommandGetTopicsOfNamespace_Mode
3850type GetTopicsOfNamespaceMode string
3951
@@ -62,7 +74,7 @@ type LookupService interface {
6274 GetTopicsOfNamespace (namespace string , mode GetTopicsOfNamespaceMode ) ([]string , error )
6375
6476 // GetSchema returns schema for a given version.
65- GetSchema (topic string , schemaVersion []byte ) (schema * pb. Schema , err error )
77+ GetSchema (topic string , schemaVersion []byte ) (* LookupSchema , error )
6678
6779 GetBrokerAddress (brokerServiceURL string , proxyThroughServiceURL bool ) (* LookupResult , error )
6880
@@ -97,7 +109,7 @@ func NewLookupService(rpcClient RPCClient, serviceURL *url.URL, serviceNameResol
97109 }
98110}
99111
100- func (ls * lookupService ) GetSchema (topic string , schemaVersion []byte ) (schema * pb. Schema , err error ) {
112+ func (ls * lookupService ) GetSchema (topic string , schemaVersion []byte ) (* LookupSchema , error ) {
101113 id := ls .rpcClient .NewRequestID ()
102114 req := & pb.CommandGetSchema {
103115 RequestId : proto .Uint64 (id ),
@@ -106,12 +118,23 @@ func (ls *lookupService) GetSchema(topic string, schemaVersion []byte) (schema *
106118 }
107119 res , err := ls .rpcClient .RequestToAnyBroker (id , pb .BaseCommand_GET_SCHEMA , req )
108120 if err != nil {
109- return nil , err
121+ return & LookupSchema {} , err
110122 }
111123 if res .Response .Error != nil {
112- return nil , errors .New (res .Response .GetError ().String ())
124+ return & LookupSchema {} , errors .New (res .Response .GetError ().String ())
113125 }
114- return res .Response .GetSchemaResponse .Schema , nil
126+
127+ // deserialize pb.schema and convert it to LookupSchema struct
128+ pbSchema := res .Response .GetSchemaResponse .Schema
129+ if pbSchema == nil {
130+ err = fmt .Errorf ("schema not found for topic: [ %v ], schema version : [ %v ]" , topic , schemaVersion )
131+ return & LookupSchema {}, err
132+ }
133+ return & LookupSchema {
134+ PbSchemaType : int (* pbSchema .Type ),
135+ Data : string (pbSchema .SchemaData ),
136+ Properties : ConvertToStringMap (pbSchema .Properties ),
137+ }, nil
115138}
116139
117140func (ls * lookupService ) GetBrokerAddress (brokerServiceURL string , proxyThroughServiceURL bool ) (* LookupResult , error ) {
@@ -273,6 +296,8 @@ const HTTPAdminServiceV1Format string = "/admin/%s/partitions"
273296const HTTPAdminServiceV2Format string = "/admin/v2/%s/partitions"
274297const HTTPTopicUnderNamespaceV1 string = "/admin/namespaces/%s/destinations?mode=%s"
275298const HTTPTopicUnderNamespaceV2 string = "/admin/v2/namespaces/%s/topics?mode=%s"
299+ const HTTPSchemaV2 string = "/admin/v2/schemas/%s/schema"
300+ const HTTPSchemaWithVersionV2 string = "/admin/v2/schemas/%s/schema/%d"
276301
277302type httpLookupData struct {
278303 BrokerURL string `json:"brokerUrl"`
@@ -371,8 +396,33 @@ func (h *httpLookupService) GetTopicsOfNamespace(namespace string, mode GetTopic
371396 return topics , nil
372397}
373398
374- func (h * httpLookupService ) GetSchema (_ string , _ []byte ) (schema * pb.Schema , err error ) {
375- return nil , errors .New ("GetSchema is not supported by httpLookupService" )
399+ func (h * httpLookupService ) GetSchema (topic string , schemaVersion []byte ) (* LookupSchema , error ) {
400+ topicName , err := ParseTopicName (topic )
401+ if err != nil {
402+ return nil , err
403+ }
404+ topicRestPath := fmt .Sprintf ("%s/%s" , topicName .Namespace , topicName .Topic )
405+ var path string
406+ if schemaVersion != nil {
407+ path = fmt .Sprintf (HTTPSchemaWithVersionV2 , topicRestPath , int64 (binary .BigEndian .Uint64 (schemaVersion )))
408+ } else {
409+ path = fmt .Sprintf (HTTPSchemaV2 , topicRestPath )
410+ }
411+ httpSchema := & LookupSchema {}
412+ if err := h .httpClient .Get (path , & httpSchema , nil ); err != nil {
413+ if strings .HasPrefix (err .Error (), "Code: 404" ) {
414+ // Unlike other language pulsar sdks,
415+ // golang sdk directly use pb.Schema{} binary command instead of lookup service
416+ // in consumer/producer schema initialization.
417+ //
418+ // Golang sdk only use this GetSchema() interface in tableView schema query and msg deserialize,
419+ // so that we don't need to take more care about 404 NotFound http exception.
420+ err = fmt .Errorf ("schema not found for topic: [ %v ], schema version : [ %v ]" , topic , schemaVersion )
421+ }
422+ h .log .Errorf ("schema [ %v ] request error, schema version : [ %v ]" , topic , schemaVersion )
423+ return & LookupSchema {}, err
424+ }
425+ return httpSchema , nil
376426}
377427
378428func (h * httpLookupService ) ServiceNameResolver () * ServiceNameResolver {
0 commit comments