|
5 | 5 | "errors" |
6 | 6 | "fmt" |
7 | 7 | "reflect" |
| 8 | + "strings" |
8 | 9 |
|
9 | 10 | gogoproto "github.com/cosmos/gogoproto/proto" |
10 | 11 |
|
@@ -61,7 +62,7 @@ func (b *MsgRouterBuilder) HandlerExists(msgType string) bool { |
61 | 62 | return ok |
62 | 63 | } |
63 | 64 |
|
64 | | -func (b *MsgRouterBuilder) Build() (Router, error) { |
| 65 | +func (b *MsgRouterBuilder) Build() (coreRouterImpl, error) { |
65 | 66 | handlers := make(map[string]appmodulev2.Handler) |
66 | 67 |
|
67 | 68 | globalPreHandler := func(ctx context.Context, msg appmodulev2.Message) error { |
@@ -93,7 +94,7 @@ func (b *MsgRouterBuilder) Build() (Router, error) { |
93 | 94 | handlers[msgType] = buildHandler(handler, preHandlers, globalPreHandler, postHandlers, globalPostHandler) |
94 | 95 | } |
95 | 96 |
|
96 | | - return Router{ |
| 97 | + return coreRouterImpl{ |
97 | 98 | handlers: handlers, |
98 | 99 | }, nil |
99 | 100 | } |
@@ -139,39 +140,73 @@ func msgTypeURL(msg gogoproto.Message) string { |
139 | 140 | return gogoproto.MessageName(msg) |
140 | 141 | } |
141 | 142 |
|
142 | | -var _ router.Service = (*Router)(nil) |
| 143 | +var _ router.Service = (*coreRouterImpl)(nil) |
143 | 144 |
|
144 | | -// Router implements the STF router for msg and query handlers. |
145 | | -type Router struct { |
| 145 | +// coreRouterImpl implements the STF router for msg and query handlers. |
| 146 | +type coreRouterImpl struct { |
146 | 147 | handlers map[string]appmodulev2.Handler |
147 | 148 | } |
148 | 149 |
|
149 | | -func (r Router) CanInvoke(_ context.Context, typeURL string) error { |
| 150 | +func (r coreRouterImpl) CanInvoke(_ context.Context, typeURL string) error { |
| 151 | + // trimming prefixes is a backwards compatibility strategy that we use |
| 152 | + // for baseapp components that did routing through type URL rather |
| 153 | + // than protobuf message names. |
| 154 | + typeURL = strings.TrimPrefix(typeURL, "/") |
150 | 155 | _, exists := r.handlers[typeURL] |
151 | 156 | if !exists { |
152 | 157 | return fmt.Errorf("%w: %s", ErrNoHandler, typeURL) |
153 | 158 | } |
154 | 159 | return nil |
155 | 160 | } |
156 | 161 |
|
157 | | -func (r Router) InvokeTyped(ctx context.Context, req, resp gogoproto.Message) error { |
| 162 | +func (r coreRouterImpl) InvokeTyped(ctx context.Context, req, resp gogoproto.Message) error { |
158 | 163 | handlerResp, err := r.InvokeUntyped(ctx, req) |
159 | 164 | if err != nil { |
160 | 165 | return err |
161 | 166 | } |
162 | | - merge(handlerResp, resp) |
163 | | - return nil |
164 | | -} |
165 | | - |
166 | | -func merge(src, dst gogoproto.Message) { |
167 | | - reflect.Indirect(reflect.ValueOf(dst)).Set(reflect.Indirect(reflect.ValueOf(src))) |
| 167 | + return merge(handlerResp, resp) |
168 | 168 | } |
169 | 169 |
|
170 | | -func (r Router) InvokeUntyped(ctx context.Context, req gogoproto.Message) (res gogoproto.Message, err error) { |
| 170 | +func (r coreRouterImpl) InvokeUntyped(ctx context.Context, req gogoproto.Message) (res gogoproto.Message, err error) { |
171 | 171 | typeName := msgTypeURL(req) |
172 | 172 | handler, exists := r.handlers[typeName] |
173 | 173 | if !exists { |
174 | 174 | return nil, fmt.Errorf("%w: %s", ErrNoHandler, typeName) |
175 | 175 | } |
176 | 176 | return handler(ctx, req) |
177 | 177 | } |
| 178 | + |
| 179 | +// merge merges together two protobuf messages by setting the pointer |
| 180 | +// to src in dst. Used internally. |
| 181 | +func merge(src, dst gogoproto.Message) error { |
| 182 | + if src == nil { |
| 183 | + return fmt.Errorf("source message is nil") |
| 184 | + } |
| 185 | + if dst == nil { |
| 186 | + return fmt.Errorf("destination message is nil") |
| 187 | + } |
| 188 | + |
| 189 | + srcVal := reflect.ValueOf(src) |
| 190 | + dstVal := reflect.ValueOf(dst) |
| 191 | + |
| 192 | + if srcVal.Kind() == reflect.Interface { |
| 193 | + srcVal = srcVal.Elem() |
| 194 | + } |
| 195 | + if dstVal.Kind() == reflect.Interface { |
| 196 | + dstVal = dstVal.Elem() |
| 197 | + } |
| 198 | + |
| 199 | + if srcVal.Kind() != reflect.Ptr || dstVal.Kind() != reflect.Ptr { |
| 200 | + return fmt.Errorf("both source and destination must be pointers") |
| 201 | + } |
| 202 | + |
| 203 | + srcElem := srcVal.Elem() |
| 204 | + dstElem := dstVal.Elem() |
| 205 | + |
| 206 | + if !srcElem.Type().AssignableTo(dstElem.Type()) { |
| 207 | + return fmt.Errorf("incompatible types: cannot merge %v into %v", srcElem.Type(), dstElem.Type()) |
| 208 | + } |
| 209 | + |
| 210 | + dstElem.Set(srcElem) |
| 211 | + return nil |
| 212 | +} |
0 commit comments