diff --git a/CHANGELOG.md b/CHANGELOG.md index 131c9dd07..8fb321944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,14 @@ #### Added - (#174) Add CHANGELOG.md file +- (#179) [API] Add `eventFilter` on `ListenEvent` API to get notification when an event with a specific name occurs + [API] Add `taskFilter` on `ListenResult` API to get notification when a result from a specific task occurs + [API] Add `outputFilter` on `ListenResult` API to get notification when a result returns a specific output - (#183) Add a `configuration` attribute in the `mesg.yml` file to accept docker configuration for your service - (#187) Stop all services when the daemon stops #### Removed #### Fixed -- (#185) Fix logs with extra characters when `mesg-core daemon logs` \ No newline at end of file +- (#179) [Doc] Outdated documentation for the CLI +- (#185) Fix logs with extra characters when `mesg-core daemon logs` diff --git a/api/core/api.pb.go b/api/core/api.pb.go index a5b4b0f7d..6cbe50383 100644 --- a/api/core/api.pb.go +++ b/api/core/api.pb.go @@ -47,7 +47,8 @@ var _ = math.Inf const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type ListenEventRequest struct { - ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` + ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` + EventFilter string `protobuf:"bytes,2,opt,name=eventFilter" json:"eventFilter,omitempty"` } func (m *ListenEventRequest) Reset() { *m = ListenEventRequest{} } @@ -62,6 +63,13 @@ func (m *ListenEventRequest) GetServiceID() string { return "" } +func (m *ListenEventRequest) GetEventFilter() string { + if m != nil { + return m.EventFilter + } + return "" +} + type ExecuteTaskRequest struct { ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` TaskKey string `protobuf:"bytes,2,opt,name=taskKey" json:"taskKey,omitempty"` @@ -95,7 +103,9 @@ func (m *ExecuteTaskRequest) GetTaskData() string { } type ListenResultRequest struct { - ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` + ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` + TaskFilter string `protobuf:"bytes,2,opt,name=taskFilter" json:"taskFilter,omitempty"` + OutputFilter string `protobuf:"bytes,3,opt,name=outputFilter" json:"outputFilter,omitempty"` } func (m *ListenResultRequest) Reset() { *m = ListenResultRequest{} } @@ -110,6 +120,20 @@ func (m *ListenResultRequest) GetServiceID() string { return "" } +func (m *ListenResultRequest) GetTaskFilter() string { + if m != nil { + return m.TaskFilter + } + return "" +} + +func (m *ListenResultRequest) GetOutputFilter() string { + if m != nil { + return m.OutputFilter + } + return "" +} + type StartServiceRequest struct { ServiceID string `protobuf:"bytes,1,opt,name=serviceID" json:"serviceID,omitempty"` } @@ -679,38 +703,40 @@ var _Core_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("github.com/mesg-foundation/core/api/core/api.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 526 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcb, 0x6e, 0xd3, 0x40, - 0x14, 0xcd, 0xab, 0x2d, 0xb9, 0x2e, 0x10, 0xa6, 0x81, 0x1a, 0xab, 0x42, 0xd5, 0xac, 0x0a, 0x12, - 0x09, 0x72, 0x60, 0x83, 0x84, 0x2a, 0x85, 0x64, 0xc1, 0x63, 0x95, 0xb0, 0x82, 0x95, 0x1b, 0x2e, - 0xad, 0x55, 0xd7, 0x33, 0xd8, 0xe3, 0x0a, 0xff, 0x0b, 0xbf, 0xc5, 0xff, 0xa0, 0x19, 0xdb, 0xe3, - 0xf1, 0x83, 0x92, 0xac, 0x92, 0xfb, 0xbe, 0x67, 0xce, 0x3d, 0x06, 0xf7, 0xd2, 0x17, 0x57, 0xc9, - 0xc5, 0x64, 0xc3, 0x6e, 0xa6, 0x37, 0x18, 0x5f, 0xbe, 0xfc, 0xc1, 0x92, 0xf0, 0xbb, 0x27, 0x7c, - 0x16, 0x4e, 0x37, 0x2c, 0xc2, 0xa9, 0xc7, 0x7d, 0xfd, 0x67, 0xc2, 0x23, 0x26, 0x18, 0xe9, 0x7b, - 0xdc, 0x77, 0xde, 0xfc, 0xaf, 0x30, 0xc6, 0xe8, 0xd6, 0xdf, 0xe8, 0xdf, 0xac, 0x96, 0xba, 0x40, - 0x3e, 0xfb, 0xb1, 0xc0, 0x70, 0x79, 0x8b, 0xa1, 0x58, 0xe1, 0xcf, 0x04, 0x63, 0x41, 0x4e, 0x60, - 0x98, 0xa7, 0x7d, 0x58, 0xd8, 0xdd, 0xd3, 0xee, 0xd9, 0x70, 0x55, 0x3a, 0xe8, 0x15, 0x90, 0xe5, - 0x2f, 0xdc, 0x24, 0x02, 0xbf, 0x78, 0xf1, 0xf5, 0x56, 0x35, 0xc4, 0x86, 0x03, 0xe1, 0xc5, 0xd7, - 0x9f, 0x30, 0xb5, 0x7b, 0x2a, 0x56, 0x98, 0xc4, 0x81, 0x7b, 0xf2, 0xef, 0xc2, 0x13, 0x9e, 0xdd, - 0x57, 0x21, 0x6d, 0xd3, 0x19, 0x1c, 0x65, 0xdb, 0xad, 0x30, 0x4e, 0x82, 0x2d, 0xd7, 0x9b, 0xc1, - 0xd1, 0x5a, 0x78, 0x91, 0x58, 0x67, 0x9e, 0xed, 0x8a, 0x5c, 0x20, 0x6b, 0xc1, 0xf8, 0x4e, 0x35, - 0xdf, 0x60, 0xa8, 0x5e, 0x4d, 0xae, 0x4a, 0xc6, 0xb0, 0x87, 0x51, 0xc4, 0xa2, 0x3c, 0x2d, 0x33, - 0x24, 0x38, 0x94, 0x29, 0x25, 0x6e, 0x6d, 0xcb, 0xe6, 0x58, 0x94, 0xe7, 0xc8, 0x4b, 0x07, 0xfd, - 0x08, 0xa3, 0xca, 0x23, 0xf3, 0x20, 0x25, 0xa7, 0x60, 0xa1, 0xf2, 0xf9, 0x2c, 0xd4, 0x0b, 0x99, - 0xae, 0x72, 0x8b, 0x9e, 0xb1, 0x05, 0xfd, 0xdd, 0x05, 0xc8, 0x5e, 0xf0, 0x8e, 0x55, 0x6b, 0xcd, - 0x7b, 0xcd, 0xe6, 0x06, 0x87, 0xfd, 0x2a, 0x87, 0x27, 0x30, 0x64, 0x89, 0xe0, 0x89, 0xc2, 0x39, - 0xc8, 0xa0, 0x68, 0x07, 0x79, 0x06, 0x90, 0x19, 0x0a, 0xe9, 0x9e, 0x0a, 0x1b, 0x1e, 0xfa, 0x1c, - 0x1e, 0x55, 0x09, 0x93, 0x58, 0x5b, 0x97, 0xa4, 0x67, 0x30, 0xaa, 0xd0, 0xf4, 0xef, 0xcc, 0x39, - 0x8c, 0x17, 0xc8, 0x03, 0x96, 0xd6, 0x28, 0x7d, 0x01, 0x07, 0x39, 0x83, 0x2a, 0xdf, 0x72, 0x47, - 0x93, 0x42, 0x11, 0x45, 0x66, 0x91, 0x20, 0x8f, 0xa2, 0xd6, 0x43, 0xce, 0xbb, 0xfb, 0x28, 0x5e, - 0xcb, 0xb9, 0x01, 0x0a, 0xdc, 0xe9, 0x94, 0xc6, 0x72, 0x52, 0xa5, 0x8a, 0x07, 0xa9, 0xfb, 0xa7, - 0x0f, 0x83, 0xf7, 0x2c, 0x42, 0xf2, 0x16, 0x2c, 0x43, 0xa5, 0xe4, 0x78, 0x22, 0xc5, 0xdf, 0xd4, - 0xad, 0xf3, 0x40, 0x05, 0xf4, 0x51, 0xd2, 0xce, 0xab, 0x2e, 0x39, 0x07, 0xcb, 0x38, 0xa4, 0xbc, - 0xb6, 0xa9, 0x5f, 0xe7, 0x71, 0x33, 0xc0, 0x83, 0x94, 0x76, 0xc8, 0x3b, 0x38, 0x34, 0x45, 0x48, - 0x6c, 0x63, 0x7a, 0x45, 0x97, 0xce, 0x43, 0x15, 0x29, 0x2f, 0x4d, 0xcd, 0x9f, 0xc3, 0xa1, 0xc9, - 0x6e, 0x5e, 0xde, 0xa2, 0x50, 0xe7, 0x49, 0x4b, 0x24, 0x5b, 0xe1, 0x1c, 0x2c, 0x83, 0xf6, 0x1c, - 0x43, 0x53, 0xaf, 0x39, 0x86, 0xfa, 0x85, 0xd0, 0x0e, 0x59, 0xc2, 0xfd, 0x0a, 0x93, 0xe4, 0xa9, - 0xca, 0x6c, 0xbb, 0x10, 0xe7, 0xb8, 0x2d, 0x64, 0xb4, 0x31, 0x68, 0xd2, 0x6d, 0x9a, 0x84, 0xeb, - 0x36, 0x75, 0x56, 0x69, 0x67, 0xbe, 0xff, 0x75, 0x20, 0x3f, 0xc9, 0x17, 0xfb, 0xea, 0x1b, 0x3c, - 0xfb, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xc3, 0x7d, 0x2c, 0xd2, 0xf5, 0x05, 0x00, 0x00, + // 559 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4b, 0x6f, 0xd3, 0x40, + 0x10, 0xce, 0xab, 0x2d, 0x19, 0x07, 0x08, 0xdb, 0x40, 0x8d, 0x55, 0xa1, 0x6a, 0x4f, 0x05, 0x89, + 0x04, 0xa5, 0x70, 0x41, 0x42, 0x95, 0x42, 0x82, 0xc4, 0xe3, 0x94, 0xf4, 0x04, 0x27, 0x37, 0x0c, + 0xad, 0x55, 0xd7, 0x6b, 0xec, 0x75, 0xc1, 0xff, 0x85, 0xbf, 0xc5, 0xff, 0x41, 0xbb, 0xeb, 0xc7, + 0xae, 0x6d, 0xda, 0xe4, 0x64, 0xef, 0x3c, 0xbe, 0x99, 0xd9, 0xef, 0xdb, 0x81, 0xe9, 0x85, 0xc7, + 0x2f, 0x93, 0xf3, 0xf1, 0x9a, 0x5d, 0x4f, 0xae, 0x31, 0xbe, 0x78, 0xf9, 0x83, 0x25, 0xc1, 0x77, + 0x97, 0x7b, 0x2c, 0x98, 0xac, 0x59, 0x84, 0x13, 0x37, 0xf4, 0x8a, 0x9f, 0x71, 0x18, 0x31, 0xce, + 0x48, 0xd7, 0x0d, 0x3d, 0xe7, 0xcd, 0x5d, 0x89, 0x31, 0x46, 0x37, 0xde, 0xba, 0xf8, 0xaa, 0x5c, + 0x7a, 0x06, 0xe4, 0x8b, 0x17, 0x73, 0x0c, 0x16, 0x37, 0x18, 0xf0, 0x25, 0xfe, 0x4c, 0x30, 0xe6, + 0xe4, 0x10, 0xfa, 0x59, 0xd8, 0xc7, 0xb9, 0xdd, 0x3e, 0x6a, 0x1f, 0xf7, 0x97, 0xa5, 0x81, 0x1c, + 0x81, 0x85, 0x22, 0xfa, 0x83, 0xe7, 0x73, 0x8c, 0xec, 0x8e, 0xf4, 0xeb, 0x26, 0x7a, 0x09, 0x64, + 0xf1, 0x1b, 0xd7, 0x09, 0xc7, 0x33, 0x37, 0xbe, 0xda, 0x0c, 0xd5, 0x86, 0x3d, 0xee, 0xc6, 0x57, + 0x9f, 0x31, 0xcd, 0x10, 0xf3, 0x23, 0x71, 0xe0, 0x9e, 0xf8, 0x9d, 0xbb, 0xdc, 0xb5, 0xbb, 0xd2, + 0x55, 0x9c, 0xe9, 0x2f, 0xd8, 0x57, 0xfd, 0x2f, 0x31, 0x4e, 0xfc, 0x0d, 0x07, 0x78, 0x06, 0x20, + 0x00, 0x8c, 0xfe, 0x35, 0x0b, 0xa1, 0x30, 0x60, 0x09, 0x0f, 0x93, 0x7c, 0x42, 0x55, 0xd4, 0xb0, + 0xd1, 0x13, 0xd8, 0x5f, 0x71, 0x37, 0xe2, 0x2b, 0x85, 0xba, 0x51, 0x61, 0x3a, 0x05, 0xb2, 0xe2, + 0x2c, 0xdc, 0x2a, 0xe7, 0x1b, 0xf4, 0x25, 0x37, 0x62, 0x5c, 0x32, 0x82, 0x1d, 0x8c, 0x22, 0x16, + 0x65, 0x61, 0xea, 0x20, 0x2e, 0x48, 0xde, 0x7e, 0x79, 0x77, 0xc5, 0x59, 0x80, 0x63, 0x9e, 0x9e, + 0x0d, 0x52, 0x1a, 0xe8, 0x27, 0x18, 0x1a, 0x44, 0x85, 0x7e, 0x2a, 0xe9, 0x95, 0x36, 0x8f, 0x05, + 0x45, 0x43, 0xba, 0xa9, 0xec, 0xa2, 0xa3, 0x75, 0x41, 0xff, 0xb4, 0x01, 0x14, 0x0b, 0xb7, 0xb4, + 0x5a, 0x01, 0xef, 0xd4, 0xc1, 0x35, 0x1d, 0x74, 0x4d, 0x1d, 0x1c, 0x42, 0x5f, 0x51, 0x20, 0x7c, + 0x3d, 0x35, 0x4a, 0x61, 0x10, 0xa4, 0xaa, 0x83, 0x9c, 0x74, 0x47, 0x91, 0x5a, 0x5a, 0xe8, 0x73, + 0x78, 0x64, 0x12, 0x26, 0x66, 0x6d, 0x6c, 0x92, 0x1e, 0xc3, 0xd0, 0xa0, 0xe9, 0xff, 0x91, 0x33, + 0x18, 0xcd, 0x31, 0xf4, 0x59, 0x5a, 0xa1, 0xf4, 0x05, 0xec, 0x65, 0x0c, 0xca, 0x78, 0x6b, 0x3a, + 0x1c, 0xe7, 0xef, 0x2e, 0x8f, 0xcc, 0x03, 0x84, 0x28, 0x2a, 0x18, 0xa2, 0xde, 0xed, 0xa2, 0x78, + 0x2d, 0xea, 0xfa, 0xc8, 0x71, 0x2b, 0x29, 0x8d, 0x44, 0x25, 0x23, 0x2b, 0xf4, 0xd3, 0xe9, 0xdf, + 0x2e, 0xf4, 0xde, 0xb3, 0x08, 0xc9, 0x5b, 0xb0, 0xb4, 0x5d, 0x40, 0x0e, 0xc6, 0x62, 0xc5, 0xd4, + 0xb7, 0x83, 0xf3, 0x40, 0x3a, 0x0a, 0x51, 0xd2, 0xd6, 0xab, 0x36, 0x39, 0x05, 0x4b, 0x13, 0x52, + 0x96, 0x5b, 0xdf, 0x01, 0xce, 0xe3, 0xba, 0x23, 0xf4, 0x53, 0xda, 0x22, 0xef, 0x60, 0xa0, 0x3f, + 0x64, 0x62, 0x6b, 0xd5, 0x8d, 0xb7, 0xed, 0x3c, 0x94, 0x9e, 0x52, 0x69, 0xb2, 0xfe, 0x0c, 0x06, + 0x3a, 0xbb, 0x59, 0x7a, 0xc3, 0x0b, 0x75, 0x9e, 0x34, 0x78, 0x54, 0x0b, 0xa7, 0x60, 0x69, 0xb4, + 0x67, 0x33, 0xd4, 0xdf, 0x6b, 0x36, 0x43, 0x55, 0x21, 0xb4, 0x45, 0x16, 0x70, 0xdf, 0x60, 0x92, + 0x3c, 0x95, 0x91, 0x4d, 0x0a, 0x71, 0x0e, 0x9a, 0x5c, 0x1a, 0x8c, 0x46, 0x53, 0x01, 0x53, 0x27, + 0xbc, 0x80, 0xa9, 0xb2, 0x4a, 0x5b, 0xb3, 0xdd, 0xaf, 0x3d, 0xb1, 0xf8, 0xcf, 0x77, 0xe5, 0xa6, + 0x3f, 0xf9, 0x17, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x3f, 0x12, 0xf8, 0x5b, 0x06, 0x00, 0x00, } diff --git a/api/core/api.proto b/api/core/api.proto index 22e8a1340..6c26fcc88 100644 --- a/api/core/api.proto +++ b/api/core/api.proto @@ -17,6 +17,7 @@ service Core { message ListenEventRequest { string serviceID = 1; + string eventFilter = 2; } message ExecuteTaskRequest { @@ -27,6 +28,8 @@ message ExecuteTaskRequest { message ListenResultRequest { string serviceID = 1; + string taskFilter = 2; + string outputFilter = 3; } message StartServiceRequest { diff --git a/api/core/listen_event.go b/api/core/listen_event.go index c5705835a..7a3731db6 100644 --- a/api/core/listen_event.go +++ b/api/core/listen_event.go @@ -2,8 +2,11 @@ package core import ( "encoding/json" + "errors" "github.com/mesg-foundation/core/database/services" + service "github.com/mesg-foundation/core/service" + "github.com/mesg-foundation/core/utils/array" "github.com/mesg-foundation/core/event" "github.com/mesg-foundation/core/pubsub" @@ -15,14 +18,35 @@ func (s *Server) ListenEvent(request *ListenEventRequest, stream Core_ListenEven if err != nil { return } + if err = validateEventKey(&service, request.EventFilter); err != nil { + return + } subscription := pubsub.Subscribe(service.EventSubscriptionChannel()) for data := range subscription { event := data.(*event.Event) - eventData, _ := json.Marshal(event.Data) - stream.Send(&EventData{ - EventKey: event.Key, - EventData: string(eventData), - }) + if isSubscribedEvent(request, event) { + eventData, _ := json.Marshal(event.Data) + stream.Send(&EventData{ + EventKey: event.Key, + EventData: string(eventData), + }) + } } return } + +func validateEventKey(service *service.Service, eventKey string) (err error) { + if eventKey == "" || eventKey == "*" { + return + } + _, ok := service.Events[eventKey] + if ok { + return + } + err = errors.New("Event '" + eventKey + "' doesn't exist in this service") + return +} + +func isSubscribedEvent(request *ListenEventRequest, e *event.Event) bool { + return array.IncludedIn([]string{"", "*", e.Key}, request.EventFilter) +} diff --git a/api/core/listen_event_test.go b/api/core/listen_event_test.go new file mode 100644 index 000000000..bf32a4f60 --- /dev/null +++ b/api/core/listen_event_test.go @@ -0,0 +1,39 @@ +package core + +import ( + "testing" + + "github.com/mesg-foundation/core/event" + "github.com/mesg-foundation/core/service" + "github.com/stvp/assert" +) + +func TestValidateEventKey(t *testing.T) { + s := &service.Service{ + Events: map[string]*service.Event{ + "test": &service.Event{}, + }, + } + assert.Nil(t, validateEventKey(s, "")) + assert.Nil(t, validateEventKey(s, "*")) + assert.Nil(t, validateEventKey(s, "test")) + assert.NotNil(t, validateEventKey(s, "xxx")) +} + +func TestIsSubscribedEvent(t *testing.T) { + e := &event.Event{Key: "test"} + r := &ListenEventRequest{} + assert.True(t, isSubscribedEvent(r, e)) + + r = &ListenEventRequest{EventFilter: ""} + assert.True(t, isSubscribedEvent(r, e)) + + r = &ListenEventRequest{EventFilter: "*"} + assert.True(t, isSubscribedEvent(r, e)) + + r = &ListenEventRequest{EventFilter: "test"} + assert.True(t, isSubscribedEvent(r, e)) + + r = &ListenEventRequest{EventFilter: "xxx"} + assert.False(t, isSubscribedEvent(r, e)) +} diff --git a/api/core/listen_result.go b/api/core/listen_result.go index 52ebf398c..7cc3e2c89 100644 --- a/api/core/listen_result.go +++ b/api/core/listen_result.go @@ -2,29 +2,80 @@ package core import ( "encoding/json" + "errors" "github.com/mesg-foundation/core/database/services" + service "github.com/mesg-foundation/core/service" + "github.com/mesg-foundation/core/utils/array" "github.com/mesg-foundation/core/execution" "github.com/mesg-foundation/core/pubsub" ) -// ListenResult will listne for results from a services +// ListenResult will listen for results from a services func (s *Server) ListenResult(request *ListenResultRequest, stream Core_ListenResultServer) (err error) { service, err := services.Get(request.ServiceID) if err != nil { return } + if err = validateTaskKey(&service, request.TaskFilter); err != nil { + return + } + if err = validateOutputKey(&service, request.TaskFilter, request.OutputFilter); err != nil { + return + } subscription := pubsub.Subscribe(service.ResultSubscriptionChannel()) for data := range subscription { execution := data.(*execution.Execution) - outputs, _ := json.Marshal(execution.OutputData) - stream.Send(&ResultData{ - ExecutionID: execution.ID, - TaskKey: execution.Task, - OutputKey: execution.Output, - OutputData: string(outputs), - }) + if isSubscribedTask(request, execution) && isSubscribedOutput(request, execution) { + outputs, _ := json.Marshal(execution.OutputData) + stream.Send(&ResultData{ + ExecutionID: execution.ID, + TaskKey: execution.Task, + OutputKey: execution.Output, + OutputData: string(outputs), + }) + } } return } + +func validateTaskKey(service *service.Service, taskKey string) (err error) { + if taskKey == "" || taskKey == "*" { + return + } + _, ok := service.Tasks[taskKey] + if ok { + return + } + err = errors.New("Task '" + taskKey + "' doesn't exist in this service") + return +} + +func validateOutputKey(service *service.Service, taskKey string, outputFilter string) (err error) { + if outputFilter == "" || outputFilter == "*" { + return + } + if taskKey == "" { + err = errors.New("Cannot filter output without specifying a task") + return + } + task, ok := service.Tasks[taskKey] + if !ok { + err = errors.New("Task '" + taskKey + "' doesn't exist in this service") + return + } + _, ok = task.Outputs[outputFilter] + if !ok { + err = errors.New("Output '" + outputFilter + "' doesn't exist in the task '" + taskKey + "' of this service") + } + return +} + +func isSubscribedTask(request *ListenResultRequest, e *execution.Execution) bool { + return array.IncludedIn([]string{"", "*", e.Task}, request.TaskFilter) +} + +func isSubscribedOutput(request *ListenResultRequest, e *execution.Execution) bool { + return array.IncludedIn([]string{"", "*", e.Output}, request.OutputFilter) +} diff --git a/api/core/listen_result_test.go b/api/core/listen_result_test.go new file mode 100644 index 000000000..b8ccba14c --- /dev/null +++ b/api/core/listen_result_test.go @@ -0,0 +1,77 @@ +package core + +import ( + "testing" + + "github.com/mesg-foundation/core/execution" + "github.com/mesg-foundation/core/service" + "github.com/stvp/assert" +) + +func TestValidateTaskKey(t *testing.T) { + s := &service.Service{ + Tasks: map[string]*service.Task{ + "test": &service.Task{}, + }, + } + assert.Nil(t, validateTaskKey(s, "")) + assert.Nil(t, validateTaskKey(s, "*")) + assert.Nil(t, validateTaskKey(s, "test")) + assert.NotNil(t, validateTaskKey(s, "xxx")) +} + +func TestValidateOutputKey(t *testing.T) { + s := &service.Service{ + Tasks: map[string]*service.Task{ + "test": &service.Task{ + Outputs: map[string]*service.Output{ + "outputx": &service.Output{}, + }, + }, + }, + } + assert.Nil(t, validateOutputKey(s, "test", "")) + assert.Nil(t, validateOutputKey(s, "test", "*")) + assert.Nil(t, validateOutputKey(s, "test", "outputx")) + assert.NotNil(t, validateOutputKey(s, "test", "xxx")) + assert.Nil(t, validateOutputKey(s, "xxx", "")) + assert.Nil(t, validateOutputKey(s, "xxx", "*")) + assert.NotNil(t, validateOutputKey(s, "xxx", "outputX")) + assert.NotNil(t, validateOutputKey(s, "xxx", "xxx")) +} + +func TestIsSubscribedTask(t *testing.T) { + x := &execution.Execution{Task: "task"} + r := &ListenResultRequest{} + assert.True(t, isSubscribedTask(r, x)) + + r = &ListenResultRequest{TaskFilter: ""} + assert.True(t, isSubscribedTask(r, x)) + + r = &ListenResultRequest{TaskFilter: "*"} + assert.True(t, isSubscribedTask(r, x)) + + r = &ListenResultRequest{TaskFilter: "task"} + assert.True(t, isSubscribedTask(r, x)) + + r = &ListenResultRequest{TaskFilter: "xxx"} + assert.False(t, isSubscribedTask(r, x)) +} + +func TestIsSubscribedOutput(t *testing.T) { + x := &execution.Execution{Output: "output"} + r := &ListenResultRequest{} + assert.True(t, isSubscribedOutput(r, x)) + + r = &ListenResultRequest{OutputFilter: ""} + assert.True(t, isSubscribedOutput(r, x)) + + r = &ListenResultRequest{OutputFilter: "*"} + assert.True(t, isSubscribedOutput(r, x)) + + r = &ListenResultRequest{OutputFilter: "output"} + assert.True(t, isSubscribedOutput(r, x)) + + r = &ListenResultRequest{OutputFilter: "xxx"} + assert.False(t, isSubscribedOutput(r, x)) +} diff --git a/cmd/service/test.go b/cmd/service/test.go index 85f8c54e3..1e9527385 100644 --- a/cmd/service/test.go +++ b/cmd/service/test.go @@ -32,7 +32,8 @@ mesg-core service test --keep-alive`, func listenEvents(serviceID string, filter string) { stream, err := cli.ListenEvent(context.Background(), &core.ListenEventRequest{ - ServiceID: serviceID, + ServiceID: serviceID, + EventFilter: filter, }) handleError(err) for { @@ -41,15 +42,15 @@ func listenEvents(serviceID string, filter string) { log.Println(aurora.Red(err)) return } - if filter == "*" || filter == event.EventKey { - log.Println("Receive event", aurora.Green(event.EventKey), ":", aurora.Bold(event.EventData)) - } + log.Println("Receive event", aurora.Green(event.EventKey), ":", aurora.Bold(event.EventData)) } } -func listenResults(serviceID string) { +func listenResults(serviceID string, result string, output string) { stream, err := cli.ListenResult(context.Background(), &core.ListenResultRequest{ - ServiceID: serviceID, + ServiceID: serviceID, + TaskFilter: result, + OutputFilter: output, }) handleError(err) for { @@ -58,7 +59,7 @@ func listenResults(serviceID string) { log.Println(aurora.Red(err)) return } - log.Println("Receive result", aurora.Green(result.TaskKey), aurora.Green(result.OutputKey), ":", aurora.Bold(result.OutputData)) + log.Println("Receive result", aurora.Green(result.TaskKey), aurora.Cyan(result.OutputKey), ":", aurora.Bold(result.OutputData)) } } @@ -83,41 +84,53 @@ func executeTask(serviceID string, task string, dataPath string) (execution *cor } func testHandler(cmd *cobra.Command, args []string) { - service := loadService(defaultPath(args)) - imageHash := buildDockerImage(defaultPath(args)) - injectConfigurationInDependencies(service, imageHash) - - deployment, err := cli.DeployService(context.Background(), &core.DeployServiceRequest{ - Service: service, - }) - handleError(err) + var err error + serviceID := cmd.Flag("serviceID").Value.String() + if serviceID == "" { + service := loadService(defaultPath(args)) + imageHash := buildDockerImage(defaultPath(args)) + injectConfigurationInDependencies(service, imageHash) + + deployment, err := cli.DeployService(context.Background(), &core.DeployServiceRequest{ + Service: service, + }) + handleError(err) + serviceID = deployment.ServiceID + fmt.Println("Service deployed with success with service ID:", serviceID) - cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Starting service..."}, func() { - _, err = cli.StartService(context.Background(), &core.StartServiceRequest{ - ServiceID: deployment.ServiceID, + cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Starting service..."}, func() { + _, err = cli.StartService(context.Background(), &core.StartServiceRequest{ + ServiceID: serviceID, + }) }) - }) - handleError(err) - fmt.Println(aurora.Green("Service started")) + handleError(err) + fmt.Println(aurora.Green("Service started")) + } - go listenEvents(deployment.ServiceID, cmd.Flag("event").Value.String()) - go listenResults(deployment.ServiceID) + go listenEvents(serviceID, cmd.Flag("event-filter").Value.String()) + go listenResults(serviceID, cmd.Flag("task-filter").Value.String(), cmd.Flag("output-filter").Value.String()) time.Sleep(time.Second) - executeTask(deployment.ServiceID, cmd.Flag("task").Value.String(), cmd.Flag("data").Value.String()) + executeTask(serviceID, cmd.Flag("task").Value.String(), cmd.Flag("data").Value.String()) <-cmdUtils.WaitForCancel() - cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Stopping service..."}, func() { - _, err = cli.StopService(context.Background(), &core.StopServiceRequest{ - ServiceID: deployment.ServiceID, + if cmd.Flag("keep-alive").Value.String() != "true" { + cmdUtils.ShowSpinnerForFunc(cmdUtils.SpinnerOptions{Text: "Stopping service..."}, func() { + _, err = cli.StopService(context.Background(), &core.StopServiceRequest{ + ServiceID: serviceID, + }) }) - }) - handleError(err) - fmt.Println(aurora.Green("Service stopped")) + handleError(err) + fmt.Println(aurora.Green("Service stopped")) + } } func init() { - Test.Flags().StringP("event", "e", "*", "Only log a specific event") - Test.Flags().StringP("task", "t", "", "Run a specific task") + Test.Flags().StringP("event-filter", "e", "*", "Only log the data of the given event") + Test.Flags().StringP("task", "t", "", "Run the given task") Test.Flags().StringP("data", "d", "", "Path to the file containing the data required to run the task") + Test.Flags().StringP("task-filter", "r", "", "Only log the result of the given task") + Test.Flags().StringP("output-filter", "o", "", "Only log the data of the given output of a task result. If set, you also need to set the task in --result") + Test.Flags().StringP("serviceID", "s", "", "ID of a previously deployed service") + Test.Flags().BoolP("keep-alive", "", false, "Do not stop the service at the end of this command") } diff --git a/docs/cli/mesg-cli.md b/docs/cli/mesg-cli.md deleted file mode 100644 index d1ad554c4..000000000 --- a/docs/cli/mesg-cli.md +++ /dev/null @@ -1,19 +0,0 @@ -## mesg-cli - -MESG CLI - -### Synopsis - -MESG CLI - -### Options - -``` - -h, --help help for mesg-cli -``` - -### SEE ALSO - -* [mesg-cli daemon](mesg-cli_daemon.md) - Manage your MESG daemon -* [mesg-cli service](mesg-cli_service.md) - Manage your services - diff --git a/docs/cli/mesg-cli_daemon.md b/docs/cli/mesg-cli_daemon.md deleted file mode 100644 index 34d227e8d..000000000 --- a/docs/cli/mesg-cli_daemon.md +++ /dev/null @@ -1,21 +0,0 @@ -## mesg-cli daemon - -Manage your MESG daemon - -### Synopsis - -Manage your MESG daemon - -### Options - -``` - -h, --help help for daemon -``` - -### SEE ALSO - -* [mesg-cli](mesg-cli.md) - MESG CLI -* [mesg-cli daemon start](mesg-cli_daemon_start.md) - Start the daemon -* [mesg-cli daemon status](mesg-cli_daemon_status.md) - Status of the daemon -* [mesg-cli daemon stop](mesg-cli_daemon_stop.md) - Stop the daemon - diff --git a/docs/cli/mesg-core.md b/docs/cli/mesg-core.md index 8ecd7b065..0ebaa1bf0 100644 --- a/docs/cli/mesg-core.md +++ b/docs/cli/mesg-core.md @@ -6,10 +6,6 @@ MESG CORE MESG CORE -``` -mesg-core [flags] -``` - ### Options ``` @@ -18,5 +14,6 @@ mesg-core [flags] ### SEE ALSO +* [mesg-core daemon](mesg-core_daemon.md) - Manage the MESG daemon * [mesg-core service](mesg-core_service.md) - Manage your services diff --git a/docs/cli/mesg-core_daemon.md b/docs/cli/mesg-core_daemon.md new file mode 100644 index 000000000..08bcec0b5 --- /dev/null +++ b/docs/cli/mesg-core_daemon.md @@ -0,0 +1,22 @@ +## mesg-core daemon + +Manage the MESG daemon + +### Synopsis + +Manage the MESG daemon + +### Options + +``` + -h, --help help for daemon +``` + +### SEE ALSO + +* [mesg-core](mesg-core.md) - MESG CORE +* [mesg-core daemon logs](mesg-core_daemon_logs.md) - Show the daemon's logs +* [mesg-core daemon start](mesg-core_daemon_start.md) - Start the daemon +* [mesg-core daemon status](mesg-core_daemon_status.md) - Status of the daemon +* [mesg-core daemon stop](mesg-core_daemon_stop.md) - Stop the daemon + diff --git a/docs/cli/mesg-core_daemon_logs.md b/docs/cli/mesg-core_daemon_logs.md new file mode 100644 index 000000000..05b97c7c1 --- /dev/null +++ b/docs/cli/mesg-core_daemon_logs.md @@ -0,0 +1,22 @@ +## mesg-core daemon logs + +Show the daemon's logs + +### Synopsis + +Show the daemon's logs + +``` +mesg-core daemon logs [flags] +``` + +### Options + +``` + -h, --help help for logs +``` + +### SEE ALSO + +* [mesg-core daemon](mesg-core_daemon.md) - Manage the MESG daemon + diff --git a/docs/cli/mesg-cli_daemon_start.md b/docs/cli/mesg-core_daemon_start.md similarity index 50% rename from docs/cli/mesg-cli_daemon_start.md rename to docs/cli/mesg-core_daemon_start.md index c361a5ab3..25053e932 100644 --- a/docs/cli/mesg-cli_daemon_start.md +++ b/docs/cli/mesg-core_daemon_start.md @@ -1,4 +1,4 @@ -## mesg-cli daemon start +## mesg-core daemon start Start the daemon @@ -7,7 +7,7 @@ Start the daemon Start the daemon ``` -mesg-cli daemon start [flags] +mesg-core daemon start [flags] ``` ### Options @@ -18,5 +18,5 @@ mesg-cli daemon start [flags] ### SEE ALSO -* [mesg-cli daemon](mesg-cli_daemon.md) - Manage your MESG daemon +* [mesg-core daemon](mesg-core_daemon.md) - Manage the MESG daemon diff --git a/docs/cli/mesg-cli_daemon_status.md b/docs/cli/mesg-core_daemon_status.md similarity index 51% rename from docs/cli/mesg-cli_daemon_status.md rename to docs/cli/mesg-core_daemon_status.md index 7c1c4b1c4..ea80125d2 100644 --- a/docs/cli/mesg-cli_daemon_status.md +++ b/docs/cli/mesg-core_daemon_status.md @@ -1,4 +1,4 @@ -## mesg-cli daemon status +## mesg-core daemon status Status of the daemon @@ -7,7 +7,7 @@ Status of the daemon Status of the daemon ``` -mesg-cli daemon status [flags] +mesg-core daemon status [flags] ``` ### Options @@ -18,5 +18,5 @@ mesg-cli daemon status [flags] ### SEE ALSO -* [mesg-cli daemon](mesg-cli_daemon.md) - Manage your MESG daemon +* [mesg-core daemon](mesg-core_daemon.md) - Manage the MESG daemon diff --git a/docs/cli/mesg-cli_daemon_stop.md b/docs/cli/mesg-core_daemon_stop.md similarity index 50% rename from docs/cli/mesg-cli_daemon_stop.md rename to docs/cli/mesg-core_daemon_stop.md index b94368f67..c3f2ac8aa 100644 --- a/docs/cli/mesg-cli_daemon_stop.md +++ b/docs/cli/mesg-core_daemon_stop.md @@ -1,4 +1,4 @@ -## mesg-cli daemon stop +## mesg-core daemon stop Stop the daemon @@ -7,7 +7,7 @@ Stop the daemon Stop the daemon ``` -mesg-cli daemon stop [flags] +mesg-core daemon stop [flags] ``` ### Options @@ -18,5 +18,5 @@ mesg-cli daemon stop [flags] ### SEE ALSO -* [mesg-cli daemon](mesg-cli_daemon.md) - Manage your MESG daemon +* [mesg-core daemon](mesg-core_daemon.md) - Manage the MESG daemon diff --git a/docs/cli/mesg-core_service.md b/docs/cli/mesg-core_service.md index a3cb0b7be..1066f049b 100644 --- a/docs/cli/mesg-core_service.md +++ b/docs/cli/mesg-core_service.md @@ -15,8 +15,11 @@ Manage your services ### SEE ALSO * [mesg-core](mesg-core.md) - MESG CORE +* [mesg-core service delete](mesg-core_service_delete.md) - Delete a service +* [mesg-core service deploy](mesg-core_service_deploy.md) - Deploy a service * [mesg-core service detail](mesg-core_service_detail.md) - Show details of a published service * [mesg-core service init](mesg-core_service_init.md) - Initialize a service +* [mesg-core service list](mesg-core_service_list.md) - List all published services * [mesg-core service start](mesg-core_service_start.md) - Start a service * [mesg-core service status](mesg-core_service_status.md) - List started services * [mesg-core service stop](mesg-core_service_stop.md) - Stop a service diff --git a/docs/cli/mesg-core_service_delete.md b/docs/cli/mesg-core_service_delete.md new file mode 100644 index 000000000..764305bfc --- /dev/null +++ b/docs/cli/mesg-core_service_delete.md @@ -0,0 +1,28 @@ +## mesg-core service delete + +Delete a service + +### Synopsis + +Delete a service + +``` +mesg-core service delete [flags] +``` + +### Examples + +``` +mesg-core service delete +``` + +### Options + +``` + -h, --help help for delete +``` + +### SEE ALSO + +* [mesg-core service](mesg-core_service.md) - Manage your services + diff --git a/docs/cli/mesg-core_service_deploy.md b/docs/cli/mesg-core_service_deploy.md new file mode 100644 index 000000000..fd2e00803 --- /dev/null +++ b/docs/cli/mesg-core_service_deploy.md @@ -0,0 +1,30 @@ +## mesg-core service deploy + +Deploy a service + +### Synopsis + +Deploy a service on the Network. + +To get more information, see the [deploy page from the documentation](https://docs.mesg.tech/service/publish-a-service) + +``` +mesg-core service deploy [flags] +``` + +### Examples + +``` +mesg-core sevice deploy +``` + +### Options + +``` + -h, --help help for deploy +``` + +### SEE ALSO + +* [mesg-core service](mesg-core_service.md) - Manage your services + diff --git a/docs/cli/mesg-core_service_detail.md b/docs/cli/mesg-core_service_detail.md index 07f6522cc..c03769448 100644 --- a/docs/cli/mesg-core_service_detail.md +++ b/docs/cli/mesg-core_service_detail.md @@ -7,13 +7,13 @@ Show details of a published service Show details of a published service ``` -mesg-core service detail SERVICE_FOLDER [flags] +mesg-core service detail SERVICE_ID [flags] ``` ### Examples ``` -mesg-core service detail SERVICE_FOLDER +mesg-core service detail SERVICE_ID ``` ### Options diff --git a/docs/cli/mesg-core_service_list.md b/docs/cli/mesg-core_service_list.md new file mode 100644 index 000000000..1cb2417d1 --- /dev/null +++ b/docs/cli/mesg-core_service_list.md @@ -0,0 +1,30 @@ +## mesg-core service list + +List all published services + +### Synopsis + +This command returns all published services with basic information. +Optionally, you can filter the services published by a specific developer: +To have more details, see the [detail command](mesg-core_service_detail.md). + +``` +mesg-core service list [flags] +``` + +### Examples + +``` +mesg-core service list +``` + +### Options + +``` + -h, --help help for list +``` + +### SEE ALSO + +* [mesg-core service](mesg-core_service.md) - Manage your services + diff --git a/docs/cli/mesg-core_service_start.md b/docs/cli/mesg-core_service_start.md index 5936283a0..9f853663f 100644 --- a/docs/cli/mesg-core_service_start.md +++ b/docs/cli/mesg-core_service_start.md @@ -7,13 +7,13 @@ Start a service Start a service from the published available services. You have to provide a stake value and duration. ``` -mesg-core service start SERVICE_FOLDER [flags] +mesg-core service start SERVICE_ID [flags] ``` ### Examples ``` -mesg-core service start SERVICE_FOLDER +mesg-core service start SERVICE_ID ``` ### Options diff --git a/docs/cli/mesg-core_service_stop.md b/docs/cli/mesg-core_service_stop.md index 0d08b5a96..2b0043f48 100644 --- a/docs/cli/mesg-core_service_stop.md +++ b/docs/cli/mesg-core_service_stop.md @@ -11,13 +11,13 @@ You will **NOT** get your stake back immediately. You will get your remaining st To have more explanation, see the page [stake explanation from the documentation](). ``` -mesg-core service stop SERVICE_FOLDER [flags] +mesg-core service stop SERVICE_ID [flags] ``` ### Examples ``` -mesg-core service stop SERVICE_FOLDER +mesg-core service stop SERVICE_ID ``` ### Options diff --git a/docs/cli/mesg-core_service_test.md b/docs/cli/mesg-core_service_test.md index 82a280547..ae50802a0 100644 --- a/docs/cli/mesg-core_service_test.md +++ b/docs/cli/mesg-core_service_test.md @@ -25,10 +25,14 @@ mesg-core service test --keep-alive ### Options ``` - -d, --data string Path to the file containing the data required to run the task - -e, --event string Only log a specific event (default "*") - -h, --help help for test - -t, --task string Run a specific task + -d, --data string Path to the file containing the data required to run the task + -e, --event string Only log a specific event (default "*") + -h, --help help for test + --keep-alive Do not stop the service + -o, --output string Filter output of a task + -r, --result string Filter the result of a specific task + -s, --service string Debug a deployed service + -t, --task string Run a specific task ``` ### SEE ALSO diff --git a/utils/array/include.go b/utils/array/include.go new file mode 100644 index 000000000..31908403a --- /dev/null +++ b/utils/array/include.go @@ -0,0 +1,16 @@ +package array + +// IncludedIn returns true if the element value is in the arr, otherwise return false +func IncludedIn(arr []string, value string) bool { + if len(arr) == 0 { + return false + } + i := 0 + for _, item := range arr { + if item == value { + break + } + i++ + } + return i != len(arr) +} diff --git a/utils/array/include_test.go b/utils/array/include_test.go new file mode 100644 index 000000000..f7b845dc6 --- /dev/null +++ b/utils/array/include_test.go @@ -0,0 +1,18 @@ +package array + +import ( + "testing" + + "github.com/stvp/assert" +) + +func TestIncludedIn(t *testing.T) { + assert.False(t, IncludedIn([]string{}, "")) + assert.True(t, IncludedIn([]string{""}, "")) + assert.False(t, IncludedIn([]string{"a"}, "")) + assert.True(t, IncludedIn([]string{"a"}, "a")) + assert.False(t, IncludedIn([]string{""}, "a")) + assert.True(t, IncludedIn([]string{"a", "b"}, "a")) + assert.True(t, IncludedIn([]string{"a", "b"}, "b")) + assert.False(t, IncludedIn([]string{"a", "b"}, "c")) +}