Skip to content

Commit

Permalink
shadow: Support named shadow (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamatama41 authored Feb 10, 2021
1 parent cc2c9dd commit 786f4a1
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 7 deletions.
9 changes: 5 additions & 4 deletions examples/shadow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import (
"time"

"github.com/at-wat/mqtt-go"
"github.com/seqsense/aws-iot-device-sdk-go/v4"
awsiotdev "github.com/seqsense/aws-iot-device-sdk-go/v4"
"github.com/seqsense/aws-iot-device-sdk-go/v4/shadow"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if len(os.Args) != 3 {
println("usage: shadow AWS_IOT_ENDPOINT THING_NAME")
if len(os.Args) != 4 {
println("usage: shadow AWS_IOT_ENDPOINT THING_NAME SHADOW_NAME")
println("")
println("This example updates and deletes AWS IoT Thing Shadow.")
println("THING_NAME must be registered to your account of AWS IoT beforehand.")
Expand All @@ -43,6 +43,7 @@ func main() {
}
host := os.Args[1]
thingName := os.Args[2]
shadowName := os.Args[3]

for _, file := range []string{
"root-CA.crt",
Expand Down Expand Up @@ -88,7 +89,7 @@ func main() {
panic(err)
}

s, err := shadow.New(ctx, cli)
s, err := shadow.New(ctx, cli, shadow.WithName(shadowName))
if err != nil {
panic(err)
}
Expand Down
31 changes: 31 additions & 0 deletions shadow/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2020-2021 SEQSENSE, Inc.
//
// 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 shadow

// Options stores Device Shadow options.
type Options struct {
Name string
}

// Option is a functional option of UpdateJob.
type Option func(options *Options) error

// WithName sets shadow name.
func WithName(name string) Option {
return func(o *Options) error {
o.Name = name
return nil
}
}
18 changes: 15 additions & 3 deletions shadow/shadow.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (

"github.com/at-wat/mqtt-go"

"github.com/seqsense/aws-iot-device-sdk-go/v4"
awsiotdev "github.com/seqsense/aws-iot-device-sdk-go/v4"
"github.com/seqsense/aws-iot-device-sdk-go/v4/internal/ioterr"
)

Expand Down Expand Up @@ -57,6 +57,7 @@ type shadow struct {
mqtt.ServeMux
cli mqtt.Client
thingName string
name string
doc *ThingDocument
mu sync.Mutex
onDelta func(delta map[string]interface{})
Expand All @@ -73,7 +74,11 @@ func (s *shadow) token() string {
}

func (s *shadow) topic(operation string) string {
return "$aws/things/" + s.thingName + "/shadow/" + operation
prefix := "$aws/things/" + s.thingName + "/shadow"
if s.name != "" {
prefix += "/name/" + s.name
}
return prefix + "/" + operation
}

func (s *shadow) handleResponse(r interface{}) {
Expand Down Expand Up @@ -160,10 +165,17 @@ func (s *shadow) deleteAccepted(msg *mqtt.Message) {
}

// New creates Thing Shadow interface.
func New(ctx context.Context, cli awsiotdev.Device) (Shadow, error) {
func New(ctx context.Context, cli awsiotdev.Device, opt ...Option) (Shadow, error) {
opts := &Options{}
for _, o := range opt {
if err := o(opts); err != nil {
return nil, ioterr.New(err, "applying option")
}
}
s := &shadow{
cli: cli,
thingName: cli.ThingName(),
name: opts.Name,
doc: &ThingDocument{
State: ThingState{
Desired: map[string]interface{}{},
Expand Down
38 changes: 38 additions & 0 deletions shadow/shadow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,44 @@ func TestNew(t *testing.T) {
t.Errorf("Expected error: %v, got: %v", errDummy, err)
}
})

t.Run("Options", func(t *testing.T) {
t.Run("WithName", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

cli := &mockDevice{&mockmqtt.Client{}}
operation := "foo/bar"

testCases := map[string]struct {
input string
expected string
}{
"ClassicShadow": {
input: "",
expected: "$aws/things/" + cli.ThingName() + "/shadow/" + operation,
},
"NamedShadow": {
input: "testShadow",
expected: "$aws/things/" + cli.ThingName() + "/shadow/name/testShadow/" + operation,
},
}

for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
s, err := New(ctx, cli, WithName(testCase.input))
if err != nil {
t.Fatal(err)
}
topic := s.(*shadow).topic(operation)
if topic != testCase.expected {
t.Errorf("Expected topic name: %v, got: %v", testCase.expected, topic)
}
})
}
})
})
}

func TestHandlers(t *testing.T) {
Expand Down

0 comments on commit 786f4a1

Please sign in to comment.