Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions .github/renovate.json
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:base", "default:automergeDigest"],
"extends": [
"config:recommended",
"default:automergeDigest",
"helpers:pinGitHubActionDigestsToSemver"
],
"minimumReleaseAge": "7 days",
"internalChecksFilter": "strict",
"packageRules": [
{
"description": "Group Go stdlib / toolchain updates and automerge when tests pass",
"description": "Automerge non-major Go module updates when checks pass",
"matchManagers": ["gomod"],
"matchDepNames": ["go"],
"matchDepTypes": ["golang", "toolchain"],
"groupName": "go",
"rangeStrategy": "bump",
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
},
{
"description": "Group GitHub Actions updates and automerge when tests pass",
"description": "Automerge GitHub Actions updates, including majors, when checks pass",
"matchManagers": ["github-actions"],
"groupName": "github-actions",
"automerge": true
},
{
"matchDatasources": ["go", "github-releases", "github-tags"],
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
"automerge": true
}
]
Expand Down
33 changes: 19 additions & 14 deletions .github/workflows/codetests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,30 @@ on:
pull_request:
branches:
- main
push:
branches:
- main
permissions:
contents: read
jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: codespell-project/actions-codespell@e3258cca84ce02b0bb36a3d41f2c18f719a0cc1a # v2.4.3
with:
skip: .git,go.sum
ignore_words_list: Medias
# Runs `go test` against 3 operating systems.
gotest:
strategy:
matrix:
os: [macos, windows, ubuntu]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: stable
- name: go-test
run: go test -race '-test.v' -covermode=atomic ./...
run: go test -race -covermode=atomic '-test.v' ./...
# Runs golangci-lint on macos against freebsd and macos.
golangci-darwin:
strategy:
Expand All @@ -32,14 +37,14 @@ jobs:
env:
GOOS: ${{ matrix.os }}
steps:
- uses: actions/setup-go@v7
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: stable
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.12
version: v2.13
# Runs golangci-lint on linux against linux and windows.
golangci-linux:
strategy:
Expand All @@ -50,11 +55,11 @@ jobs:
env:
GOOS: ${{ matrix.os }}
steps:
- uses: actions/setup-go@v7
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: stable
- uses: actions/checkout@v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
version: v2.12
version: v2.13
32 changes: 15 additions & 17 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
version: '2'
version: "2"
linters:
default: all
disable:
- exhaustruct
- depguard
- wsl
- funcorder
- noinlineerr
- exhaustive
- wsl # deprecated.
- exhaustruct # deprecated.
- exhaustruct_v5 # camera and XML structs are filled a field at a time.
- gomodguard # deprecated.
- depguard # not useful.
- nlreturn
- gomodguard
- goconst
settings:
errcheck:
exclude-functions:
- (*os.File).Close
- (io.Closer).Close
exhaustive:
default-signifies-exhaustive: true
gocritic:
enable-all: true
disabled-checks:
- whyNoLint
- commentedOutCode
settings:
unnamedResult:
checkExported: true
errcheck:
check-type-assertions: true
check-blank: false
disable-default-exclusions: false
exclude-functions:
- (*os.File).Close
- (io.Closer).Close

issues:
max-issues-per-linter: 0
max-same-issues: 0
Expand Down
21 changes: 14 additions & 7 deletions cameras.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ func (c *Camera) StreamVideo(ops *VidOps, length time.Duration, maxsize int64) (
// UseHTTP is not supported (returns ErrHTTPVideoUnsupported).
// Set VidOps.VCodec to "h265" for HEVC cameras (see PreferredVCodec).
func (c *Camera) SaveVideo(ops *VidOps, length time.Duration, maxsize int64, outputFile string) error {
if _, err := os.Stat(outputFile); !os.IsNotExist(err) {
_, statErr := os.Stat(outputFile)
if !os.IsNotExist(statErr) {
return ErrPathExists
}

Expand Down Expand Up @@ -351,7 +352,8 @@ func (c *Camera) ToggleContinuous(arm CameraArmMode) error {
params := make(url.Values)
params.Set("arm", string(arm))

if err := c.server.SimpleReq("++ssControlContinuous", params, c.Number); err != nil {
err := c.server.SimpleReq("++ssControlContinuous", params, c.Number)
if err != nil {
if errors.Is(err, server.ErrNotFound) {
return ErrUnsupported
}
Expand All @@ -367,7 +369,8 @@ func (c *Camera) ToggleMotion(arm CameraArmMode) error {
params := make(url.Values)
params.Set("arm", string(arm))

if err := c.server.SimpleReq("++ssControlMotionCapture", params, c.Number); err != nil {
err := c.server.SimpleReq("++ssControlMotionCapture", params, c.Number)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

Expand All @@ -379,7 +382,8 @@ func (c *Camera) ToggleActions(arm CameraArmMode) error {
params := make(url.Values)
params.Set("arm", string(arm))

if err := c.server.SimpleReq("++ssControlActions", params, c.Number); err != nil {
err := c.server.SimpleReq("++ssControlActions", params, c.Number)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

Expand All @@ -389,7 +393,8 @@ func (c *Camera) ToggleActions(arm CameraArmMode) error {
// TriggerMotion sets a camera as currently seeing motion.
// Other actions likely occur because of this!
func (c *Camera) TriggerMotion() error {
if err := c.server.SimpleReq("++triggermd", make(url.Values), c.Number); err != nil {
err := c.server.SimpleReq("++triggermd", make(url.Values), c.Number)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

Expand Down Expand Up @@ -497,7 +502,8 @@ func (c *Camera) SetSchedule(mode CameraMode, scheduleID int) error {
params.Set("mode", string(mode))
params.Set("id", strconv.Itoa(scheduleID))

if err := c.server.SimpleReq("++ssSetSchedule", params, c.Number); err != nil {
err := c.server.SimpleReq("++ssSetSchedule", params, c.Number)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

Expand All @@ -512,7 +518,8 @@ func (c *Camera) SetScheduleOverride(mode CameraMode, overrideID int) error {
params.Set("mode", string(mode))
params.Set("id", strconv.Itoa(overrideID))

if err := c.server.SimpleReq("++ssSetOverride", params, c.Number); err != nil {
err := c.server.SimpleReq("++ssSetOverride", params, c.Number)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}

Expand Down
18 changes: 9 additions & 9 deletions cameras_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ import (

func TestUnmarshalXMLCameraSchedule(t *testing.T) {
t.Parallel()
asert := assert.New(t)
check := assert.New(t)

var s securityspy.CameraSchedule

err := xml.Unmarshal([]byte("<tag>3</tag>"), &s)
require.NoError(t, err, "valid data must not produce an error")
asert.Equal(3, s.ID, "the data was not unmarshalled properly")
check.Equal(3, s.ID, "the data was not unmarshalled properly")
}

// SS 5.5 keeps v5 width/height tags but also emits video-format (a v6-era field).
Expand Down Expand Up @@ -54,40 +54,40 @@ func TestUnmarshalXMLCameraSS55WithVideoFormat(t *testing.T) {

func TestAll(t *testing.T) {
t.Parallel()
asert := assert.New(t)
check := assert.New(t)

secspyServer, _, _ := testServerWithCamera(t)

cams := secspyServer.Cameras.All()
asert.Len(cams, 2, "the data contains two cameras, two cameras must be returned")
check.Len(cams, 2, "the data contains two cameras, two cameras must be returned")
}

func TestByNum(t *testing.T) {
t.Parallel()
asert := assert.New(t)
check := assert.New(t)

secspyServer, _, _ := testServerWithCamera(t)

cam := secspyServer.Cameras.ByNum(2)
asert.Equal("Porch", cam.Name, "camera 2 is Porch in the v6 test data")
check.Equal("Porch", cam.Name, "camera 2 is Porch in the v6 test data")
require.Nil(t, secspyServer.Cameras.ByNum(99), "a non-existent camera must return nil")
}

func TestByName(t *testing.T) {
t.Parallel()
asert := assert.New(t)
check := assert.New(t)

secspyServer, _, _ := testServerWithCamera(t)

cam := secspyServer.Cameras.ByName("Porch")
asert.Equal(2, cam.Number, "camera 2 is Porch in the v6 test data")
check.Equal(2, cam.Number, "camera 2 is Porch in the v6 test data")
require.Nil(t, secspyServer.Cameras.ByName("not here"), "a non-existent camera must return nil")

cam = secspyServer.Cameras.ByName("porch2")
require.Nil(t, cam, "there is no camera named porch2")

cam = secspyServer.Cameras.ByName("porch")
asert.Equal(2, cam.Number, "camera 2 is Porch in the v6 test data")
check.Equal(2, cam.Number, "camera 2 is Porch in the v6 test data")
require.Nil(t, secspyServer.Cameras.ByName("not here"), "a non-existent camera must return nil")
}

Expand Down
7 changes: 5 additions & 2 deletions cameras_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ type CameraSchedule struct {
// UnmarshalXML stores a schedule ID into a CameraSchedule type.
// This isn't a method you should ever call directly; it is only used during data initialization.
func (bit *CameraSchedule) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if err := d.DecodeElement(&bit.ID, &start); err != nil {
err := d.DecodeElement(&bit.ID, &start)
if err != nil {
return fmt.Errorf("decoding xml: %w", err)
}

Expand Down Expand Up @@ -340,7 +341,9 @@ type cameraXML struct {
//nolint:funlen // dual schema mapping
func (c *Camera) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var raw cameraXML
if err := d.DecodeElement(&raw, &start); err != nil {

err := d.DecodeElement(&raw, &start)
if err != nil {
return fmt.Errorf("decoding camera xml: %w", err)
}

Expand Down
12 changes: 8 additions & 4 deletions events.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ func (e *Events) eventStreamSelector(ctx context.Context, refreshOnConfigChange
}

func (e *Events) serverRefresh(ctx context.Context) {
if err := e.server.RefreshContext(ctx); err != nil {
err := e.server.RefreshContext(ctx)
if err != nil {
e.custom(EventWatcherRefreshFail, -9997, -1, err.Error())

return
Expand Down Expand Up @@ -380,13 +381,15 @@ func (e *Events) UnmarshalEvent(text string) *Event {
eventTime = fmt.Sprintf("%v%+03.0f", parts[0], gmtOffset)

//nolint:gosmopolitan // The event stream uses the system's local time.
if newEvent.When, err = time.ParseInLocation(EventTimeFormat+"-07", eventTime, time.Local); err != nil {
newEvent.When, err = time.ParseInLocation(EventTimeFormat+"-07", eventTime, time.Local)
if err != nil {
newEvent.When = time.Now()
newEvent.Errors = append(newEvent.Errors, ErrDateParseFail)
}

// Parse the ID
if newEvent.ID, err = strconv.Atoi(parts[1]); err != nil {
newEvent.ID, err = strconv.Atoi(parts[1])
if err != nil {
newEvent.ID = BadID
newEvent.Errors = append(newEvent.Errors, ErrIDParseFail)
}
Expand All @@ -395,7 +398,8 @@ func (e *Events) UnmarshalEvent(text string) *Event {
parts[2] = strings.TrimPrefix(parts[2], "CAM")

if cams := e.server.GetCameras(); parts[2] != "X" && cams != nil {
if cameraNum, err := strconv.Atoi(parts[2]); err != nil {
cameraNum, err := strconv.Atoi(parts[2])
if err != nil {
newEvent.Errors = append(newEvent.Errors, ErrCAMParseFail)
} else if newEvent.Camera = cams.ByNum(cameraNum); newEvent.Camera == nil {
newEvent.Errors = append(newEvent.Errors, ErrCAMMissing)
Expand Down
Loading
Loading