Skip to content

Commit

Permalink
feat(app): Add Custom Trigger Example
Browse files Browse the repository at this point in the history
Introduce an example for the custom trigger functionality introduced to
the SDK in edgexfoundry/app-functions-sdk-go#587

Signed-off-by: Alex Ullrich <alexullrich@technotects.com>
  • Loading branch information
Alex Ullrich committed Jan 11, 2021
1 parent cb139d8 commit cdc57be
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 31 deletions.
32 changes: 1 addition & 31 deletions application-services/custom/cloud-event/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,37 +93,7 @@ func gotEvent(ctx context.Context, event cloudevents.Event) {
var readingData string
event.DataAs(&readingData)
fmt.Printf("CloudEvent received reading value: %v\n", readingData)
}

// App function to send the cloudevent to the receiver
func sendCloudEvents(edgexcontext *appcontext.Context, params ...interface{}) (bool, interface{}) {
edgexcontext.LoggingClient.Info("sendCloudEvent")
if len(params) < 1 {
return false, errors.New("No Event Received")
}

events, ok := params[0].([]cloudevents.Event)
if !ok {
return false, errors.New("Cloud event not received")
}
ctx := cloudevents.ContextWithTarget(context.Background(), "http://localhost:8080/")
ctx = cloudevents.ContextWithHeader(ctx, "demo", "header value")
c, err := cloudevents.NewDefaultClient()
if err != nil {
edgexcontext.LoggingClient.Error(fmt.Sprintf("failed to create client, %v", err))
return false, nil
}
for _, cloudevent := range events {
if _, resp, err := c.Send(ctx, cloudevent); err != nil {
edgexcontext.LoggingClient.Error(fmt.Sprintf("failed to send: %v", err))
return false, nil
} else if resp != nil {
// don't need a response back, in this example we aren't expecting/sending one
edgexcontext.LoggingClient.Info(fmt.Sprintf("got back a response: %s", resp))
}
}
return true, events
}
}z

func printToConsole(edgexcontext *appcontext.Context, params ...interface{}) (bool, interface{}) {
edgexcontext.LoggingClient.Info("PrintToConsole")
Expand Down
46 changes: 46 additions & 0 deletions application-services/custom/custom-trigger/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# Copyright (c) 2019 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

FROM golang:1.15-alpine AS builder

LABEL license='SPDX-License-Identifier: Apache-2.0' \
copyright='Copyright (c) 2019: Intel'

# add git for go modules
RUN apk update && apk add --no-cache make git gcc libc-dev libsodium-dev zeromq-dev
WORKDIR /custom-trigger

COPY go.mod .

RUN go mod download

COPY . .
RUN apk info -a zeromq-dev

RUN make build

# Next image - Copy built Go binary into new workspace
FROM alpine

LABEL license='SPDX-License-Identifier: Apache-2.0' \
copyright='Copyright (c) 2019: Intel'

RUN apk --no-cache add zeromq

COPY --from=builder /custom-trigger/res /res
COPY --from=builder /custom-trigger/app-service /custom-trigger

CMD [ "/custom-trigger", "--confdir=/res"]
17 changes: 17 additions & 0 deletions application-services/custom/custom-trigger/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.PHONY: build clean

GO=CGO_ENABLED=1 GO111MODULE=on go

build:
$(GO) build -o app-service

docker:
docker build \
--build-arg http_proxy \
--build-arg https_proxy \
-f Dockerfile \
-t edgexfoundry/docker-custom-trigger-example:dev \
.

clean:
rm -f app-service
11 changes: 11 additions & 0 deletions application-services/custom/custom-trigger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Custom-Trigger

Custom-Trigger provides an example for using a custom trigger with the app functions SDK.

## Overview

In this example we introduce a trigger that listens for input on os.Stdin and sends it through the function pipeline. The function pipeline is a single function that introduce a slight delay based on the length of the input string and then print it to the console.

To run:

`make docker && docker run -it edgexfoundry/docker-custom-trigger-example:dev`
10 changes: 10 additions & 0 deletions application-services/custom/custom-trigger/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module custom-trigger

go 1.15

require (
github.com/cloudevents/sdk-go v1.1.2
github.com/edgexfoundry/app-functions-sdk-go v1.3.1-dev.16
github.com/edgexfoundry/go-mod-core-contracts v0.1.112
github.com/stretchr/testify v1.6.1
)
141 changes: 141 additions & 0 deletions application-services/custom/custom-trigger/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//
// Copyright (c) 2019 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package main

import (
"bufio"
"context"
"fmt"
"github.com/edgexfoundry/app-functions-sdk-go/appcontext"
"github.com/edgexfoundry/app-functions-sdk-go/appsdk"
"github.com/edgexfoundry/app-functions-sdk-go/pkg/util"
"github.com/edgexfoundry/go-mod-bootstrap/bootstrap"
"github.com/edgexfoundry/go-mod-messaging/pkg/types"
"os"
"strings"
"sync"
"time"
)

const (
serviceKey = "customTrigger"
)

type stdinTrigger struct{
tc appsdk.TriggerConfig
}

func (t *stdinTrigger) Initialize(wg *sync.WaitGroup, ctx context.Context, background <-chan types.MessageEnvelope) (bootstrap.Deferred, error) {
msgs := make(chan []byte)

ctx, cancel := context.WithCancel(context.Background())

receiveMessage := true

go func() {
fmt.Print("> ")
rdr := bufio.NewReader(os.Stdin)
for receiveMessage {
s, err := rdr.ReadString('\n')
s = strings.TrimRight(s, "\n")

if err != nil {
t.tc.Logger.Error(err.Error())
continue
}

msgs <- []byte(s)
}
}()

for receiveMessage {
select {
case <- ctx.Done():
receiveMessage = false
case m := <- msgs:
go func() {
env := types.MessageEnvelope{
Payload: m,
}

ctx := t.tc.ContextBuilder(env)

err := t.tc.MessageProcessor(ctx, env)

if err != nil {
t.tc.Logger.Error(err.Error())
}
}()
}


}
return func() {
cancel()
}, nil
}

func main() {
// turn off secure mode for examples. Not recommended for production
os.Setenv("EDGEX_SECURITY_SECRET_STORE", "false")
// First thing to do is to create an instance of the EdgeX SDK and initialize it.
edgexSdk := &appsdk.AppFunctionsSDK{ServiceKey: serviceKey, TargetType: &[]byte{} }

if err := edgexSdk.Initialize(); err != nil {
edgexSdk.LoggingClient.Error(fmt.Sprintf("SDK initialization failed: %v\n", err))
os.Exit(-1)
}

edgexSdk.RegisterCustomTriggerFactory("custom-stdin", func(config appsdk.TriggerConfig) (appsdk.Trigger, error) {
return &stdinTrigger{
tc: config,
}, nil
})

edgexSdk.SetFunctionsPipeline(
printToConsole,
)

// Lastly, we'll go ahead and tell the SDK to "start" and begin listening for events
err := edgexSdk.MakeItRun()
if err != nil {
edgexSdk.LoggingClient.Error("MakeItRun returned error: ", err.Error())
os.Exit(-1)
}

// Do any required cleanup here
os.Exit(0)
}

func printToConsole(edgexcontext *appcontext.Context, params ...interface{}) (bool, interface{}) {
input, err := util.CoerceType(params[0])

if err != nil {
edgexcontext.LoggingClient.Error(err.Error())
return false, err
}

wait := time.Millisecond * time.Duration(len(input))

time.Sleep(wait)

edgexcontext.LoggingClient.Info("PrintToConsole")

os.Stdout.WriteString(fmt.Sprintf("'%s' received %s ago\n>", string(input), wait.String()))

return false, nil
}
25 changes: 25 additions & 0 deletions application-services/custom/custom-trigger/res/configuration.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[Writable]
LogLevel = 'INFO'

[Service]
BootTimeout = '30s'
ClientMonitor = '15s'
CheckInterval = '10s'
Host = 'localhost'
Port = 48095
Protocol = 'http'
ReadMaxLimit = 100
StartupMsg = 'Cloud Event Transforms'
Timeout = '5s'

[Registry]
Host = 'localhost'
Port = 8500
Type = 'consul'

[Logging]
EnableRemote = false
File = ''

[Binding]
Type="custom-stdin"

0 comments on commit cdc57be

Please sign in to comment.