feat: Replace DIDCommMsg type with map[string]interface{} #1054
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1054 +/- ##
==========================================
- Coverage 91.14% 91.08% -0.07%
==========================================
Files 102 102
Lines 6446 6469 +23
==========================================
+ Hits 5875 5892 +17
- Misses 311 314 +3
- Partials 260 263 +3
Continue to review full report at Codecov.
|
@soluchok It would be nice if we can describe the reason for this change. Currently, I don't see any in PR or Issue description. |
|
||
// ID returns the message id | ||
func (m DIDCommMsg) ID() string { | ||
if m == nil || m[jsonID] == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if ID is ""?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ID function will return the default value. Default is "".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be invalid error if ID is empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the message is generic, it doesn't make sense to return an error. The empty type should be returned. We may provide the IsValid function to check the message if it is needed. For the functions which have some logic, I agree there should be an error. e.g ThreadID function. When we just want to get the direct value, it does not make sense to return an error.
} | ||
|
||
// ToStruct converts msh message to struct | ||
func (m DIDCommMsg) ToStruct(v interface{}) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, why can't we use "https://github.com/mitchellh/mapstructure"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mapstructure not maintainable anymore mitchellh/mapstructure#145 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think it's better than rolling our own code until we have a good reason to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@soluchok @llorllale I believe the issue is that we need omit:empty and that feature hasn't been merged into mapstructure. correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, but I think it is not a big problem
return err | ||
} | ||
|
||
if svc.Accept(h) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing whole message may be risky to check acceptance criteria, for now add a TODO to pass subset of DIDComm msg map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accept may use an interface e.g
type Typer interface {
Type() string
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are also going to check it based on ~purpose
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Moopli ^^^
if !ok { | ||
return "" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're hiding an error condition here. Likewise in ID()
.
Not sure what to do. Adding an error
return parameter would make the usage of Type()
clumsy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the best way is to return a default value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewDidCommMsg()
should guarantee these base values exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -275,7 +273,7 @@ func (s *Service) handle(msg *message, aEvent chan<- service.DIDCommAction) erro | |||
s.sendMsgEvents(&service.StateMsg{ | |||
ProtocolName: DIDExchange, | |||
Type: service.PostState, | |||
Msg: msg.Msg.Clone(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's interesting that we now lose this aspect (no longer exporting a copy).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about it, I think instead of copy we may provide didcommmsg interface.
type IDIDCommMsg interface{
ID()
Type()
ToStrunct()
}
copy
a message is not a cheap operation. My suggestion is to provide an interface. I have not seen that we really use this message. Anyway providing an interface looks better and cheaper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interface or a struct is fine by me personally. Gophers would probably prefer it be a struct though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An interface should only be returned if that is need to satisfy the signature of another interface.
Otherwise return a struct. The consuming code should accept the struct using an interface, of course.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two public artifacts is overkill in this case. Either make it a public struct or a public interface + private struct. It's immutable and the method set [ID(), Type(), ThreadID(), Scan()] to me strikes the ideal balance between size, cohesion, and generality/usefulness.
@soluchok we lost the |
} | ||
|
||
// DIDCommMsg did comm msg | ||
type DIDCommMsg map[string]interface{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably not be in common/service anymore.
It is an implementation rather than a common interface being consumed by other packages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Give me a hint of where to move it. pkg/common/didcommmsg
?
Signed-off-by: Andrii Soluk <isoluchok@gmail.com>
The intention of this PR is to generalize all messages in the system/framework. Because our messages are JSON based messages the structure map[string]interface is enough to make messages with the same type. The benefit of this can be:
Since the message is a map, it can be modified by some other package/client. To prevent this we need to expose only the message interface. The interface provides Type and Scan functions. Having these functions any package/client may convert a message into a specific structure.
The usage:
In our current logic, we send events to the client/user. DIDCommAction and StateMsg accordingly. In that case, we cannot expose the message to the client. Because we are using DIDCommMsg message in our services (background handling e.g Continue function). So, instead of exposing DIDCommMsg we should expose an interface DIDMsg.
Closes #1065 #1039