├── .appveyor.yml ├── .github ├── FUNDING.yml └── workflows │ └── go.yml ├── .gitignore ├── .gitmodules ├── .goreleaser.yml ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── admin ├── beehive.service ├── beehive.service.conf └── beehive.sh ├── api ├── api.go ├── bindata_stub.go ├── context │ └── context.go └── resources │ ├── actions │ ├── actions.go │ ├── actions_get.go │ ├── actions_post.go │ └── actions_response.go │ ├── bees │ ├── bees.go │ ├── bees_delete.go │ ├── bees_get.go │ ├── bees_post.go │ ├── bees_put.go │ └── bees_response.go │ ├── chains │ ├── chains.go │ ├── chains_delete.go │ ├── chains_get.go │ ├── chains_post.go │ └── chains_response.go │ ├── hives │ ├── hives.go │ ├── hives_get.go │ └── hives_response.go │ └── logs │ ├── logs.go │ ├── logs_get.go │ └── logs_response.go ├── app └── app.go ├── assets ├── bees │ ├── alertoverbee.png │ ├── anelpowerctrlbee.png │ ├── cfddns.png │ ├── cleverbotbee.png │ ├── cricketbee.png │ ├── cronbee.png │ ├── devrantbee.png │ ├── discordbee.png │ ├── efabee.png │ ├── emailbee.png │ ├── emailserverbee.png │ ├── execbee.png │ ├── facebookbee.png │ ├── fsnotifybee.png │ ├── githubbee.png │ ├── gitterbee.png │ ├── gotifybee.png │ ├── horizonboxbee.png │ ├── htmlextractbee.png │ ├── huebee.png │ ├── instapaperbee.png │ ├── ipify.png │ ├── ircbee.png │ ├── jabberbee.png │ ├── jenkinsbee.png │ ├── jirabee.png │ ├── mastodonbee.png │ ├── mixcloudbee.png │ ├── mumblebee.png │ ├── nagiosbee.png │ ├── notificationbee.png │ ├── openweathermapbee.png │ ├── pastebinbee.png │ ├── prometheusbee.png │ ├── pushoverbee.png │ ├── redis.png │ ├── rocketchatbee.png │ ├── rssbee.png │ ├── s3bee.png │ ├── serialbee.png │ ├── simplepushbee.png │ ├── slackbee.png │ ├── socketbee.png │ ├── spaceapibee.png │ ├── sunbee.png │ ├── telegrambee.png │ ├── transmissionbee.png │ ├── travisbee.png │ ├── tumblrbee.png │ ├── twiliobee.png │ ├── twitchbee.png │ ├── twitterbee.png │ └── webbee.png ├── logo.png ├── logo_128.png ├── logo_16.png ├── logo_256.png ├── logo_32.png ├── logo_512.png └── logo_64.png ├── beehive.go ├── bees ├── actions.go ├── alertoverbee │ ├── README.md │ ├── alertoverbee.go │ └── alertoverbeefactory.go ├── anelpowerctrlbee │ ├── anelpowerctrlbee.go │ └── anelpowerctrlbeefactory.go ├── bees.go ├── cfddnsbee │ ├── README.md │ ├── cfddnsbee.go │ └── cfddnsbeefactory.go ├── chains.go ├── cleverbotbee │ ├── README.md │ ├── cleverbotbee.go │ └── cleverbotbeefactory.go ├── config.go ├── context.go ├── cricketbee │ ├── README.md │ ├── cricketbee.go │ └── cricketbeefactory.go ├── cronbee │ ├── cronbee.go │ ├── cronbeefactory.go │ └── thoughts.txt ├── descriptors.go ├── devrantbee │ ├── devrantbee.go │ └── devrantbeefactory.go ├── discordbee │ ├── discordbee.go │ └── discordbeefactory.go ├── efabee │ ├── efabee.go │ └── efabeefactory.go ├── emailbee │ ├── emailbee.go │ └── emailbeefactory.go ├── emailserverbee │ ├── emailserverbee.go │ └── emailserverbeefactory.go ├── events.go ├── execbee │ ├── execbee.go │ └── execbeefactory.go ├── facebookbee │ ├── facebookbee.go │ └── facebookbeefactory.go ├── factories.go ├── filters.go ├── fsnotifybee │ ├── README.md │ ├── fsnotifybee.go │ └── fsnotifybeefactory.go ├── githubbee │ ├── events.go │ ├── githubbee.go │ └── githubbeefactory.go ├── gitterbee │ ├── README.md │ ├── gitterbee.go │ └── gitterbeefactory.go ├── gotifybee │ ├── README.md │ ├── gotifybee.go │ └── gotifybeefactory.go ├── hellobee │ ├── hellobee.go │ └── hellobeefactory.go ├── horizonboxbee │ ├── horizonboxbee.go │ └── horizonboxbeefactory.go ├── htmlextractbee │ ├── htmlextractbee.go │ └── htmlextractbeefactory.go ├── httpbee │ ├── httpbee.go │ └── httpbeefactory.go ├── huebee │ ├── huebee.go │ └── huebeefactory.go ├── instapaperbee │ ├── instapaperbee.go │ └── instapaperbeefactory.go ├── ipifybee │ ├── README.md │ ├── ipifybee.go │ └── ipifybeefactory.go ├── ircbee │ ├── ircbee.go │ ├── ircbeefactory.go │ └── irctools │ │ └── irctools.go ├── jabberbee │ ├── jabberbee.go │ └── jabberbeefactory.go ├── jenkinsbee │ ├── jenkinsbee.go │ └── jenkinsbeefactory.go ├── jirabee │ ├── events.go │ ├── jirabee.go │ └── jirabeefactory.go ├── logs.go ├── mastodonbee │ ├── README.md │ ├── events.go │ ├── mastodonbee.go │ └── mastodonbeefactory.go ├── mixcloudbee │ ├── mixcloudbee.go │ └── mixcloudbeefactory.go ├── mumblebee │ ├── mumblebee.go │ └── mumblebeefactory.go ├── nagiosbee │ ├── nagiosbee.go │ └── nagiosbeefactory.go ├── notificationbee │ ├── notificationbee.go │ ├── notificationbee_osx.go │ ├── notificationbee_unix.go │ └── notificationbeefactory.go ├── openweathermapbee │ ├── README.md │ ├── event.go │ ├── openweathermapbee.go │ └── openweathermapbeefactory.go ├── options.go ├── pastebinbee │ ├── README.md │ ├── pastebinbee.go │ └── pastebinbeefactory.go ├── placeholders.go ├── prometheusbee │ ├── prometheusbee.go │ └── prometheusbeefactory.go ├── pushoverbee │ ├── pushoverbee.go │ └── pushoverbeefactory.go ├── redisbee │ ├── README.md │ ├── redisbee.go │ └── redisbeefactory.go ├── rocketchatbee │ ├── README.md │ ├── client.go │ ├── rocketchatbee.go │ └── rocketchatbeefactory.go ├── rssbee │ ├── rssbee.go │ └── rssbeefactory.go ├── s3bee │ ├── README.md │ ├── s3bee.go │ └── s3beefactory.go ├── serialbee │ ├── serialbee.go │ └── serialbeefactory.go ├── simplepushbee │ ├── simplepushbee.go │ └── simplepushbeefactory.go ├── slackbee │ ├── README.md │ ├── slackbee.go │ └── slackbeefactory.go ├── socketbee │ ├── socketbee.go │ └── socketbeefactory.go ├── spaceapibee │ ├── spaceapibee.go │ └── spaceapibeefactory.go ├── sunbee │ ├── README.md │ ├── sunbee.go │ └── sunbeefactory.go ├── telegrambee │ ├── README.md │ ├── telegrambee.go │ └── telegrambeefactory.go ├── timebee │ ├── timebee.go │ └── timebeefactory.go ├── transmissionbee │ ├── transmissionbee.go │ └── transmissionbeefactory.go ├── travisbee │ ├── travisbee.go │ └── travisbeefactory.go ├── tumblrbee │ ├── tumblrbee.go │ └── tumblrbeefactory.go ├── twiliobee │ ├── README.md │ ├── twiliobee.go │ └── twiliobeefactory.go ├── twitchbee │ ├── twitchbee.go │ └── twitchbeefactory.go ├── twitterbee │ ├── twitterbee.go │ └── twitterbeefactory.go └── webbee │ ├── webbee.go │ └── webbeefactory.go ├── build-constants.go ├── cfg ├── aesbackend.go ├── aesbackend_test.go ├── config.go ├── config_test.go ├── filebackend.go ├── filebackend_test.go ├── membackend.go ├── membackend_test.go └── testdata │ ├── beehive-crypto.conf │ ├── beehive.conf │ └── beehive.yaml ├── docker-compose.yml ├── docker └── README.md ├── docs ├── config_encryption.md └── watchdog.md ├── filters ├── filters.go └── template │ ├── templatefilter.go │ └── templatefilter_test.go ├── go.mod ├── go.sum ├── hives.go ├── hives_linux.go ├── hives_osx.go ├── hives_unix.go ├── templatehelper ├── templatehelper.go └── templatehelper_test.go ├── tools ├── encrypted-config-wrapper └── release.sh └── watchdog_linux.go /.appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | os: Windows Server 2012 R2 4 | 5 | clone_folder: c:\gopath\src\github.com\muesli\beehive 6 | 7 | environment: 8 | GOPATH: c:\gopath 9 | GO111MODULE: on 10 | 11 | install: 12 | - echo %PATH% 13 | - echo %GOPATH% 14 | - go version 15 | - go env 16 | - git submodule update --init 17 | 18 | build_script: 19 | - go build 20 | - go test -v 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: muesli 2 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.13.x, 1.14.x, 1.15.x] 8 | os: [ubuntu-latest, macos-latest] 9 | runs-on: ${{ matrix.os }} 10 | env: 11 | GO111MODULE: "on" 12 | steps: 13 | - name: Install Go 14 | uses: actions/setup-go@v1 15 | with: 16 | go-version: ${{ matrix.go-version }} 17 | 18 | - name: Checkout code 19 | uses: actions/checkout@v1 20 | 21 | - name: Download Go modules 22 | run: go mod download 23 | 24 | - name: Build 25 | run: go build -v ./... 26 | 27 | - name: Test 28 | run: go test ./... 29 | 30 | - name: Coverage 31 | env: 32 | COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | run: | 34 | go test -race -covermode atomic -coverprofile=profile.cov ./... 35 | GO111MODULE=off go get github.com/mattn/goveralls 36 | $(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github 37 | if: matrix.go-version == '1.14.x' && matrix.platform == 'ubuntu-latest' 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | vendor/ 3 | 4 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 5 | *.o 6 | *.a 7 | *.so 8 | 9 | # Folders 10 | _obj 11 | _test 12 | /dist 13 | 14 | # Architecture specific extensions/prefixes 15 | *.[568vq] 16 | [568vq].out 17 | 18 | *.cgo1.go 19 | *.cgo2.c 20 | _cgo_defun.c 21 | _cgo_gotypes.go 22 | _cgo_export.* 23 | 24 | _testmain.go 25 | 26 | *.exe 27 | *.test 28 | 29 | *~ 30 | beehive 31 | /beehive.conf 32 | /beehive.yaml 33 | 34 | # Texteditor-specific stuff 35 | .*.sw* 36 | *.sublime-project 37 | *.sublime-workspace 38 | 39 | # Jetbrains IDEs 40 | .idea 41 | 42 | # Embedded assets 43 | api/bindata.go 44 | 45 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "config"] 2 | path = config 3 | url = https://github.com/muesli/beehive-admin-dist.git 4 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | env: 2 | - GO111MODULE=on 3 | before: 4 | hooks: 5 | - go mod download 6 | builds: 7 | - 8 | binary: beehive 9 | ldflags: -s -w -X main.Version={{ .Version }} -X main.CommitSHA={{ .Commit }} 10 | goos: 11 | - linux 12 | - darwin 13 | - windows 14 | goarch: 15 | - amd64 16 | - arm64 17 | - 386 18 | - arm 19 | goarm: 20 | - 6 21 | - 7 22 | ignore: 23 | - goos: darwin 24 | goarch: 386 25 | - goos: linux 26 | goarch: arm 27 | goarm: 7 28 | flags: 29 | - -tags=embed 30 | hooks: 31 | pre: go-bindata --tags embed --pkg api -o api/bindata.go --ignore config/.git assets/... config/... 32 | signs: 33 | - artifacts: checksum 34 | archives: 35 | - 36 | replacements: 37 | darwin: Darwin 38 | linux: Linux 39 | windows: Windows 40 | 386: i386 41 | amd64: x86_64 42 | checksum: 43 | name_template: 'checksums.txt' 44 | snapshot: 45 | name_template: "{{ .Tag }}-next" 46 | changelog: 47 | sort: asc 48 | filters: 49 | exclude: 50 | - '^docs:' 51 | - '^test:' 52 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS builder 2 | 3 | LABEL authors="Gabriel Alacchi: alacchi.g@gmail.com, Christian Muehlhaeuser: muesli@gmail.com" 4 | 5 | # Install git & make 6 | # Git is required for fetching the dependencies 7 | RUN apk update && \ 8 | apk add --no-cache git make ca-certificates && \ 9 | update-ca-certificates 10 | 11 | # Set the working directory for the container 12 | WORKDIR /go/beehive 13 | 14 | # Build the binary 15 | COPY . . 16 | RUN make embed 17 | 18 | FROM alpine 19 | 20 | RUN apk update && \ 21 | apk add --no-cache ca-certificates tzdata && \ 22 | update-ca-certificates 23 | 24 | COPY --from=builder /go/beehive/beehive /go/bin/beehive 25 | 26 | # Where the admin interface will be served from 27 | ENV CANONICAL_URL=http://localhost:8181 28 | 29 | # Expose the application port 30 | EXPOSE 8181 31 | 32 | # create a volume for the configuration persistence 33 | VOLUME /conf 34 | 35 | # This form of ENTRYPOINT allows the beehive process to catch signals from the `docker stop` command 36 | ENTRYPOINT /go/bin/beehive -config /conf/beehive.conf -bind 0.0.0.0:8181 -canonicalurl ${CANONICAL_URL} 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BEEHIVE_VERSION=0.4.0 2 | COMMIT_SHA=$(shell git rev-parse --short HEAD) 3 | 4 | all: submodule embed 5 | 6 | submodule: 7 | [ -d .git ] && git submodule update --init || true 8 | 9 | noembed: submodule build 10 | 11 | generate: 12 | $(shell go env GOPATH)/bin/go-bindata --tags embed --pkg api -o api/bindata.go --ignore config/.git assets/... config/... 13 | 14 | go-bindata: 15 | [ -f $(shell go env GOPATH)/bin/go-bindata ] || go get -u github.com/kevinburke/go-bindata/go-bindata 16 | 17 | embed: go-bindata generate build 18 | 19 | build: 20 | go build -tags 'embed' -ldflags '-s -w -X main.Version=$(BEEHIVE_VERSION) -X main.CommitSHA=$(COMMIT_SHA)' 21 | 22 | debug: submodule go-bindata generate 23 | go build -tags 'embed' -ldflags '-X main.Version=$(BEEHIVE_VERSION) -X main.CommitSHA=$(COMMIT_SHA)' 24 | 25 | test: 26 | go test -v $(shell go list ./... | grep -v vendor/) 27 | 28 | release: 29 | @./tools/release.sh 30 | 31 | clean: 32 | rm -f beehive 33 | 34 | .PHONY: clean embed go-bindata noembed generate submodule build release all 35 | -------------------------------------------------------------------------------- /admin/beehive.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=beehive Event daemon 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=$GOPATH/bin/beehive -config=${config} 7 | User=beehive 8 | Group=users 9 | RestartSec=5 10 | Restart=on-failure 11 | # Enable the software watchdog. 12 | # See https://github.com/muesli/beehive/tree/master/docs/watchdog.md 13 | WatchdogSec=30s 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /admin/beehive.service.conf: -------------------------------------------------------------------------------- 1 | GOROOT="/usr/local/opt/go" 2 | GOPATH="/home/beehive/go" 3 | 4 | config="/home/beehive/beehive.conf" 5 | -------------------------------------------------------------------------------- /admin/beehive.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: beehive 5 | # Required-Start: $syslog 6 | # Required-Stop: $syslog 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 9 | # Short-Description: beehive daemon 10 | ### END INIT INFO 11 | 12 | set -e 13 | 14 | # /etc/init.d/beehive: start and stop the beehive daemon 15 | 16 | umask 022 17 | 18 | . /lib/lsb/init-functions 19 | 20 | export GOROOT="/usr/local/opt/go" 21 | export PATH="$GOROOT/bin:$PATH" 22 | export GOPATH="/home/beehive/go" 23 | 24 | BINARY="$GOPATH/bin/beehive" 25 | PIDFILE="/var/run/beehive.pid" 26 | CONFIG="/home/beehive/beehive.conf" 27 | 28 | test -x $BINARY || exit 0 29 | 30 | case "$1" in 31 | start) 32 | log_daemon_msg "Starting beehive daemon" "beehive" || true 33 | if start-stop-daemon --start -b --quiet --oknodo -m --pidfile $PIDFILE --exec $BINARY -- -config="$CONFIG"; then 34 | log_end_msg 0 || true 35 | else 36 | log_end_msg 1 || true 37 | fi 38 | ;; 39 | stop) 40 | log_daemon_msg "Stopping beehive daemon" "beehive" || true 41 | if start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE; then 42 | log_end_msg 0 || true 43 | else 44 | log_end_msg 1 || true 45 | fi 46 | ;; 47 | 48 | reload|force-reload) 49 | log_daemon_msg "Reloading beehive daemon's configuration" "beehive" || true 50 | if start-stop-daemon --stop --signal 1 --quiet --oknodo --pidfile $PIDFILE --exec $BINARY ; then 51 | log_end_msg 0 || true 52 | else 53 | log_end_msg 1 || true 54 | fi 55 | ;; 56 | 57 | restart) 58 | log_daemon_msg "Restarting beehive daemon" "beehive" || true 59 | start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDFILE 60 | if start-stop-daemon --start -b --quiet --oknodo -m --pidfile $PIDFILE --exec $BINARY -- -config="$CONFIG"; then 61 | log_end_msg 0 || true 62 | else 63 | log_end_msg 1 || true 64 | fi 65 | ;; 66 | 67 | status) 68 | status_of_proc -p $PIDFILE $BINARY beehive && exit 0 || exit $? 69 | ;; 70 | 71 | *) 72 | log_action_msg "Usage: /etc/init.d/beehive {start|stop|reload|restart|status}" || true 73 | exit 1 74 | esac 75 | 76 | exit 0 77 | -------------------------------------------------------------------------------- /api/bindata_stub.go: -------------------------------------------------------------------------------- 1 | // +build !embed 2 | 3 | // go-bindata (https://github.com/kevinburke/go-bindata) stub 4 | // so beehive also works without embedded assets. 5 | package api 6 | 7 | import "io/ioutil" 8 | 9 | func Asset(asset string) ([]byte, error) { 10 | return ioutil.ReadFile(asset) 11 | } 12 | -------------------------------------------------------------------------------- /api/context/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package context 22 | 23 | import ( 24 | "strings" 25 | 26 | restful "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // APIContext is polly's central context 31 | type APIContext struct { 32 | Config smolder.APIConfig 33 | } 34 | 35 | // NewAPIContext returns a new polly context 36 | func (context *APIContext) NewAPIContext() smolder.APIContext { 37 | ctx := &APIContext{ 38 | Config: context.Config, 39 | } 40 | return ctx 41 | } 42 | 43 | // Authentication parses the request for an access-/authtoken and returns the matching user 44 | func (context *APIContext) Authentication(request *restful.Request) (interface{}, error) { 45 | //FIXME: implement this properly 46 | 47 | t := request.QueryParameter("accesstoken") 48 | if len(t) == 0 { 49 | t = request.HeaderParameter("authorization") 50 | if strings.Index(t, " ") > 0 { 51 | t = strings.TrimSpace(strings.Split(t, " ")[1]) 52 | } 53 | } 54 | 55 | return nil, nil // context.GetUserByAccessToken(t) 56 | } 57 | 58 | // LogSummary logs out the current context stats 59 | func (context *APIContext) LogSummary() { 60 | } 61 | -------------------------------------------------------------------------------- /api/resources/actions/actions.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package actions 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/smolder" 26 | ) 27 | 28 | // ActionResource is the resource responsible for /actions 29 | type ActionResource struct { 30 | smolder.Resource 31 | } 32 | 33 | var ( 34 | _ smolder.GetIDSupported = &ActionResource{} 35 | _ smolder.GetSupported = &ActionResource{} 36 | _ smolder.PostSupported = &ActionResource{} 37 | ) 38 | 39 | // Register this resource with the container to setup all the routes 40 | func (r *ActionResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { 41 | r.Name = "ActionResource" 42 | r.TypeName = "action" 43 | r.Endpoint = "actions" 44 | r.Doc = "Manage actions" 45 | 46 | r.Config = config 47 | r.Context = context 48 | 49 | r.Init(container, r) 50 | } 51 | 52 | // Reads returns the model that will be read by POST, PUT & PATCH operations 53 | func (r *ActionResource) Reads() interface{} { 54 | return &ActionPostStruct{} 55 | } 56 | 57 | // Returns returns the model that will be returned 58 | func (r *ActionResource) Returns() interface{} { 59 | return ActionResponse{} 60 | } 61 | 62 | // Validate checks an incoming request for data errors 63 | func (r *ActionResource) Validate(context smolder.APIContext, data interface{}, request *restful.Request) error { 64 | // ps := data.(*ActionPostStruct) 65 | // FIXME 66 | return nil 67 | } 68 | -------------------------------------------------------------------------------- /api/resources/actions/actions_get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package actions 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // GetAuthRequired returns true because all requests need authentication 31 | func (r *ActionResource) GetAuthRequired() bool { 32 | return false 33 | } 34 | 35 | // GetByIDsAuthRequired returns true because all requests need authentication 36 | func (r *ActionResource) GetByIDsAuthRequired() bool { 37 | return false 38 | } 39 | 40 | // GetDoc returns the description of this API endpoint 41 | func (r *ActionResource) GetDoc() string { 42 | return "retrieve actions" 43 | } 44 | 45 | // GetParams returns the parameters supported by this API endpoint 46 | func (r *ActionResource) GetParams() []*restful.Parameter { 47 | params := []*restful.Parameter{} 48 | // params = append(params, restful.QueryParameter("user_id", "id of a user").DataType("int64")) 49 | 50 | return params 51 | } 52 | 53 | // GetByIDs sends out all items matching a set of IDs 54 | func (r *ActionResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { 55 | resp := ActionResponse{} 56 | resp.Init(ctx) 57 | 58 | for _, id := range ids { 59 | action := bees.GetAction(id) 60 | if action == nil { 61 | r.NotFound(request, response) 62 | return 63 | } 64 | 65 | resp.AddAction(action) 66 | } 67 | 68 | resp.Send(response) 69 | } 70 | 71 | // Get sends out items matching the query parameters 72 | func (r *ActionResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { 73 | // ctxapi := ctx.(*context.APIContext) 74 | actions := bees.GetActions() 75 | if len(actions) == 0 { 76 | r.NotFound(request, response) 77 | return 78 | } 79 | 80 | resp := ActionResponse{} 81 | resp.Init(ctx) 82 | 83 | for _, action := range actions { 84 | resp.AddAction(&action) 85 | } 86 | 87 | resp.Send(response) 88 | } 89 | -------------------------------------------------------------------------------- /api/resources/actions/actions_post.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package actions 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/beehive/bees" 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // ActionPostStruct holds all values of an incoming POST request 30 | type ActionPostStruct struct { 31 | Action struct { 32 | Bee string `json:"bee"` 33 | Name string `json:"name"` 34 | Options bees.Placeholders `json:"options"` 35 | } `json:"action"` 36 | } 37 | 38 | // PostAuthRequired returns true because all requests need authentication 39 | func (r *ActionResource) PostAuthRequired() bool { 40 | return false 41 | } 42 | 43 | // PostDoc returns the description of this API endpoint 44 | func (r *ActionResource) PostDoc() string { 45 | return "create a new action" 46 | } 47 | 48 | // PostParams returns the parameters supported by this API endpoint 49 | func (r *ActionResource) PostParams() []*restful.Parameter { 50 | return nil 51 | } 52 | 53 | // Post processes an incoming POST (create) request 54 | func (r *ActionResource) Post(context smolder.APIContext, data interface{}, request *restful.Request, response *restful.Response) { 55 | resp := ActionResponse{} 56 | resp.Init(context) 57 | 58 | pps := data.(*ActionPostStruct) 59 | action := bees.Action{ 60 | ID: bees.UUID(), 61 | Bee: pps.Action.Bee, 62 | Name: pps.Action.Name, 63 | Options: pps.Action.Options, 64 | } 65 | actions := append(bees.GetActions(), action) 66 | bees.SetActions(actions) 67 | 68 | resp.AddAction(&action) 69 | resp.Send(response) 70 | } 71 | -------------------------------------------------------------------------------- /api/resources/actions/actions_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package actions 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // ActionResponse is the common response to 'action' requests 30 | type ActionResponse struct { 31 | smolder.Response 32 | 33 | Actions []actionInfoResponse `json:"actions,omitempty"` 34 | actions []*bees.Action 35 | } 36 | 37 | type actionInfoResponse struct { 38 | ID string `json:"id"` 39 | Bee string `json:"bee"` 40 | Name string `json:"name"` 41 | Options bees.Placeholders `json:"options"` 42 | } 43 | 44 | // Init a new response 45 | func (r *ActionResponse) Init(context smolder.APIContext) { 46 | r.Parent = r 47 | r.Context = context 48 | 49 | r.Actions = []actionInfoResponse{} 50 | } 51 | 52 | // AddAction adds a action to the response 53 | func (r *ActionResponse) AddAction(action *bees.Action) { 54 | r.actions = append(r.actions, action) 55 | r.Actions = append(r.Actions, prepareActionResponse(r.Context, action)) 56 | } 57 | 58 | // EmptyResponse returns an empty API response for this endpoint if there's no data to respond with 59 | func (r *ActionResponse) EmptyResponse() interface{} { 60 | if len(r.actions) == 0 { 61 | var out struct { 62 | Actions interface{} `json:"actions"` 63 | } 64 | out.Actions = []actionInfoResponse{} 65 | return out 66 | } 67 | return nil 68 | } 69 | 70 | func prepareActionResponse(context smolder.APIContext, action *bees.Action) actionInfoResponse { 71 | // ctx := context.(*context.APIContext) 72 | resp := actionInfoResponse{ 73 | ID: (*action).ID, 74 | Bee: (*action).Bee, 75 | Name: (*action).Name, 76 | Options: (*action).Options, 77 | } 78 | 79 | return resp 80 | } 81 | -------------------------------------------------------------------------------- /api/resources/bees/bees.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package bees 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/smolder" 26 | ) 27 | 28 | // BeeResource is the resource responsible for /bees 29 | type BeeResource struct { 30 | smolder.Resource 31 | } 32 | 33 | var ( 34 | _ smolder.GetIDSupported = &BeeResource{} 35 | _ smolder.GetSupported = &BeeResource{} 36 | _ smolder.PostSupported = &BeeResource{} 37 | _ smolder.PutSupported = &BeeResource{} 38 | _ smolder.DeleteSupported = &BeeResource{} 39 | ) 40 | 41 | // Register this resource with the container to setup all the routes 42 | func (r *BeeResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { 43 | r.Name = "BeeResource" 44 | r.TypeName = "bee" 45 | r.Endpoint = "bees" 46 | r.Doc = "Manage bees" 47 | 48 | r.Config = config 49 | r.Context = context 50 | 51 | r.Init(container, r) 52 | } 53 | 54 | // Reads returns the model that will be read by POST, PUT & PATCH operations 55 | func (r *BeeResource) Reads() interface{} { 56 | return &BeePostStruct{} 57 | } 58 | 59 | // Returns returns the model that will be returned 60 | func (r *BeeResource) Returns() interface{} { 61 | return BeeResponse{} 62 | } 63 | 64 | // Validate checks an incoming request for data errors 65 | func (r *BeeResource) Validate(context smolder.APIContext, data interface{}, request *restful.Request) error { 66 | // ps := data.(*BeePostStruct) 67 | // FIXME 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /api/resources/bees/bees_delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package bees 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/beehive/bees" 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // DeleteAuthRequired returns true because all requests need authentication 30 | func (r *BeeResource) DeleteAuthRequired() bool { 31 | return false 32 | } 33 | 34 | // DeleteDoc returns the description of this API endpoint 35 | func (r *BeeResource) DeleteDoc() string { 36 | return "delete a bee" 37 | } 38 | 39 | // DeleteParams returns the parameters supported by this API endpoint 40 | func (r *BeeResource) DeleteParams() []*restful.Parameter { 41 | return nil 42 | } 43 | 44 | // Delete processes an incoming DELETE request 45 | func (r *BeeResource) Delete(context smolder.APIContext, request *restful.Request, response *restful.Response) { 46 | resp := BeeResponse{} 47 | resp.Init(context) 48 | 49 | id := request.PathParameter("bee-id") 50 | bee := bees.GetBee(id) 51 | if bee == nil { 52 | r.NotFound(request, response) 53 | return 54 | } 55 | 56 | go func() { 57 | bees.DeleteBee(bee) 58 | }() 59 | 60 | resp.Send(response) 61 | } 62 | -------------------------------------------------------------------------------- /api/resources/bees/bees_get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package bees 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // GetAuthRequired returns true because all requests need authentication 31 | func (r *BeeResource) GetAuthRequired() bool { 32 | return false 33 | } 34 | 35 | // GetByIDsAuthRequired returns true because all requests need authentication 36 | func (r *BeeResource) GetByIDsAuthRequired() bool { 37 | return false 38 | } 39 | 40 | // GetDoc returns the description of this API endpoint 41 | func (r *BeeResource) GetDoc() string { 42 | return "retrieve bees" 43 | } 44 | 45 | // GetParams returns the parameters supported by this API endpoint 46 | func (r *BeeResource) GetParams() []*restful.Parameter { 47 | params := []*restful.Parameter{} 48 | // params = append(params, restful.QueryParameter("user_id", "id of a user").DataType("int64")) 49 | 50 | return params 51 | } 52 | 53 | // GetByIDs sends out all items matching a set of IDs 54 | func (r *BeeResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { 55 | resp := BeeResponse{} 56 | resp.Init(ctx) 57 | 58 | for _, id := range ids { 59 | bee := bees.GetBee(id) 60 | if bee == nil { 61 | r.NotFound(request, response) 62 | return 63 | } 64 | 65 | resp.AddBee(bee) 66 | } 67 | 68 | resp.Send(response) 69 | } 70 | 71 | // Get sends out items matching the query parameters 72 | func (r *BeeResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { 73 | // ctxapi := ctx.(*context.APIContext) 74 | bees := bees.GetBees() 75 | resp := BeeResponse{} 76 | resp.Init(ctx) 77 | 78 | for _, bee := range bees { 79 | resp.AddBee(bee) 80 | } 81 | 82 | resp.Send(response) 83 | } 84 | -------------------------------------------------------------------------------- /api/resources/bees/bees_post.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package bees 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/beehive/bees" 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // BeePostStruct holds all values of an incoming POST request 30 | type BeePostStruct struct { 31 | Bee struct { 32 | Name string `json:"name"` 33 | Namespace string `json:"namespace"` 34 | Description string `json:"description"` 35 | Active bool `json:"active"` 36 | Options bees.BeeOptions `json:"options"` 37 | } `json:"bee"` 38 | } 39 | 40 | // PostAuthRequired returns true because all requests need authentication 41 | func (r *BeeResource) PostAuthRequired() bool { 42 | return false 43 | } 44 | 45 | // PostDoc returns the description of this API endpoint 46 | func (r *BeeResource) PostDoc() string { 47 | return "create a new bee" 48 | } 49 | 50 | // PostParams returns the parameters supported by this API endpoint 51 | func (r *BeeResource) PostParams() []*restful.Parameter { 52 | return nil 53 | } 54 | 55 | // Post processes an incoming POST (create) request 56 | func (r *BeeResource) Post(context smolder.APIContext, data interface{}, request *restful.Request, response *restful.Response) { 57 | resp := BeeResponse{} 58 | resp.Init(context) 59 | 60 | pps := data.(*BeePostStruct) 61 | c, err := bees.NewBeeConfig(pps.Bee.Name, pps.Bee.Namespace, pps.Bee.Description, pps.Bee.Options) 62 | if err != nil { 63 | smolder.ErrorResponseHandler(request, response, err, smolder.NewErrorResponse( 64 | 422, // Go 1.7+: http.StatusUnprocessableEntity, 65 | err, 66 | "BeeResource POST")) 67 | return 68 | } 69 | 70 | bee := bees.StartBee(c) 71 | resp.AddBee(bee) 72 | 73 | resp.Send(response) 74 | } 75 | -------------------------------------------------------------------------------- /api/resources/bees/bees_put.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package bees 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/beehive/bees" 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // PutAuthRequired returns true because all requests need authentication 30 | func (r *BeeResource) PutAuthRequired() bool { 31 | return false 32 | } 33 | 34 | // PutDoc returns the description of this API endpoint 35 | func (r *BeeResource) PutDoc() string { 36 | return "update an existing bee" 37 | } 38 | 39 | // PutParams returns the parameters supported by this API endpoint 40 | func (r *BeeResource) PutParams() []*restful.Parameter { 41 | return nil 42 | } 43 | 44 | // Put processes an incoming PUT (update) request 45 | func (r *BeeResource) Put(context smolder.APIContext, data interface{}, request *restful.Request, response *restful.Response) { 46 | resp := BeeResponse{} 47 | resp.Init(context) 48 | 49 | pps := data.(*BeePostStruct) 50 | id := request.PathParameter("bee-id") 51 | bee := bees.GetBee(id) 52 | if bee == nil { 53 | r.NotFound(request, response) 54 | return 55 | } 56 | 57 | (*bee).SetDescription(pps.Bee.Description) 58 | (*bee).ReloadOptions(pps.Bee.Options) 59 | 60 | if pps.Bee.Active { 61 | bees.RestartBee(bee) 62 | } else { 63 | (*bee).Stop() 64 | } 65 | 66 | resp.AddBee(bee) 67 | resp.Send(response) 68 | } 69 | -------------------------------------------------------------------------------- /api/resources/chains/chains.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package chains 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/smolder" 26 | ) 27 | 28 | // ChainResource is the resource responsible for /chains 29 | type ChainResource struct { 30 | smolder.Resource 31 | } 32 | 33 | var ( 34 | _ smolder.GetIDSupported = &ChainResource{} 35 | _ smolder.GetSupported = &ChainResource{} 36 | _ smolder.PostSupported = &ChainResource{} 37 | _ smolder.DeleteSupported = &ChainResource{} 38 | ) 39 | 40 | // Register this resource with the container to setup all the routes 41 | func (r *ChainResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { 42 | r.Name = "ChainResource" 43 | r.TypeName = "chain" 44 | r.Endpoint = "chains" 45 | r.Doc = "Manage chains" 46 | 47 | r.Config = config 48 | r.Context = context 49 | 50 | r.Init(container, r) 51 | } 52 | 53 | // Reads returns the model that will be read by POST, PUT & PATCH operations 54 | func (r *ChainResource) Reads() interface{} { 55 | return &ChainPostStruct{} 56 | } 57 | 58 | // Returns returns the model that will be returned 59 | func (r *ChainResource) Returns() interface{} { 60 | return ChainResponse{} 61 | } 62 | 63 | // Validate checks an incoming request for data errors 64 | func (r *ChainResource) Validate(context smolder.APIContext, data interface{}, request *restful.Request) error { 65 | // ps := data.(*ChainPostStruct) 66 | // FIXME 67 | return nil 68 | } 69 | -------------------------------------------------------------------------------- /api/resources/chains/chains_delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package chains 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/beehive/bees" 26 | "github.com/muesli/smolder" 27 | ) 28 | 29 | // DeleteAuthRequired returns true because all requests need authentication 30 | func (r *ChainResource) DeleteAuthRequired() bool { 31 | return false 32 | } 33 | 34 | // DeleteDoc returns the description of this API endpoint 35 | func (r *ChainResource) DeleteDoc() string { 36 | return "delete a chain" 37 | } 38 | 39 | // DeleteParams returns the parameters supported by this API endpoint 40 | func (r *ChainResource) DeleteParams() []*restful.Parameter { 41 | return nil 42 | } 43 | 44 | // Delete processes an incoming DELETE request 45 | func (r *ChainResource) Delete(context smolder.APIContext, request *restful.Request, response *restful.Response) { 46 | resp := ChainResponse{} 47 | resp.Init(context) 48 | 49 | id := request.PathParameter("chain-id") 50 | 51 | found := false 52 | chains := []bees.Chain{} 53 | for _, v := range bees.GetChains() { 54 | if v.Name == id { 55 | found = true 56 | } else { 57 | chains = append(chains, v) 58 | } 59 | } 60 | 61 | if found { 62 | bees.SetChains(chains) 63 | resp.Send(response) 64 | } else { 65 | r.NotFound(request, response) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /api/resources/chains/chains_get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package chains 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // GetAuthRequired returns true because all requests need authentication 31 | func (r *ChainResource) GetAuthRequired() bool { 32 | return false 33 | } 34 | 35 | // GetByIDsAuthRequired returns true because all requests need authentication 36 | func (r *ChainResource) GetByIDsAuthRequired() bool { 37 | return false 38 | } 39 | 40 | // GetDoc returns the description of this API endpoint 41 | func (r *ChainResource) GetDoc() string { 42 | return "retrieve chains" 43 | } 44 | 45 | // GetParams returns the parameters supported by this API endpoint 46 | func (r *ChainResource) GetParams() []*restful.Parameter { 47 | params := []*restful.Parameter{} 48 | // params = append(params, restful.QueryParameter("user_id", "id of a user").DataType("int64")) 49 | 50 | return params 51 | } 52 | 53 | // GetByIDs sends out all items matching a set of IDs 54 | func (r *ChainResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { 55 | resp := ChainResponse{} 56 | resp.Init(ctx) 57 | 58 | for _, id := range ids { 59 | chain := bees.GetChain(id) 60 | if chain == nil { 61 | r.NotFound(request, response) 62 | return 63 | } 64 | 65 | resp.AddChain(*chain) 66 | } 67 | 68 | resp.Send(response) 69 | } 70 | 71 | // Get sends out items matching the query parameters 72 | func (r *ChainResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { 73 | // ctxapi := ctx.(*context.APIContext) 74 | chains := bees.GetChains() 75 | resp := ChainResponse{} 76 | resp.Init(ctx) 77 | 78 | for _, chain := range chains { 79 | resp.AddChain(chain) 80 | } 81 | 82 | resp.Send(response) 83 | } 84 | -------------------------------------------------------------------------------- /api/resources/chains/chains_post.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package chains 22 | 23 | import ( 24 | "errors" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/beehive/bees" 28 | "github.com/muesli/smolder" 29 | ) 30 | 31 | // ChainPostStruct holds all values of an incoming POST request 32 | type ChainPostStruct struct { 33 | Chain struct { 34 | Name string `json:"name"` 35 | Description string `json:"description"` 36 | Event bees.Event `json:"event"` 37 | Filters []string `json:"filters"` 38 | Actions []string `json:"actions"` 39 | } `json:"chain"` 40 | } 41 | 42 | // PostAuthRequired returns true because all requests need authentication 43 | func (r *ChainResource) PostAuthRequired() bool { 44 | return false 45 | } 46 | 47 | // PostDoc returns the description of this API endpoint 48 | func (r *ChainResource) PostDoc() string { 49 | return "create a new chain" 50 | } 51 | 52 | // PostParams returns the parameters supported by this API endpoint 53 | func (r *ChainResource) PostParams() []*restful.Parameter { 54 | return nil 55 | } 56 | 57 | // Post processes an incoming POST (create) request 58 | func (r *ChainResource) Post(context smolder.APIContext, data interface{}, request *restful.Request, response *restful.Response) { 59 | resp := ChainResponse{} 60 | resp.Init(context) 61 | 62 | pps := data.(*ChainPostStruct) 63 | dupe := bees.GetChain(pps.Chain.Name) 64 | if dupe != nil { 65 | smolder.ErrorResponseHandler(request, response, nil, smolder.NewErrorResponse( 66 | 422, // Go 1.7+: http.StatusUnprocessableEntity, 67 | errors.New("A Chain with that name exists already"), 68 | "ChainResource POST")) 69 | return 70 | } 71 | 72 | chain := bees.Chain{ 73 | Name: pps.Chain.Name, 74 | Description: pps.Chain.Description, 75 | Event: &pps.Chain.Event, 76 | Actions: pps.Chain.Actions, 77 | Filters: pps.Chain.Filters, 78 | } 79 | chains := append(bees.GetChains(), chain) 80 | bees.SetChains(chains) 81 | 82 | resp.AddChain(chain) 83 | resp.Send(response) 84 | } 85 | -------------------------------------------------------------------------------- /api/resources/chains/chains_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package chains 22 | 23 | import ( 24 | "sort" 25 | 26 | restful "github.com/emicklei/go-restful" 27 | "github.com/muesli/beehive/bees" 28 | 29 | "github.com/muesli/smolder" 30 | ) 31 | 32 | // ChainResponse is the common response to 'chain' requests 33 | type ChainResponse struct { 34 | smolder.Response 35 | 36 | Chains []chainInfoResponse `json:"chains,omitempty"` 37 | chains map[string]*bees.Chain 38 | } 39 | 40 | type chainInfoResponse struct { 41 | ID string `json:"id"` 42 | Name string `json:"name"` 43 | Description string `json:"description"` 44 | Event *bees.Event `json:"event"` 45 | Filters []string `json:"filters,omitempty"` 46 | Actions []string `json:"actions"` 47 | } 48 | 49 | // Init a new response 50 | func (r *ChainResponse) Init(context smolder.APIContext) { 51 | r.Parent = r 52 | r.Context = context 53 | 54 | r.chains = make(map[string]*bees.Chain) 55 | } 56 | 57 | // AddChain adds a chain to the response 58 | func (r *ChainResponse) AddChain(chain bees.Chain) { 59 | r.chains[chain.Name] = &chain 60 | } 61 | 62 | // Send responds to a request with http.StatusOK 63 | func (r *ChainResponse) Send(response *restful.Response) { 64 | var keys []string 65 | for k := range r.chains { 66 | keys = append(keys, k) 67 | } 68 | sort.Strings(keys) 69 | 70 | for _, k := range keys { 71 | r.Chains = append(r.Chains, prepareChainResponse(r.Context, r.chains[k])) 72 | } 73 | 74 | r.Response.Send(response) 75 | } 76 | 77 | // EmptyResponse returns an empty API response for this endpoint if there's no data to respond with 78 | func (r *ChainResponse) EmptyResponse() interface{} { 79 | if len(r.chains) == 0 { 80 | var out struct { 81 | Chains interface{} `json:"chains"` 82 | } 83 | out.Chains = []chainInfoResponse{} 84 | return out 85 | } 86 | return nil 87 | } 88 | 89 | func prepareChainResponse(context smolder.APIContext, chain *bees.Chain) chainInfoResponse { 90 | // ctx := context.(*context.APIContext) 91 | resp := chainInfoResponse{ 92 | ID: (*chain).Name, 93 | Name: (*chain).Name, 94 | Description: (*chain).Description, 95 | Event: (*chain).Event, 96 | Actions: (*chain).Actions, 97 | Filters: (*chain).Filters, 98 | } 99 | 100 | return resp 101 | } 102 | -------------------------------------------------------------------------------- /api/resources/hives/hives.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package hives 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/smolder" 26 | ) 27 | 28 | // HiveResource is the resource responsible for /hives 29 | type HiveResource struct { 30 | smolder.Resource 31 | } 32 | 33 | var ( 34 | _ smolder.GetIDSupported = &HiveResource{} 35 | _ smolder.GetSupported = &HiveResource{} 36 | ) 37 | 38 | // Register this resource with the container to setup all the routes 39 | func (r *HiveResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { 40 | r.Name = "HiveResource" 41 | r.TypeName = "hive" 42 | r.Endpoint = "hives" 43 | r.Doc = "Manage hives" 44 | 45 | r.Config = config 46 | r.Context = context 47 | 48 | r.Init(container, r) 49 | } 50 | 51 | // Returns returns the model that will be returned 52 | func (r *HiveResource) Returns() interface{} { 53 | return HiveResponse{} 54 | } 55 | -------------------------------------------------------------------------------- /api/resources/hives/hives_get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package hives 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // GetAuthRequired returns true because all requests need authentication 31 | func (r *HiveResource) GetAuthRequired() bool { 32 | return false 33 | } 34 | 35 | // GetByIDsAuthRequired returns true because all requests need authentication 36 | func (r *HiveResource) GetByIDsAuthRequired() bool { 37 | return false 38 | } 39 | 40 | // GetDoc returns the description of this API endpoint 41 | func (r *HiveResource) GetDoc() string { 42 | return "retrieve hives" 43 | } 44 | 45 | // GetParams returns the parameters supported by this API endpoint 46 | func (r *HiveResource) GetParams() []*restful.Parameter { 47 | params := []*restful.Parameter{} 48 | // params = append(params, restful.QueryParameter("user_id", "id of a user").DataType("int64")) 49 | 50 | return params 51 | } 52 | 53 | // GetByIDs sends out all items matching a set of IDs 54 | func (r *HiveResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { 55 | resp := HiveResponse{} 56 | resp.Init(ctx) 57 | 58 | for _, id := range ids { 59 | hive := bees.GetFactory(id) 60 | if hive == nil { 61 | r.NotFound(request, response) 62 | return 63 | } 64 | 65 | resp.AddHive(hive) 66 | } 67 | 68 | resp.Send(response) 69 | } 70 | 71 | // Get sends out items matching the query parameters 72 | func (r *HiveResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { 73 | // ctxapi := ctx.(*context.APIContext) 74 | hives := bees.GetFactories() 75 | if len(hives) == 0 { // err != nil { 76 | r.NotFound(request, response) 77 | return 78 | } 79 | 80 | resp := HiveResponse{} 81 | resp.Init(ctx) 82 | 83 | for _, hive := range hives { 84 | resp.AddHive(hive) 85 | } 86 | 87 | resp.Send(response) 88 | } 89 | -------------------------------------------------------------------------------- /api/resources/logs/logs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2019 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package logs 22 | 23 | import ( 24 | "github.com/emicklei/go-restful" 25 | "github.com/muesli/smolder" 26 | ) 27 | 28 | // LogResource is the resource responsible for /logs 29 | type LogResource struct { 30 | smolder.Resource 31 | } 32 | 33 | var ( 34 | // _ smolder.GetIDSupported = &LogResource{} 35 | _ smolder.GetSupported = &LogResource{} 36 | ) 37 | 38 | // Register this resource with the container to setup all the routes 39 | func (r *LogResource) Register(container *restful.Container, config smolder.APIConfig, context smolder.APIContextFactory) { 40 | r.Name = "LogResource" 41 | r.TypeName = "log" 42 | r.Endpoint = "logs" 43 | r.Doc = "Manage logs" 44 | 45 | r.Config = config 46 | r.Context = context 47 | 48 | r.Init(container, r) 49 | } 50 | 51 | // Returns returns the model that will be returned 52 | func (r *LogResource) Returns() interface{} { 53 | return LogResponse{} 54 | } 55 | -------------------------------------------------------------------------------- /api/resources/logs/logs_get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017-2019 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package logs 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | 26 | "github.com/emicklei/go-restful" 27 | "github.com/muesli/smolder" 28 | ) 29 | 30 | // GetAuthRequired returns true because all requests need authentication 31 | func (r *LogResource) GetAuthRequired() bool { 32 | return false 33 | } 34 | 35 | // GetByIDsAuthRequired returns true because all requests need authentication 36 | func (r *LogResource) GetByIDsAuthRequired() bool { 37 | return false 38 | } 39 | 40 | // GetDoc returns the description of this API endpoint 41 | func (r *LogResource) GetDoc() string { 42 | return "retrieve logs" 43 | } 44 | 45 | // GetParams returns the parameters supported by this API endpoint 46 | func (r *LogResource) GetParams() []*restful.Parameter { 47 | params := []*restful.Parameter{} 48 | params = append(params, restful.QueryParameter("bee", "id of a bee").DataType("string")) 49 | 50 | return params 51 | } 52 | 53 | // GetByIDs sends out all items matching a set of IDs 54 | /* 55 | func (r *LogResource) GetByIDs(ctx smolder.APIContext, request *restful.Request, response *restful.Response, ids []string) { 56 | resp := LogResponse{} 57 | resp.Init(ctx) 58 | 59 | resp.Send(response) 60 | } 61 | */ 62 | 63 | // Get sends out items matching the query parameters 64 | func (r *LogResource) Get(ctx smolder.APIContext, request *restful.Request, response *restful.Response, params map[string][]string) { 65 | // ctxapi := ctx.(*context.APIContext) 66 | bee := request.QueryParameter("bee") 67 | 68 | resp := LogResponse{} 69 | resp.Init(ctx) 70 | 71 | logs := bees.GetLogs(bee) 72 | for _, log := range logs { 73 | resp.AddLog(&log) 74 | } 75 | 76 | resp.Send(response) 77 | } 78 | -------------------------------------------------------------------------------- /api/resources/logs/logs_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015-2019 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package logs 22 | 23 | import ( 24 | "time" 25 | 26 | "github.com/muesli/beehive/bees" 27 | 28 | "github.com/muesli/smolder" 29 | ) 30 | 31 | // LogResponse is the common response to 'log' requests 32 | type LogResponse struct { 33 | smolder.Response 34 | 35 | Logs []logInfoResponse `json:"logs,omitempty"` 36 | logs []*bees.LogMessage 37 | } 38 | 39 | type logInfoResponse struct { 40 | ID string `json:"id"` 41 | Bee string `json:"bee"` 42 | Level int64 `json:"level"` 43 | Message string `json:"message"` 44 | Timestamp time.Time `json:"timestamp"` 45 | } 46 | 47 | // Init a new response 48 | func (r *LogResponse) Init(context smolder.APIContext) { 49 | r.Parent = r 50 | r.Context = context 51 | 52 | r.Logs = []logInfoResponse{} 53 | } 54 | 55 | // AddLog adds a log to the response 56 | func (r *LogResponse) AddLog(log *bees.LogMessage) { 57 | r.logs = append(r.logs, log) 58 | r.Logs = append(r.Logs, prepareLogResponse(r.Context, log)) 59 | } 60 | 61 | // EmptyResponse returns an empty API response for this endpoint if there's no data to respond with 62 | func (r *LogResponse) EmptyResponse() interface{} { 63 | if len(r.logs) == 0 { 64 | var out struct { 65 | Logs interface{} `json:"logs"` 66 | } 67 | out.Logs = []logInfoResponse{} 68 | return out 69 | } 70 | return nil 71 | } 72 | 73 | func prepareLogResponse(context smolder.APIContext, log *bees.LogMessage) logInfoResponse { 74 | // ctx := context.(*context.APIContext) 75 | resp := logInfoResponse{ 76 | ID: (*log).ID, 77 | Bee: (*log).Bee, 78 | Level: int64((*log).MessageType), 79 | Message: (*log).Message, 80 | Timestamp: (*log).Timestamp, 81 | } 82 | 83 | return resp 84 | } 85 | -------------------------------------------------------------------------------- /app/app.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package app is Beehive's application container. Handles command-line arguments parsing. 22 | package app 23 | 24 | import ( 25 | "flag" 26 | ) 27 | 28 | // A CliFlag can be added by Beehive modules to map a command-line parameter 29 | // to a local variable 30 | type CliFlag struct { 31 | V interface{} 32 | Name string 33 | Value interface{} 34 | Desc string 35 | } 36 | 37 | var ( 38 | appflags []CliFlag 39 | ) 40 | 41 | // AddFlags adds CliFlags to appflags 42 | func AddFlags(flags []CliFlag) { 43 | for _, flag := range flags { 44 | appflags = append(appflags, flag) 45 | } 46 | } 47 | 48 | // Run sets up all the cli-param mappings 49 | func Run() { 50 | for _, f := range appflags { 51 | switch f.Value.(type) { 52 | case string: 53 | flag.StringVar((f.V).(*string), f.Name, f.Value.(string), f.Desc) 54 | case bool: 55 | flag.BoolVar((f.V).(*bool), f.Name, f.Value.(bool), f.Desc) 56 | } 57 | } 58 | 59 | flag.Parse() 60 | } 61 | -------------------------------------------------------------------------------- /assets/bees/alertoverbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/alertoverbee.png -------------------------------------------------------------------------------- /assets/bees/anelpowerctrlbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/anelpowerctrlbee.png -------------------------------------------------------------------------------- /assets/bees/cfddns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/cfddns.png -------------------------------------------------------------------------------- /assets/bees/cleverbotbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/cleverbotbee.png -------------------------------------------------------------------------------- /assets/bees/cricketbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/cricketbee.png -------------------------------------------------------------------------------- /assets/bees/cronbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/cronbee.png -------------------------------------------------------------------------------- /assets/bees/devrantbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/devrantbee.png -------------------------------------------------------------------------------- /assets/bees/discordbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/discordbee.png -------------------------------------------------------------------------------- /assets/bees/efabee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/efabee.png -------------------------------------------------------------------------------- /assets/bees/emailbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/emailbee.png -------------------------------------------------------------------------------- /assets/bees/emailserverbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/emailserverbee.png -------------------------------------------------------------------------------- /assets/bees/execbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/execbee.png -------------------------------------------------------------------------------- /assets/bees/facebookbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/facebookbee.png -------------------------------------------------------------------------------- /assets/bees/fsnotifybee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/fsnotifybee.png -------------------------------------------------------------------------------- /assets/bees/githubbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/githubbee.png -------------------------------------------------------------------------------- /assets/bees/gitterbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/gitterbee.png -------------------------------------------------------------------------------- /assets/bees/gotifybee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/gotifybee.png -------------------------------------------------------------------------------- /assets/bees/horizonboxbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/horizonboxbee.png -------------------------------------------------------------------------------- /assets/bees/htmlextractbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/htmlextractbee.png -------------------------------------------------------------------------------- /assets/bees/huebee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/huebee.png -------------------------------------------------------------------------------- /assets/bees/instapaperbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/instapaperbee.png -------------------------------------------------------------------------------- /assets/bees/ipify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/ipify.png -------------------------------------------------------------------------------- /assets/bees/ircbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/ircbee.png -------------------------------------------------------------------------------- /assets/bees/jabberbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/jabberbee.png -------------------------------------------------------------------------------- /assets/bees/jenkinsbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/jenkinsbee.png -------------------------------------------------------------------------------- /assets/bees/jirabee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/jirabee.png -------------------------------------------------------------------------------- /assets/bees/mastodonbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/mastodonbee.png -------------------------------------------------------------------------------- /assets/bees/mixcloudbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/mixcloudbee.png -------------------------------------------------------------------------------- /assets/bees/mumblebee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/mumblebee.png -------------------------------------------------------------------------------- /assets/bees/nagiosbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/nagiosbee.png -------------------------------------------------------------------------------- /assets/bees/notificationbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/notificationbee.png -------------------------------------------------------------------------------- /assets/bees/openweathermapbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/openweathermapbee.png -------------------------------------------------------------------------------- /assets/bees/pastebinbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/pastebinbee.png -------------------------------------------------------------------------------- /assets/bees/prometheusbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/prometheusbee.png -------------------------------------------------------------------------------- /assets/bees/pushoverbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/pushoverbee.png -------------------------------------------------------------------------------- /assets/bees/redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/redis.png -------------------------------------------------------------------------------- /assets/bees/rocketchatbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/rocketchatbee.png -------------------------------------------------------------------------------- /assets/bees/rssbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/rssbee.png -------------------------------------------------------------------------------- /assets/bees/s3bee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/s3bee.png -------------------------------------------------------------------------------- /assets/bees/serialbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/serialbee.png -------------------------------------------------------------------------------- /assets/bees/simplepushbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/simplepushbee.png -------------------------------------------------------------------------------- /assets/bees/slackbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/slackbee.png -------------------------------------------------------------------------------- /assets/bees/socketbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/socketbee.png -------------------------------------------------------------------------------- /assets/bees/spaceapibee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/spaceapibee.png -------------------------------------------------------------------------------- /assets/bees/sunbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/sunbee.png -------------------------------------------------------------------------------- /assets/bees/telegrambee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/telegrambee.png -------------------------------------------------------------------------------- /assets/bees/transmissionbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/transmissionbee.png -------------------------------------------------------------------------------- /assets/bees/travisbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/travisbee.png -------------------------------------------------------------------------------- /assets/bees/tumblrbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/tumblrbee.png -------------------------------------------------------------------------------- /assets/bees/twiliobee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/twiliobee.png -------------------------------------------------------------------------------- /assets/bees/twitchbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/twitchbee.png -------------------------------------------------------------------------------- /assets/bees/twitterbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/twitterbee.png -------------------------------------------------------------------------------- /assets/bees/webbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/bees/webbee.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo.png -------------------------------------------------------------------------------- /assets/logo_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_128.png -------------------------------------------------------------------------------- /assets/logo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_16.png -------------------------------------------------------------------------------- /assets/logo_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_256.png -------------------------------------------------------------------------------- /assets/logo_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_32.png -------------------------------------------------------------------------------- /assets/logo_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_512.png -------------------------------------------------------------------------------- /assets/logo_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/assets/logo_64.png -------------------------------------------------------------------------------- /bees/alertoverbee/README.md: -------------------------------------------------------------------------------- 1 | # AlertOverbee 2 | 3 | This bee can push notification to your iOS or Android device or extension in Chrome as an action to some event. 4 | 5 | You can get your **SOURCE-KEY** and **RECEIVER-KEY** from: https://www.alertover.com/pages/api 6 | 7 | ## APP 8 | 9 | * [iOS APP](https://itunes.apple.com/cn/app/alertover-gao-xiao-mian-fei/id1069760182?l=en&mt=8) 10 | * [Android APP](http://www.wandoujia.com/apps/com.alertover.app) 11 | * [Chrome extension](https://chrome.google.com/webstore/detail/alertover/cgcgodonijnlgljfdbiicdccnldpdgia?hl=zh-CN) 12 | 13 | ## Configuration 14 | 15 | The SOURCE-KEY, RECEIVER-KEY and message content are mandatory. If the message's title is empty, it would be replaced by AlertOver. 16 | 17 | The priority of the message is option, 0 for normal and 1 for emergency, 0 and 1 is string. 18 | 19 | ### Options 20 | ```json 21 | "Bees": [ 22 | { 23 | "Name": "alertover example", 24 | "Class": "alertoverbee", 25 | "Description": "This is example of alertoverbee", 26 | "Options": [ 27 | { 28 | "Name": "source", 29 | "Value": "SOURCE-KEY" 30 | } 31 | ] 32 | }, 33 | ] 34 | ``` 35 | 36 | ### Actions 37 | 38 | ```json 39 | "Actions": [ 40 | { 41 | "Bee": "alertover example", 42 | "Name": "send", 43 | "Options": [ 44 | { 45 | "Name": "receiver", 46 | "Type": "string", 47 | "Value": "RECEIVER-KEY" 48 | }, 49 | { 50 | "Name": "title", 51 | "Type": "string", 52 | "Value": "" 53 | }, 54 | { 55 | "Name": "content", 56 | "Type": "string", 57 | "Value": "" 58 | }, 59 | { 60 | "Name": "url", 61 | "Type": "string", 62 | "Value": "" 63 | }, 64 | { 65 | "Name": "priority", 66 | "Type": "string", 67 | "Value": "" 68 | } 69 | ] 70 | }, 71 | ] 72 | ``` -------------------------------------------------------------------------------- /bees/alertoverbee/alertoverbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Henson Lu 3 | * 2015-2017 Christian Muehlhaeuser 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: 19 | * Henson Lu 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | // Package alertoverbee is able to send notifications on AlertOver. 24 | package alertoverbee 25 | 26 | import ( 27 | "net/http" 28 | "net/url" 29 | "regexp" 30 | 31 | "github.com/muesli/beehive/bees" 32 | ) 33 | 34 | // AlertOverBee is a Bee that is able to send notifications on AlertOver. 35 | type AlertOverBee struct { 36 | bees.Bee 37 | source string 38 | } 39 | 40 | // Action triggers the action passed to it. 41 | func (mod *AlertOverBee) Action(action bees.Action) []bees.Placeholder { 42 | outs := []bees.Placeholder{} 43 | 44 | switch action.Name { 45 | case "send": 46 | var receiver, title, content, weburl, priority string 47 | action.Options.Bind("receiver", &receiver) 48 | action.Options.Bind("title", &title) 49 | action.Options.Bind("content", &content) 50 | action.Options.Bind("url", &weburl) 51 | action.Options.Bind("priority", &priority) 52 | 53 | if priority == "" { 54 | priority = "0" 55 | } 56 | 57 | // the message must be plain text, so 58 | // remove the HTML tags, such as and so on 59 | re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") 60 | content = re.ReplaceAllString(content, "\n") 61 | 62 | data := url.Values{ 63 | "source": {mod.source}, 64 | "receiver": {receiver}, 65 | "title": {title}, 66 | "content": {content}, 67 | "url": {weburl}, 68 | "priority": {priority}, 69 | } 70 | resp, err := http.PostForm("https://api.alertover.com/v1/alert", data) 71 | if err != nil { 72 | panic(err) 73 | } 74 | defer resp.Body.Close() 75 | if resp.StatusCode == 200 { 76 | mod.Logln("AlertOver send message success.") 77 | } 78 | 79 | default: 80 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 81 | } 82 | 83 | return outs 84 | } 85 | 86 | // ReloadOptions parses the config options and initializes the Bee. 87 | func (mod *AlertOverBee) ReloadOptions(options bees.BeeOptions) { 88 | mod.SetOptions(options) 89 | options.Bind("source", &mod.source) 90 | } 91 | -------------------------------------------------------------------------------- /bees/anelpowerctrlbee/anelpowerctrlbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package anelpowerctrlbee is a Bee for talking to Anel's PowerCtrl network 22 | // power sockets. 23 | package anelpowerctrlbee 24 | 25 | import ( 26 | "net" 27 | "strconv" 28 | "time" 29 | 30 | "github.com/muesli/beehive/bees" 31 | ) 32 | 33 | // AnelPowerCtrlBee is a Bee for talking to Anel's PowerCtrl network power 34 | // sockets. 35 | type AnelPowerCtrlBee struct { 36 | bees.Bee 37 | 38 | addr string 39 | user string 40 | password string 41 | } 42 | 43 | func (mod *AnelPowerCtrlBee) anelSwitch(socket int, state bool) bool { 44 | conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: 0}) 45 | if err != nil { 46 | mod.LogFatal(err) 47 | } 48 | conn.SetDeadline(time.Now().Add(3 * time.Second)) 49 | 50 | addr, err := net.ResolveUDPAddr("udp", mod.addr+":75") 51 | if err != nil { 52 | mod.LogFatal(err) 53 | } 54 | 55 | stateToken := "off" 56 | if state { 57 | stateToken = "on" 58 | } 59 | b := "Sw_" + stateToken + strconv.Itoa(socket) + mod.user + mod.password 60 | 61 | _, err = conn.WriteToUDP([]byte(b), addr) 62 | if err != nil { 63 | mod.LogFatal(err) 64 | } 65 | 66 | return true 67 | } 68 | 69 | // Action triggers the action passed to it. 70 | func (mod *AnelPowerCtrlBee) Action(action bees.Action) []bees.Placeholder { 71 | outs := []bees.Placeholder{} 72 | 73 | switch action.Name { 74 | case "switch": 75 | socket := 0 76 | state := false 77 | action.Options.Bind("socket", &socket) 78 | action.Options.Bind("state", &state) 79 | 80 | mod.anelSwitch(socket, state) 81 | 82 | default: 83 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 84 | } 85 | 86 | return outs 87 | } 88 | 89 | // ReloadOptions parses the config options and initializes the Bee. 90 | func (mod *AnelPowerCtrlBee) ReloadOptions(options bees.BeeOptions) { 91 | mod.SetOptions(options) 92 | 93 | options.Bind("address", &mod.addr) 94 | options.Bind("user", &mod.user) 95 | options.Bind("password", &mod.password) 96 | } 97 | -------------------------------------------------------------------------------- /bees/cfddnsbee/README.md: -------------------------------------------------------------------------------- 1 | # CFDDNS Bee 2 | 3 | Updates a Cloudflare domain name record with the given IP. 4 | 5 | See https://api.cloudflare.com/#getting-started-endpoints 6 | 7 | ## Configuration 8 | 9 | * email: Cloudflare user email 10 | * key: Cloudflare API key 11 | * domain: Domain name record to update 12 | 13 | ## Ideas 14 | 15 | * Use it in combination with the ipify bee to update a Cloudflare domain every time your public IP changes. 16 | 17 | ## Credits 18 | 19 | Cloudflare logo: https://www.cloudflare.com/logo/ 20 | -------------------------------------------------------------------------------- /bees/cfddnsbee/cfddnsbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package cfddns 22 | 23 | import ( 24 | "regexp" 25 | 26 | "github.com/cloudflare/cloudflare-go" 27 | "github.com/muesli/beehive/bees" 28 | ) 29 | 30 | var domainSplitter = regexp.MustCompile(".+\\.(.+\\..+)") 31 | 32 | // CFDDNSBee updates a Cloudflare domain name 33 | type CFDDNSBee struct { 34 | bees.Bee 35 | client *cloudflare.API 36 | domain string 37 | } 38 | 39 | // Run executes the Bee's event loop. 40 | func (mod *CFDDNSBee) Run(eventChan chan bees.Event) { 41 | } 42 | 43 | // Action triggers the action passed to it. 44 | func (mod *CFDDNSBee) Action(action bees.Action) []bees.Placeholder { 45 | outs := []bees.Placeholder{} 46 | 47 | switch action.Name { 48 | case "update_domain": 49 | address := action.Options.Value("address").(string) 50 | domain := mod.domain 51 | zoneName := domainSplitter.FindStringSubmatch(domain)[1] 52 | // Resolve the zone and record id for the host 53 | zone, err := mod.client.ZoneIDByName(zoneName) 54 | if err != nil { 55 | mod.LogErrorf("zone id resolution failed: %v", err) 56 | return outs 57 | } 58 | recs, err := mod.client.DNSRecords(zone, cloudflare.DNSRecord{Name: domain, Type: "A"}) 59 | if err != nil { 60 | mod.LogErrorf("record id resolution failed: %v", err) 61 | return outs 62 | } 63 | if len(recs) != 1 { 64 | mod.LogErrorf("invalid number of DNS records found: %+v", recs) 65 | return outs 66 | } 67 | record := recs[0] 68 | 69 | // Post the Cloudflare dns update 70 | record.Content = address 71 | 72 | if err := mod.client.UpdateDNSRecord(zone, record.ID, record); err != nil { 73 | mod.LogErrorf("dns record update for %s failed: %v", domain, err) 74 | } 75 | default: 76 | mod.LogDebugf("Unknown action triggered in %s: %s", mod.Name(), action.Name) 77 | } 78 | 79 | return outs 80 | } 81 | 82 | // ReloadOptions parses the config options and initializes the Bee. 83 | func (mod *CFDDNSBee) ReloadOptions(options bees.BeeOptions) { 84 | mod.SetOptions(options) 85 | key := options.Value("key").(string) 86 | user := options.Value("email").(string) 87 | mod.domain = options.Value("domain").(string) 88 | c, err := cloudflare.New(key, user) 89 | if err != nil { 90 | mod.LogFatal(err) 91 | } 92 | mod.client = c 93 | } 94 | -------------------------------------------------------------------------------- /bees/cleverbotbee/README.md: -------------------------------------------------------------------------------- 1 | # Cleverbotbee 2 | 3 | CleverbotBee is a simple bee chatting with cleverbot. 4 | You can send messages to the bot as action and you'll receive the answer as an 5 | event. 6 | 7 | --- 8 | 9 | You'll need an cleverbot api account containing username and key to access the 10 | cleverbot api. You can grab one [here](https://cleverbot.io/keys) 11 | 12 | -------------------------------------------------------------------------------- /bees/cleverbotbee/cleverbotbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | * Nicolas Martin 20 | */ 21 | 22 | // Package cleverbotbee is a Bee that can interact with cleverbot 23 | package cleverbotbee 24 | 25 | import ( 26 | "github.com/CleverbotIO/go-cleverbot.io" 27 | "github.com/muesli/beehive/bees" 28 | ) 29 | 30 | // CleverbotBee is a Bee that can chat with cleverbot 31 | type CleverbotBee struct { 32 | bees.Bee 33 | 34 | client *cleverbot.Session 35 | 36 | api_user string 37 | api_key string 38 | session_nick string 39 | 40 | evchan chan bees.Event 41 | } 42 | 43 | // Action triggers the action passed to it. 44 | func (mod *CleverbotBee) Action(action bees.Action) []bees.Placeholder { 45 | outs := []bees.Placeholder{} 46 | 47 | switch action.Name { 48 | case "send_message": 49 | var text string 50 | action.Options.Bind("text", &text) 51 | 52 | resp, err := mod.client.Ask(text) 53 | if err != nil { 54 | mod.LogErrorf("Failed to ask cleverbot: %v", err) 55 | return nil 56 | } 57 | 58 | ev := bees.Event{ 59 | Bee: mod.Name(), 60 | Name: "answer", 61 | Options: []bees.Placeholder{ 62 | { 63 | Name: "answer", 64 | Type: "string", 65 | Value: resp, 66 | }, 67 | }, 68 | } 69 | mod.evchan <- ev 70 | 71 | default: 72 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 73 | } 74 | 75 | return outs 76 | } 77 | 78 | // Run executes the Bee's event loop. 79 | func (mod *CleverbotBee) Run(eventChan chan bees.Event) { 80 | mod.evchan = eventChan 81 | 82 | client, err := cleverbot.New(mod.api_user, mod.api_key, mod.session_nick) 83 | if err != nil { 84 | mod.LogErrorf("Failed to start session: %v", err) 85 | return 86 | } 87 | mod.client = client 88 | 89 | select { 90 | case <-mod.SigChan: 91 | return 92 | } 93 | } 94 | 95 | // ReloadOptions parses the config options and initializes the Bee. 96 | func (mod *CleverbotBee) ReloadOptions(options bees.BeeOptions) { 97 | mod.SetOptions(options) 98 | 99 | options.Bind("api_user", &mod.api_user) 100 | options.Bind("api_key", &mod.api_key) 101 | options.Bind("session_nick", &mod.session_nick) 102 | } 103 | -------------------------------------------------------------------------------- /bees/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | import "errors" 25 | 26 | // BeeConfig contains all settings for a single Bee. 27 | type BeeConfig struct { 28 | Name string 29 | Class string 30 | Description string 31 | Options BeeOptions 32 | } 33 | 34 | // NewBeeConfig validates a configuration and sets up a new BeeConfig 35 | func NewBeeConfig(name, class, description string, options BeeOptions) (BeeConfig, error) { 36 | if len(name) == 0 { 37 | return BeeConfig{}, errors.New("A Bee's name can't be empty") 38 | } 39 | 40 | b := GetBee(name) 41 | if b != nil { 42 | return BeeConfig{}, errors.New("A Bee with that name already exists") 43 | } 44 | 45 | f := GetFactory(class) 46 | if f == nil { 47 | return BeeConfig{}, errors.New("Invalid class specified") 48 | } 49 | 50 | return BeeConfig{ 51 | Name: name, 52 | Class: class, 53 | Description: description, 54 | Options: options, 55 | }, nil 56 | } 57 | 58 | // BeeConfigs returns configs for all Bees. 59 | func BeeConfigs() []BeeConfig { 60 | bs := []BeeConfig{} 61 | for _, b := range bees { 62 | bs = append(bs, (*b).Config()) 63 | } 64 | 65 | return bs 66 | } 67 | -------------------------------------------------------------------------------- /bees/context.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | var ( 25 | ctx = NewContext() 26 | ) 27 | 28 | type Context struct { 29 | state map[*Bee]map[string]interface{} 30 | } 31 | 32 | func NewContext() *Context { 33 | return &Context{ 34 | state: make(map[*Bee]map[string]interface{}), 35 | } 36 | } 37 | 38 | func (c *Context) Set(bee *Bee, key string, value interface{}) { 39 | if _, ok := c.state[bee]; !ok { 40 | c.state[bee] = make(map[string]interface{}) 41 | } 42 | c.state[bee][key] = value 43 | } 44 | 45 | func (c *Context) Value(bee *Bee, key string) interface{} { 46 | return c.state[bee][key] 47 | } 48 | 49 | func (c *Context) FillMap(m map[string]interface{}) { 50 | cd := make(map[string]interface{}) 51 | for bee, d := range c.state { 52 | cd[bee.Name()] = d 53 | } 54 | m["context"] = cd 55 | } 56 | 57 | func (bee *Bee) ContextSet(key string, value interface{}) { 58 | ctx.Set(bee, key, value) 59 | } 60 | 61 | func (bee *Bee) ContextValue(key string) interface{} { 62 | return ctx.Value(bee, key) 63 | } 64 | -------------------------------------------------------------------------------- /bees/cricketbee/README.md: -------------------------------------------------------------------------------- 1 | ### Options 2 | 3 | Accepted favourite team value 4 | 1. Ind (India) 5 | 2. WI (West Indies) 6 | 3. Eng (England) 7 | 4. Aus (Australia) 8 | 5. Pak (Pakistan) 9 | 6. Sri (Srilanka) 10 | 7. Ban (Bangladesh) 11 | 12 | ### Events 13 | 1. Run change 14 | 2. Over change 15 | 3. Wicket fall 16 | -------------------------------------------------------------------------------- /bees/cricketbee/cricketbee.go: -------------------------------------------------------------------------------- 1 | package cricketbee 2 | 3 | /* 4 | * Copyright (C) 2017 Akash Shinde 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Akash Shinde 21 | */ 22 | 23 | import ( 24 | "github.com/akashshinde/go_cricket" 25 | "github.com/muesli/beehive/bees" 26 | ) 27 | 28 | type CricketBee struct { 29 | bees.Bee 30 | favTeam string 31 | event chan gocricket.ResponseEvent 32 | beeEvt chan bees.Event 33 | } 34 | 35 | func (c *CricketBee) placeholderOptions(r gocricket.ResponseEvent) []bees.Placeholder { 36 | return []bees.Placeholder{ 37 | { 38 | Name: "batting_team", 39 | Type: "string", 40 | Value: r.BtTeamName, 41 | }, 42 | { 43 | Name: "score", 44 | Type: "string", 45 | Value: r.Runs, 46 | }, 47 | { 48 | Name: "wickets", 49 | Type: "string", 50 | Value: r.Wickets, 51 | }, 52 | { 53 | Name: "overs", 54 | Type: "string", 55 | Value: r.Overs, 56 | }, 57 | } 58 | } 59 | 60 | func (c *CricketBee) announceCricketEvent(response gocricket.ResponseEvent) { 61 | switch response.EventType { 62 | case gocricket.EVENT_OUT: 63 | c.beeEvt <- bees.Event{ 64 | Name: "out", 65 | Options: c.placeholderOptions(response), 66 | Bee: c.Name(), 67 | } 68 | case gocricket.EVENT_OVER_CHANGED: 69 | c.beeEvt <- bees.Event{ 70 | Name: "over_changed", 71 | Options: c.placeholderOptions(response), 72 | Bee: c.Name(), 73 | } 74 | case gocricket.EVENT_RUN_CHANGE: 75 | c.beeEvt <- bees.Event{ 76 | Name: "run_change", 77 | Options: c.placeholderOptions(response), 78 | Bee: c.Name(), 79 | } 80 | } 81 | } 82 | 83 | func (c *CricketBee) Run(cin chan bees.Event) { 84 | evt := make(chan gocricket.ResponseEvent) 85 | // Start Cricket GoRoutine to poll cricket score 86 | cricket := gocricket.NewCricketWatcher(c.favTeam, evt) 87 | cricket.Start() 88 | c.beeEvt = cin 89 | for { 90 | select { 91 | case e := <-evt: 92 | c.announceCricketEvent(e) 93 | 94 | case <-c.SigChan: 95 | return 96 | } 97 | } 98 | } 99 | 100 | // ReloadOptions parses the config options and initializes the Bee. 101 | func (mod *CricketBee) ReloadOptions(options bees.BeeOptions) { 102 | mod.SetOptions(options) 103 | options.Bind("favourite_team", &mod.favTeam) 104 | } 105 | -------------------------------------------------------------------------------- /bees/cronbee/cronbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Stefan 'glaxx' Luecke 3 | * 2014-2017 Christian Muehlhaeuser 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: 19 | * Stefan Luecke 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | // Package cronbee is a Bee that acts like a time-based job scheduler (cron). 24 | package cronbee 25 | 26 | import ( 27 | "strings" 28 | "time" 29 | 30 | "github.com/muesli/beehive/bees" 31 | "github.com/robfig/cron/v3" 32 | ) 33 | 34 | // CronBee is a Bee that acts like a time-based job scheduler (cron). 35 | type CronBee struct { 36 | bees.Bee 37 | input [6]string 38 | eventChan chan bees.Event 39 | } 40 | 41 | func (mod *CronBee) runTask() { 42 | mod.LogDebugf("Running cron task " + strings.Join(mod.input[:], " ")) 43 | event := bees.Event{ 44 | Bee: mod.Name(), 45 | Name: "time", 46 | Options: []bees.Placeholder{ 47 | { 48 | Name: "timestamp", 49 | Type: "string", 50 | Value: time.Now().Format(time.RFC3339), 51 | }, 52 | }, 53 | } 54 | mod.eventChan <- event 55 | } 56 | 57 | // Run executes the Bee's event loop. 58 | func (mod *CronBee) Run(eventChan chan bees.Event) { 59 | mod.eventChan = eventChan 60 | c := cron.New(cron.WithSeconds()) 61 | mod.LogDebugf("Scheduling " + strings.Join(mod.input[:], " ")) 62 | _, err := c.AddFunc(strings.Join(mod.input[:], " "), mod.runTask) 63 | if err != nil { 64 | mod.LogFatal(err) 65 | } 66 | c.Start() 67 | 68 | for { 69 | select { 70 | case <-mod.SigChan: 71 | return 72 | } 73 | } 74 | } 75 | 76 | // ReloadOptions parses the config options and initializes the Bee. 77 | func (mod *CronBee) ReloadOptions(options bees.BeeOptions) { 78 | mod.SetOptions(options) 79 | 80 | options.Bind("second", &mod.input[0]) 81 | options.Bind("minute", &mod.input[1]) 82 | options.Bind("hour", &mod.input[2]) 83 | options.Bind("day_of_week", &mod.input[3]) 84 | options.Bind("day_of_month", &mod.input[4]) 85 | options.Bind("month", &mod.input[5]) 86 | } 87 | -------------------------------------------------------------------------------- /bees/cronbee/thoughts.txt: -------------------------------------------------------------------------------- 1 | 30 0 1 1,6,12 * 2 | 3 | 0 20 * 10 1-5 4 | 5 | 0 0 1,10,15 * * 6 | 7 | 5,10 0 10 * 1 8 | 9 | 10 | 11 | 12 | now: 25.07 13 | 14 | { 15 | months: 1,6,12 16 | days: 1 17 | = 18 | created next timestamp: 01.12 19 | } 20 | 21 | { 22 | months: 10 23 | days: * 24 | hour: 20 25 | minute: 0 26 | 27 | created next timestamp: 01.10 20:00 28 | } 29 | 30 | 31 | 32 | now: 10.07 16:30 33 | 34 | { 35 | months: * 36 | days: 1,10,15 37 | hour: 0 38 | minute: 0 39 | 40 | created next timestamp: 15.07 00:00 41 | } 42 | 43 | 44 | nextValidMonth(now = 7, input = "*") int { 45 | if input == "*" || now == input 46 | return now 47 | 48 | // 5 - 8 => 7 49 | // 5 - 6 => 5 50 | } 51 | 52 | 53 | // expected: 2015.07.01 17:00 54 | nextValidTimestamp(now = 2014.07.31 18:30, input = "0 17 * 7") { 55 | created := "0000.00.00 00:00" 56 | 57 | created.Month := nextValidMonth(07, "7") // -> 7 58 | created.Day := nextValidDay(25, "1") // -> 31 59 | created.Hour := nextValidHour(18, "17") // -> 17 60 | 61 | // 2014.07.31 17:00 62 | if created < now { 63 | created.Day = nextValidDay(31 + 1, "*") // -> 1 64 | // 2014.07.01 17:00 65 | if created < now { 66 | created.Month = nextValidMonth(7 + 1, "7") // -> 7 67 | // 2014.07.01 17:00 68 | if created < now { 69 | created.Year++ 70 | // 2015.07.01 17:00 71 | } 72 | } 73 | } 74 | } 75 | 76 | created next timestamp - now() => duration until next event 77 | -------------------------------------------------------------------------------- /bees/descriptors.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | // EventDescriptor describes an Event provided by a Bee. 25 | type EventDescriptor struct { 26 | Namespace string 27 | Name string 28 | Description string 29 | Options []PlaceholderDescriptor 30 | } 31 | 32 | // ActionDescriptor describes an Action provided by a Bee. 33 | type ActionDescriptor struct { 34 | Namespace string 35 | Name string 36 | Description string 37 | Options []PlaceholderDescriptor 38 | } 39 | 40 | // A PlaceholderDescriptor shows which in & out values a module expects and returns. 41 | type PlaceholderDescriptor struct { 42 | Name string 43 | Description string 44 | Type string 45 | Mandatory bool 46 | } 47 | 48 | // A BeeOptionDescriptor shows which config values a module expects. 49 | type BeeOptionDescriptor struct { 50 | Name string 51 | Description string 52 | Type string 53 | Default interface{} 54 | Mandatory bool 55 | } 56 | 57 | // StateDescriptor describes a State provided by a Bee. 58 | type StateDescriptor struct { 59 | Name string 60 | Description string 61 | Type string 62 | } 63 | 64 | // GetActionDescriptor returns the ActionDescriptor matching an action. 65 | func GetActionDescriptor(action *Action) ActionDescriptor { 66 | bee := GetBee(action.Bee) 67 | if bee == nil { 68 | panic("Bee " + action.Bee + " not registered") 69 | } 70 | factory := (*GetFactory((*bee).Namespace())) 71 | for _, ac := range factory.Actions() { 72 | if ac.Name == action.Name { 73 | return ac 74 | } 75 | } 76 | 77 | return ActionDescriptor{} 78 | } 79 | 80 | // GetEventDescriptor returns the EventDescriptor matching an event. 81 | func GetEventDescriptor(event *Event) EventDescriptor { 82 | bee := GetBee(event.Bee) 83 | if bee == nil { 84 | panic("Bee " + event.Bee + " not registered") 85 | } 86 | factory := (*GetFactory((*bee).Namespace())) 87 | for _, ev := range factory.Events() { 88 | if ev.Name == event.Name { 89 | return ev 90 | } 91 | } 92 | 93 | return EventDescriptor{} 94 | } 95 | -------------------------------------------------------------------------------- /bees/emailbee/emailbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package emailbee is a Bee that is able to send emails. 22 | package emailbee 23 | 24 | import ( 25 | "net" 26 | 27 | "strconv" 28 | 29 | "github.com/go-mail/mail" 30 | "github.com/muesli/beehive/bees" 31 | ) 32 | 33 | // EmailBee is a Bee that is able to send emails. 34 | type EmailBee struct { 35 | bees.Bee 36 | 37 | username string 38 | password string 39 | server string 40 | } 41 | 42 | // Action triggers the action passed to it. 43 | func (mod *EmailBee) Action(action bees.Action) []bees.Placeholder { 44 | outs := []bees.Placeholder{} 45 | 46 | switch action.Name { 47 | case "send": 48 | var from, to, plainText, htmlText, subject string 49 | action.Options.Bind("sender", &from) 50 | action.Options.Bind("recipient", &to) 51 | action.Options.Bind("subject", &subject) 52 | action.Options.Bind("text", &plainText) 53 | action.Options.Bind("html", &htmlText) 54 | 55 | m := mail.NewMessage() 56 | if len(from) > 0 { 57 | m.SetHeader("From", from) 58 | } else { 59 | m.SetHeader("From", mod.username) 60 | } 61 | m.SetHeader("To", to) 62 | m.SetHeader("Subject", subject) 63 | if plainText != "" { 64 | m.SetBody("text/plain", plainText) 65 | } 66 | if htmlText != "" { 67 | m.SetBody("text/html", htmlText) 68 | } 69 | 70 | host, portstr, err := net.SplitHostPort(mod.server) 71 | if err != nil { 72 | host = mod.server 73 | portstr = "587" 74 | } 75 | port, _ := strconv.Atoi(portstr) 76 | 77 | if len(mod.username) > 0 && len(mod.password) > 0 { 78 | // With authentication 79 | if err := mail.NewDialer(host, port, mod.username, mod.password).DialAndSend(m); err != nil { 80 | panic(err) 81 | } 82 | } else { 83 | // No Auth 84 | d := mail.Dialer{Host: host, Port: port} 85 | if err := d.DialAndSend(m); err != nil { 86 | panic(err) 87 | } 88 | } 89 | 90 | default: 91 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 92 | } 93 | 94 | return outs 95 | } 96 | 97 | // ReloadOptions parses the config options and initializes the Bee. 98 | func (mod *EmailBee) ReloadOptions(options bees.BeeOptions) { 99 | mod.SetOptions(options) 100 | 101 | options.Bind("username", &mod.username) 102 | options.Bind("password", &mod.password) 103 | options.Bind("address", &mod.server) 104 | } 105 | -------------------------------------------------------------------------------- /bees/events.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | import ( 25 | "fmt" 26 | "runtime/debug" 27 | 28 | log "github.com/sirupsen/logrus" 29 | ) 30 | 31 | // An Event describes an event including its parameters. 32 | type Event struct { 33 | Bee string 34 | Name string 35 | Options Placeholders 36 | } 37 | 38 | var ( 39 | eventsIn = make(chan Event) 40 | ) 41 | 42 | // handleEvents handles incoming events and executes matching Chains. 43 | func handleEvents() { 44 | for { 45 | event, ok := <-eventsIn 46 | if !ok { 47 | log.Println() 48 | log.Println("Stopped event handler!") 49 | break 50 | } 51 | 52 | bee := GetBee(event.Bee) 53 | (*bee).LogEvent() 54 | 55 | log.Debugln() 56 | log.Debugln("Event received:", event.Bee, "/", event.Name, "-", GetEventDescriptor(&event).Description) 57 | for _, v := range event.Options { 58 | vv := truncateString(fmt.Sprintln(v), 1000) 59 | log.Debugln("\tOptions:", vv) 60 | } 61 | 62 | go func() { 63 | defer func() { 64 | if e := recover(); e != nil { 65 | log.Printf("Fatal chain event: %s %s", e, debug.Stack()) 66 | } 67 | }() 68 | 69 | execChains(&event) 70 | }() 71 | } 72 | } 73 | 74 | func truncateString(str string, num int) string { 75 | bnoden := str 76 | if len(str) > num { 77 | if num > 3 { 78 | num -= 3 79 | } 80 | bnoden = str[0:num] + "... (" + fmt.Sprint(len(str)-num) + " more characters)" 81 | } 82 | return bnoden 83 | } 84 | -------------------------------------------------------------------------------- /bees/filters.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | import ( 25 | log "github.com/sirupsen/logrus" 26 | 27 | "github.com/muesli/beehive/filters" 28 | ) 29 | 30 | // Filter describes a user configured event filter. 31 | type Filter struct { 32 | ID string 33 | Name string 34 | Options FilterOption 35 | } 36 | 37 | // execFilter executes a filter. Returns whether the filter passed or not. 38 | func execFilter(filter string, opts map[string]interface{}) bool { 39 | f := *filters.GetFilter("template") 40 | log.Println("\tExecuting filter:", filter) 41 | 42 | defer func() { 43 | if e := recover(); e != nil { 44 | log.Println("Fatal filter event:", e) 45 | } 46 | }() 47 | 48 | return f.Passes(opts, filter) 49 | } 50 | -------------------------------------------------------------------------------- /bees/fsnotifybee/README.md: -------------------------------------------------------------------------------- 1 | # FSNotify bee 2 | 3 | Monitors filesystem paths and sends events when files are created, removed or modified. 4 | 5 | ## Configuration 6 | 7 | * path: Path to monitor (file or directory). 8 | 9 | ## Events 10 | 11 | **fsevent** 12 | 13 | * type: the event type received (CREATE, REMOVE, RENAME, CHMOD). 14 | * path: filesystem path that triggered the event. 15 | 16 | ## Credits 17 | 18 | File manager logo: https://openclipart.org/detail/35329/tango-system-file-manager 19 | -------------------------------------------------------------------------------- /bees/fsnotifybee/fsnotifybee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package fsnotifybee 22 | 23 | import ( 24 | "github.com/fsnotify/fsnotify" 25 | "github.com/muesli/beehive/bees" 26 | ) 27 | 28 | type FSNotifyBee struct { 29 | bees.Bee 30 | } 31 | 32 | func (mod *FSNotifyBee) Run(eventChan chan bees.Event) { 33 | watcher, err := fsnotify.NewWatcher() 34 | if err != nil { 35 | mod.LogFatal("error: could not create the fswatcher:", err) 36 | } 37 | defer watcher.Close() 38 | 39 | path := mod.Options().Value("path").(string) 40 | mod.Logf("monitoring %s\n", path) 41 | 42 | err = watcher.Add(path) 43 | if err != nil { 44 | mod.LogErrorf("error: watching %s failed: %v", path, err) 45 | return 46 | } 47 | for { 48 | select { 49 | case <-mod.SigChan: 50 | return 51 | case event := <-watcher.Events: 52 | if event.Op != fsnotify.Write && event.Op != 0 { 53 | sendEvent(mod.Name(), event.Op.String(), event.Name, eventChan) 54 | } 55 | case <-watcher.Errors: 56 | } 57 | } 58 | } 59 | 60 | func (mod *FSNotifyBee) ReloadOptions(options bees.BeeOptions) { 61 | mod.SetOptions(options) 62 | } 63 | 64 | func sendEvent(bee, etype, path string, eventChan chan bees.Event) { 65 | event := bees.Event{ 66 | Bee: bee, 67 | Name: "fsevent", 68 | Options: []bees.Placeholder{ 69 | { 70 | Name: "type", 71 | Type: "string", 72 | Value: etype, 73 | }, 74 | { 75 | Name: "path", 76 | Type: "string", 77 | Value: path, 78 | }, 79 | }, 80 | } 81 | eventChan <- event 82 | } 83 | -------------------------------------------------------------------------------- /bees/gitterbee/README.md: -------------------------------------------------------------------------------- 1 | # Rooms 2 | A rooms name is always the the last part of the uri. 3 | For example: `the_beehive/Lobby` 4 | -------------------------------------------------------------------------------- /bees/gotifybee/README.md: -------------------------------------------------------------------------------- 1 | # GotifyBee 2 | 3 | This bee can push notification to the specified gotify application as an action to some event. 4 | 5 | You can get your **TOKEN** for your specified gotify application by going to the **APPS** section of the gotify server instance 6 | and unhiding the token for your desired application. 7 | 8 | ## APP 9 | 10 | * [Android APP](https://play.google.com/store/apps/details?id=com.github.gotify&hl=en_US&gl=US) 11 | * [Chrome extension](https://chrome.google.com/webstore/detail/gotify-push/cbegkpikakpajcaoblfkeindhhikpfmd?hl=en) 12 | 13 | ## Configuration 14 | 15 | The **message** field is required. If the message's title is empty, it would be replaced by Gotify. 16 | 17 | The priority of the message is option. 18 | 19 | ### Options 20 | ```json 21 | "Bees": [ 22 | { 23 | "Name": "gotify example", 24 | "Class": "gotify", 25 | "Description": "This is example of gotify", 26 | "Options": [ 27 | { 28 | "Name": "token", 29 | "Value": "TOKEN" 30 | } 31 | ] 32 | }, 33 | ] 34 | ``` 35 | 36 | ### Actions 37 | 38 | ```json 39 | "Actions": [ 40 | { 41 | "Bee": "gotify example", 42 | "Name": "send", 43 | "Options": [ 44 | { 45 | "Name": "title", 46 | "Type": "string", 47 | "Value": "" 48 | }, 49 | { 50 | "Name": "message", 51 | "Type": "string", 52 | "Value": "" 53 | }, 54 | { 55 | "Name": "priority", 56 | "Type": "string", 57 | "Value": "" 58 | } 59 | ] 60 | }, 61 | ] 62 | ``` -------------------------------------------------------------------------------- /bees/gotifybee/gotifybee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 deranjer 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * deranjer 19 | */ 20 | 21 | // Package gotifybee is able to send notifications on Gotify. 22 | package gotifybee 23 | 24 | import ( 25 | "net/http" 26 | "net/url" 27 | "regexp" 28 | 29 | "github.com/muesli/beehive/bees" 30 | ) 31 | 32 | // GotifyBee is a Bee that is able to send notifications on Gotify. 33 | type GotifyBee struct { 34 | bees.Bee 35 | token string 36 | serverURL string 37 | } 38 | 39 | // Action triggers the action passed to it. 40 | func (mod *GotifyBee) Action(action bees.Action) []bees.Placeholder { 41 | outs := []bees.Placeholder{} 42 | 43 | switch action.Name { 44 | case "send": 45 | var title, message, priority string 46 | action.Options.Bind("title", &title) 47 | action.Options.Bind("message", &message) 48 | action.Options.Bind("priority", &priority) 49 | 50 | if priority == "" { 51 | priority = "0" 52 | } 53 | if title == "" { 54 | title = "Gotify" 55 | } 56 | 57 | // the message must be plain text, so 58 | // remove the HTML tags, such as and so on 59 | re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") 60 | message = re.ReplaceAllString(message, "\n") 61 | 62 | data := url.Values{ 63 | "title": {title}, 64 | "message": {message}, 65 | "priority": {priority}, 66 | } 67 | // Build the URL for sending the message 68 | rawURL := mod.serverURL + "message?token=" + mod.token 69 | resp, err := http.PostForm(rawURL, data) 70 | if err != nil { 71 | panic(err) 72 | } 73 | defer resp.Body.Close() 74 | if resp.StatusCode == 200 { 75 | mod.Logln("Gotify send message success.") 76 | } 77 | 78 | default: 79 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 80 | } 81 | 82 | return outs 83 | } 84 | 85 | // ReloadOptions parses the config options and initializes the Bee. 86 | func (mod *GotifyBee) ReloadOptions(options bees.BeeOptions) { 87 | mod.SetOptions(options) 88 | options.Bind("token", &mod.token) 89 | options.Bind("serverURL", &mod.serverURL) 90 | } 91 | -------------------------------------------------------------------------------- /bees/hellobee/hellobee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Michael Wendland 3 | * 2014-2017 Christian Muehlhaeuser 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: 19 | * Michael Wendland 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | // Package hellobee is an example for a Bee skeleton, designed to help you get 24 | // started with writing your own Bees. 25 | package hellobee 26 | 27 | import ( 28 | "github.com/muesli/beehive/bees" 29 | ) 30 | 31 | // HelloBee is an example for a Bee skeleton, designed to help you get started 32 | // with writing your own Bees. 33 | type HelloBee struct { 34 | bees.Bee 35 | } 36 | 37 | // Run executes the Bee's event loop. 38 | func (mod *HelloBee) Run(eventChan chan bees.Event) { 39 | /* ev := bees.Event{ 40 | Bee: mod.Name(), 41 | Name: "hello", 42 | Options: []bees.Placeholder{}, 43 | } 44 | 45 | eventChan <- ev*/ 46 | } 47 | 48 | // Action triggers the action passed to it. 49 | func (mod *HelloBee) Action(action bees.Action) []bees.Placeholder { 50 | return []bees.Placeholder{} 51 | } 52 | 53 | // ReloadOptions parses the config options and initializes the Bee. 54 | func (mod *HelloBee) ReloadOptions(options bees.BeeOptions) { 55 | mod.SetOptions(options) 56 | } 57 | -------------------------------------------------------------------------------- /bees/hellobee/hellobeefactory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package hellobee 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | ) 26 | 27 | // HelloBeeFactory is a factory for HelloBees. 28 | type HelloBeeFactory struct { 29 | bees.BeeFactory 30 | } 31 | 32 | // New returns a new Bee instance configured with the supplied options. 33 | func (factory *HelloBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { 34 | bee := HelloBee{ 35 | Bee: bees.NewBee(name, factory.ID(), description, options), 36 | } 37 | bee.ReloadOptions(options) 38 | 39 | return &bee 40 | } 41 | 42 | // ID returns the ID of this Bee. 43 | func (factory *HelloBeeFactory) ID() string { 44 | return "hellobee" 45 | } 46 | 47 | // Name returns the name of this Bee. 48 | func (factory *HelloBeeFactory) Name() string { 49 | return "Hello" 50 | } 51 | 52 | // Description returns the description of this Bee. 53 | func (factory *HelloBeeFactory) Description() string { 54 | return "A 'Hello World' module for beehive" 55 | } 56 | 57 | func init() { 58 | f := HelloBeeFactory{} 59 | bees.RegisterFactory(&f) 60 | } 61 | -------------------------------------------------------------------------------- /bees/instapaperbee/instapaperbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Adam Petrovic 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Adam Petrovic 19 | */ 20 | 21 | package instapaperbee 22 | 23 | import ( 24 | "net/http" 25 | "net/url" 26 | 27 | "github.com/muesli/beehive/bees" 28 | ) 29 | 30 | type InstapaperBee struct { 31 | bees.Bee 32 | 33 | username string 34 | password string 35 | } 36 | 37 | func (mod *InstapaperBee) Action(action bees.Action) []bees.Placeholder { 38 | switch action.Name { 39 | case "save": 40 | var title, page_url string 41 | action.Options.Bind("title", &title) 42 | action.Options.Bind("url", &page_url) 43 | 44 | msg := url.Values{} 45 | msg.Set("username", mod.username) 46 | msg.Set("password", mod.password) 47 | msg.Set("url", page_url) 48 | 49 | if title != "" { 50 | msg.Set("title", title) 51 | } 52 | mod.LogDebugf("Message: %s", msg) 53 | resp, err := http.PostForm("https://www.instapaper.com/api/add", msg) 54 | if err != nil { 55 | panic(err) 56 | } 57 | defer resp.Body.Close() 58 | if resp.StatusCode == 200 { 59 | mod.LogDebugf("Added article to instapaper.") 60 | } 61 | default: 62 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 63 | } 64 | return []bees.Placeholder{} 65 | } 66 | 67 | func (mod *InstapaperBee) ReloadOptions(options bees.BeeOptions) { 68 | mod.SetOptions(options) 69 | options.Bind("username", &mod.username) 70 | options.Bind("password", &mod.password) 71 | } 72 | -------------------------------------------------------------------------------- /bees/instapaperbee/instapaperbeefactory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Adam Petrovic 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Adam Petrovic 19 | */ 20 | 21 | package instapaperbee 22 | 23 | import "github.com/muesli/beehive/bees" 24 | 25 | type InstapaperBeeFactory struct { 26 | bees.BeeFactory 27 | } 28 | 29 | func (factory *InstapaperBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { 30 | bee := InstapaperBee{ 31 | Bee: bees.NewBee(name, factory.ID(), description, options), 32 | } 33 | bee.ReloadOptions(options) 34 | return &bee 35 | } 36 | 37 | func (factory *InstapaperBeeFactory) ID() string { 38 | return "instapaperbee" 39 | } 40 | 41 | func (factory *InstapaperBeeFactory) Name() string { 42 | return "Instapaper" 43 | } 44 | 45 | func (factory *InstapaperBeeFactory) Description() string { 46 | return "Add to Instapaper" 47 | } 48 | 49 | func (factory *InstapaperBeeFactory) Image() string { 50 | return factory.ID() + ".png" 51 | } 52 | 53 | func (factory *InstapaperBeeFactory) LogoColor() string { 54 | return "#808080" 55 | } 56 | 57 | func (factory *InstapaperBeeFactory) Options() []bees.BeeOptionDescriptor { 58 | opts := []bees.BeeOptionDescriptor{ 59 | { 60 | Name: "username", 61 | Description: "Instapaper Username / Email", 62 | Type: "string", 63 | Mandatory: true, 64 | }, 65 | { 66 | Name: "password", 67 | Description: "Instapaper Password", 68 | Type: "string", 69 | Mandatory: true, 70 | }, 71 | } 72 | return opts 73 | } 74 | 75 | func (factory *InstapaperBeeFactory) Actions() []bees.ActionDescriptor { 76 | actions := []bees.ActionDescriptor{ 77 | { 78 | Namespace: factory.Name(), 79 | Name: "save", 80 | Description: "Saves a URL to Instapaper", 81 | Options: []bees.PlaceholderDescriptor{ 82 | { 83 | Name: "title", 84 | Description: "Article title", 85 | Type: "string", 86 | Mandatory: false, 87 | }, 88 | { 89 | Name: "url", 90 | Description: "Article URL", 91 | Type: "string", 92 | Mandatory: true, 93 | }, 94 | }, 95 | }, 96 | } 97 | return actions 98 | } 99 | 100 | func init() { 101 | f := InstapaperBeeFactory{} 102 | bees.RegisterFactory(&f) 103 | } 104 | -------------------------------------------------------------------------------- /bees/ipifybee/README.md: -------------------------------------------------------------------------------- 1 | # Ipify Bee 2 | 3 | Queries ipify.org for the public IP and sends an event if the IP changed. 4 | 5 | ## Configuration 6 | 7 | * interval: Interval (in seconds) between requests sent to ipify.org 8 | 9 | ## Credits 10 | 11 | ipify logo: https://github.com/rdegges/ipify-www/blob/master/static/images/globe.png 12 | -------------------------------------------------------------------------------- /bees/ipifybee/ipifybee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package ipify 22 | 23 | import ( 24 | "time" 25 | 26 | "github.com/muesli/beehive/bees" 27 | "github.com/rdegges/go-ipify" 28 | ) 29 | 30 | type IpifyBee struct { 31 | bees.Bee 32 | interval int 33 | } 34 | 35 | func (mod *IpifyBee) getIP(oldIP string, eventChan chan bees.Event) string { 36 | ip, err := ipify.GetIp() 37 | if err != nil { 38 | ip, err = ipify.GetIp() 39 | if err != nil { 40 | panic(err) 41 | } 42 | } 43 | 44 | if oldIP != ip { 45 | ev := bees.Event{ 46 | Bee: mod.Name(), 47 | Name: "ip", 48 | Options: []bees.Placeholder{ 49 | { 50 | Name: "ip", 51 | Type: "string", 52 | Value: ip, 53 | }, 54 | }, 55 | } 56 | eventChan <- ev 57 | return ip 58 | } 59 | 60 | return oldIP 61 | } 62 | 63 | // Run executes the Bee's event loop. 64 | func (mod *IpifyBee) Run(eventChan chan bees.Event) { 65 | // protects us against a user setting the wrong value here 66 | if mod.interval < 1 { 67 | mod.interval = defaultUpdateInterval 68 | } 69 | 70 | oldIP := mod.getIP("", eventChan) 71 | 72 | for { 73 | select { 74 | case <-mod.SigChan: 75 | return 76 | case <-time.After(time.Duration(mod.interval) * time.Minute): 77 | mod.LogDebugf("Retrieving public IP from ipify.com") 78 | oldIP = mod.getIP(oldIP, eventChan) 79 | } 80 | } 81 | } 82 | 83 | // Action triggers the action passed to it. 84 | func (mod *IpifyBee) Action(action bees.Action) []bees.Placeholder { 85 | return []bees.Placeholder{} 86 | } 87 | 88 | // ReloadOptions parses the config options and initializes the Bee. 89 | func (mod *IpifyBee) ReloadOptions(options bees.BeeOptions) { 90 | mod.SetOptions(options) 91 | options.Bind("interval", &mod.interval) 92 | } 93 | -------------------------------------------------------------------------------- /bees/ipifybee/ipifybeefactory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package ipify 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | ) 26 | 27 | const defaultUpdateInterval int = 60 28 | 29 | // IpifyBeeFactory takes care of initializing IpifyBee 30 | type IpifyBeeFactory struct { 31 | bees.BeeFactory 32 | } 33 | 34 | // New returns a new Bee instance configured with the supplied options. 35 | func (factory *IpifyBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { 36 | bee := IpifyBee{ 37 | Bee: bees.NewBee(name, factory.ID(), description, options), 38 | } 39 | bee.ReloadOptions(options) 40 | 41 | return &bee 42 | } 43 | 44 | // ID returns the ID of this Bee. 45 | func (factory *IpifyBeeFactory) ID() string { 46 | return "ipify" 47 | } 48 | 49 | // Name returns the name of this Bee. 50 | func (factory *IpifyBeeFactory) Name() string { 51 | return "ipify" 52 | } 53 | 54 | // Description returns the description of this Bee. 55 | func (factory *IpifyBeeFactory) Description() string { 56 | return "Monitor your public IP address via ipify.org and notify when the IP changes" 57 | } 58 | 59 | // Image returns the asset name of this Bee (in the assets/bees folder) 60 | func (factory *IpifyBeeFactory) Image() string { 61 | return factory.Name() + ".png" 62 | } 63 | 64 | // Events describes the available events provided by this Bee. 65 | func (factory *IpifyBeeFactory) Events() []bees.EventDescriptor { 66 | events := []bees.EventDescriptor{ 67 | { 68 | Namespace: factory.Name(), 69 | Name: "ip", 70 | Description: "The public IP retrieved from ipify.org", 71 | Options: []bees.PlaceholderDescriptor{ 72 | { 73 | Name: "ip", 74 | Description: "IP address string", 75 | Type: "string", 76 | }, 77 | }, 78 | }, 79 | } 80 | return events 81 | } 82 | 83 | // Options returns the options available to configure this Bee. 84 | func (factory *IpifyBeeFactory) Options() []bees.BeeOptionDescriptor { 85 | opts := []bees.BeeOptionDescriptor{ 86 | { 87 | Name: "interval", 88 | Description: "Interval in minutes to query ipify.org (60 minutes by default)", 89 | Type: "int", 90 | Default: defaultUpdateInterval, 91 | Mandatory: false, 92 | }, 93 | } 94 | return opts 95 | } 96 | 97 | func init() { 98 | f := IpifyBeeFactory{} 99 | bees.RegisterFactory(&f) 100 | } 101 | -------------------------------------------------------------------------------- /bees/ircbee/irctools/irctools.go: -------------------------------------------------------------------------------- 1 | // Package irctools is a collection of convenient IRC styling methods. 2 | package irctools 3 | 4 | /* 5 | func PostTobeehive(host string, channel string, val string) { 6 | addr, err := net.ResolveTCPAddr("tcp", host) 7 | if err != nil { 8 | fmt.Println("Error:", err) 9 | return 10 | } 11 | 12 | conn, err := net.DialTCP("tcp", nil, addr) 13 | if err != nil { 14 | fmt.Println("Error:", err) 15 | return 16 | } 17 | defer conn.Close() 18 | 19 | if len(channel) > 0 { 20 | val = channel + " " + val 21 | } 22 | _, err = conn.Write([]byte(val)) 23 | if err != nil { 24 | fmt.Println("Error:", err) 25 | return 26 | } 27 | 28 | _, err = conn.Write([]byte("\n")) 29 | } 30 | */ 31 | 32 | // Bold wraps val in bold styling tags. 33 | func Bold(val string) string { 34 | return "\x02" + val + "\x02" 35 | } 36 | 37 | // Colored wraps val in color styling tags. 38 | func Colored(val string, color string) string { 39 | // 00 white 01 black 02 blue (navy) 03 green 04 red 05 brown (maroon) 40 | // 06 purple 07 orange (olive) 08 yellow 09 light green (lime) 41 | // 10 teal (a green/blue cyan) 11 light cyan (cyan) (aqua) 12 light blue (royal) 42 | // 13 pink (light purple) (fuchsia) 14 grey 15 light grey (silver) 43 | c := "01" 44 | switch color { 45 | case "white": 46 | c = "00" 47 | case "black": 48 | c = "01" 49 | case "blue": 50 | c = "02" 51 | case "green": 52 | c = "03" 53 | case "red": 54 | c = "04" 55 | case "brown": 56 | c = "05" 57 | case "purple": 58 | c = "06" 59 | case "orange": 60 | c = "07" 61 | case "yellow": 62 | c = "08" 63 | case "lime": 64 | c = "09" 65 | case "teal": 66 | c = "10" 67 | case "cyan": 68 | c = "11" 69 | case "lightblue": 70 | c = "12" 71 | case "pink": 72 | c = "13" 73 | case "grey": 74 | c = "14" 75 | case "silver": 76 | c = "15" 77 | } 78 | 79 | return "\x03" + c + val + "\x03" 80 | } 81 | -------------------------------------------------------------------------------- /bees/logs.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | import ( 25 | "sort" 26 | "sync" 27 | "time" 28 | ) 29 | 30 | // LogMessage stores a log message with its timestamp, type and originating Bee 31 | type LogMessage struct { 32 | ID string 33 | Bee string 34 | Message string 35 | MessageType uint 36 | Timestamp time.Time 37 | } 38 | 39 | var ( 40 | logs = make(map[string][]LogMessage) 41 | logMutex sync.RWMutex 42 | ) 43 | 44 | // MessageType defines the log level of the log entry we're dealing with 45 | type MessageType uint 46 | 47 | const ( 48 | // LogInfo is for info-level log entries 49 | LogInfo MessageType = iota 50 | 51 | // LogError is for error-level log entries 52 | LogError MessageType = iota 53 | 54 | // LogFatal is for fatal-level log entries 55 | LogFatal MessageType = iota 56 | 57 | // LogDebug is for debug-level log entries 58 | LogDebug MessageType = iota 59 | ) 60 | 61 | // LogSorter is used for sorting an array of LogMessages by their timestamp 62 | type LogSorter []LogMessage 63 | 64 | func (a LogSorter) Len() int { return len(a) } 65 | func (a LogSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 66 | func (a LogSorter) Less(i, j int) bool { return !a[i].Timestamp.Before(a[j].Timestamp) } 67 | 68 | // NewLogMessage returns a newly composed LogMessage 69 | func NewLogMessage(bee string, message string, messageType MessageType) LogMessage { 70 | return LogMessage{ 71 | ID: UUID(), 72 | Bee: bee, 73 | Message: message, 74 | MessageType: uint(messageType), 75 | Timestamp: time.Now(), 76 | } 77 | } 78 | 79 | // Log adds a new LogMessage to the log 80 | func Log(bee string, message string, messageType MessageType) { 81 | logMutex.Lock() 82 | defer logMutex.Unlock() 83 | 84 | logs[bee] = append(logs[bee], NewLogMessage(bee, message, messageType)) 85 | } 86 | 87 | // GetLogs returns all logs for a Bee. 88 | func GetLogs(bee string) []LogMessage { 89 | r := []LogMessage{} 90 | 91 | logMutex.RLock() 92 | for b, ls := range logs { 93 | if len(bee) == 0 || bee == b { 94 | for _, l := range ls { 95 | r = append(r, l) 96 | } 97 | } 98 | } 99 | logMutex.RUnlock() 100 | 101 | sort.Sort(LogSorter(r)) 102 | return r 103 | } 104 | -------------------------------------------------------------------------------- /bees/mastodonbee/README.md: -------------------------------------------------------------------------------- 1 | # Mastodonbee 2 | 3 | You'll need to register and authorize the 'beehive' application in mastodon in order to use the mastodonbee. 4 | 5 | 6 | You can use following code snippet: 7 | 8 | ``` 9 | package main 10 | 11 | import ( 12 | "context" 13 | "fmt" 14 | "log" 15 | 16 | "github.com/mattn/go-mastodon" 17 | ) 18 | 19 | func main() { 20 | app, err := mastodon.RegisterApp(context.Background(), &mastodon.AppConfig{ 21 | Server: "https://server.address", // Enter _your_ server address here 22 | ClientName: "", // Name for the client 23 | Scopes: "read write follow", // Permission scopes 24 | Website: "", // Optional 25 | }) 26 | if err != nil { 27 | log.Fatal(err) 28 | } 29 | // Prints out the ClientID and ClientSecret which you'll need to configure 30 | // beehive propberly 31 | fmt.Printf("client-id : %s\n", app.ClientID) 32 | fmt.Printf("client-secret: %s\n", app.ClientSecret) 33 | } 34 | ``` -------------------------------------------------------------------------------- /bees/notificationbee/notificationbee.go: -------------------------------------------------------------------------------- 1 | // +build dragonfly freebsd linux netbsd openbsd solaris darwin 2 | 3 | /* 4 | * Copyright (C) 2014 Daniel 'grindhold' Brendle 5 | * 2014-2017 Christian Muehlhaeuser 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Affero General Public License as published 9 | * by the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * along with this program. If not, see . 19 | * 20 | * Authors: 21 | * Daniel 'grindhold' Brendle 22 | * Christian Muehlhaeuser 23 | */ 24 | 25 | // Package notificationbee is a Bee that can trigger desktop notifications. 26 | package notificationbee 27 | 28 | import ( 29 | "strings" 30 | 31 | "github.com/muesli/beehive/bees" 32 | ) 33 | 34 | // Urgency level iota 35 | const ( 36 | UrgencyLow = uint32(iota) 37 | UrgencyNormal 38 | UrgencyCritical 39 | ) 40 | 41 | var ( 42 | urgencyMap = map[string]uint32{ 43 | "": UrgencyNormal, 44 | "normal": UrgencyNormal, 45 | "low": UrgencyLow, 46 | "critical": UrgencyCritical, 47 | } 48 | ) 49 | 50 | // NotificationBee is a Bee that can trigger freedesktop.org DBus 51 | // notifications. 52 | type NotificationBee struct { 53 | bees.Bee 54 | } 55 | 56 | // Run executes the Bee's event loop. 57 | func (mod *NotificationBee) Run(cin chan bees.Event) { 58 | select { 59 | case <-mod.SigChan: 60 | return 61 | } 62 | } 63 | 64 | // Action triggers the action passed to it. 65 | func (mod *NotificationBee) Action(action bees.Action) []bees.Placeholder { 66 | outs := []bees.Placeholder{} 67 | 68 | switch action.Name { 69 | case "notify": 70 | text := "" 71 | u := "" 72 | urgency := UrgencyNormal 73 | 74 | action.Options.Bind("text", &text) 75 | action.Options.Bind("urgency", &u) 76 | text = strings.TrimSpace(text) 77 | urgency, _ = urgencyMap[u] 78 | 79 | if len(text) > 0 { 80 | mod.execAction(text, urgency) 81 | } 82 | 83 | default: 84 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 85 | } 86 | return outs 87 | } 88 | 89 | // ReloadOptions parses the config options and initializes the Bee. 90 | func (mod *NotificationBee) ReloadOptions(options bees.BeeOptions) { 91 | mod.SetOptions(options) 92 | } 93 | -------------------------------------------------------------------------------- /bees/notificationbee/notificationbee_osx.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | /* 4 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | // Package notificationbee is a Bee that can trigger desktop notifications. 24 | package notificationbee 25 | 26 | import "github.com/deckarep/gosx-notifier" 27 | 28 | // Run executes the Bee's event loop. 29 | func (mod *NotificationBee) execAction(text string, urgency uint32) { 30 | note := gosxnotifier.NewNotification("Beehive") 31 | note.Title = text 32 | note.Push() 33 | } 34 | -------------------------------------------------------------------------------- /bees/notificationbee/notificationbee_unix.go: -------------------------------------------------------------------------------- 1 | // +build dragonfly freebsd linux netbsd openbsd solaris 2 | 3 | /* 4 | * Copyright (C) 2014 Daniel 'grindhold' Brendle 5 | * 2014-2017 Christian Muehlhaeuser 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU Affero General Public License as published 9 | * by the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU Affero General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU Affero General Public License 18 | * along with this program. If not, see . 19 | * 20 | * Authors: 21 | * Daniel 'grindhold' Brendle 22 | * Christian Muehlhaeuser 23 | */ 24 | 25 | // Package notificationbee is a Bee that can trigger desktop notifications. 26 | package notificationbee 27 | 28 | import ( 29 | "fmt" 30 | 31 | dbus "github.com/guelfey/go.dbus" 32 | ) 33 | 34 | // Run executes the Bee's event loop. 35 | func (mod *NotificationBee) execAction(text string, urgency uint32) { 36 | conn, err := dbus.SessionBus() 37 | if err != nil { 38 | panic(err) 39 | } 40 | 41 | notifier := conn.Object("org.freedesktop.Notifications", "/org/freedesktop/Notifications") 42 | call := notifier.Call("org.freedesktop.Notifications.Notify", 0, "", uint32(0), 43 | "", "Beehive", text, []string{}, 44 | map[string]dbus.Variant{"urgency": dbus.MakeVariant(urgency)}, int32(5000)) 45 | 46 | if call.Err != nil { 47 | mod.Logln("(" + fmt.Sprint(urgency) + ") Failed to print message: " + text) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /bees/openweathermapbee/README.md: -------------------------------------------------------------------------------- 1 | # Openweathermapbee 2 | 3 | ## Available languages 4 | English - en, Russian - ru, Italian - it, Spanish - es (or sp), Ukrainian - uk (or ua), German - de, Portuguese - pt, Romanian - ro, Polish - pl, Finnish - fi, Dutch - nl, French - fr, Bulgarian - bg, Swedish - sv (or se), Chinese Traditional - zh_tw, Chinese Simplified - zh (or zh_cn), Turkish - tr, Croatian - hr, Catalan - ca 5 | 6 | ## Multiple Measurement Systems Available 7 | Fahrenheit (OpenWeatherMap API - imperial) 8 | Celcius (OpenWeatherMap API - metric) 9 | Kelvin (OpenWeatherMap API - internal) 10 | 11 | --- 12 | 13 | To use the OpenweatherMap API, you'll need to obtain an API key. Sign up [here](https://home.openweathermap.org/users/sign_up). 14 | -------------------------------------------------------------------------------- /bees/openweathermapbee/openweathermapbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | * Nicolas Martin 20 | */ 21 | 22 | // Package openweathermapbee is a Bee that can interact with cleverbot 23 | package openweathermapbee 24 | 25 | import ( 26 | "github.com/muesli/beehive/bees" 27 | 28 | owm "github.com/briandowns/openweathermap" 29 | ) 30 | 31 | // OpenweathermapBee is a Bee that can chat with cleverbot 32 | type OpenweathermapBee struct { 33 | bees.Bee 34 | 35 | current *owm.CurrentWeatherData 36 | 37 | unit string 38 | language string 39 | key string 40 | 41 | evchan chan bees.Event 42 | } 43 | 44 | // Action triggers the action passed to it. 45 | func (mod *OpenweathermapBee) Action(action bees.Action) []bees.Placeholder { 46 | outs := []bees.Placeholder{} 47 | 48 | switch action.Name { 49 | case "get_current_weather": 50 | var location string 51 | action.Options.Bind("location", &location) 52 | 53 | err := mod.current.CurrentByName(location) 54 | if err != nil { 55 | mod.LogErrorf("Failed to fetch weather: %v", err) 56 | return nil 57 | } 58 | 59 | mod.TriggerCurrentWeatherEvent() 60 | 61 | default: 62 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 63 | } 64 | 65 | return outs 66 | } 67 | 68 | // Run executes the Bee's event loop. 69 | func (mod *OpenweathermapBee) Run(eventChan chan bees.Event) { 70 | mod.evchan = eventChan 71 | 72 | current, err := owm.NewCurrent(mod.unit, mod.language, mod.key) 73 | if err != nil { 74 | mod.LogErrorf("Failed to create new current service: %v", err) 75 | return 76 | } 77 | mod.current = current 78 | 79 | select { 80 | case <-mod.SigChan: 81 | return 82 | } 83 | } 84 | 85 | // ReloadOptions parses the config options and initializes the Bee. 86 | func (mod *OpenweathermapBee) ReloadOptions(options bees.BeeOptions) { 87 | mod.SetOptions(options) 88 | 89 | options.Bind("unit", &mod.unit) 90 | options.Bind("language", &mod.language) 91 | options.Bind("key", &mod.key) 92 | } 93 | -------------------------------------------------------------------------------- /bees/options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package bees is Beehive's central module system. 22 | package bees 23 | 24 | import "errors" 25 | 26 | // A FilterOption used by filters. 27 | type FilterOption struct { 28 | Name string 29 | Type string 30 | Inverse bool 31 | CaseInsensitive bool 32 | Trimmed bool 33 | Value interface{} 34 | } 35 | 36 | // BeeOptions is an array of BeeOption. 37 | type BeeOptions []BeeOption 38 | 39 | // A BeeOption is used to configure bees. 40 | type BeeOption struct { 41 | Name string 42 | Value interface{} 43 | } 44 | 45 | // Value retrieves a value from a BeeOptions slice. 46 | func (opts BeeOptions) Value(name string) interface{} { 47 | for _, opt := range opts { 48 | if opt.Name == name { 49 | return opt.Value 50 | } 51 | } 52 | 53 | return nil 54 | } 55 | 56 | // Bind a value from a BeeOptions slice. 57 | func (opts BeeOptions) Bind(name string, dst interface{}) error { 58 | v := opts.Value(name) 59 | if v == nil { 60 | return errors.New("Option with name " + name + " not found") 61 | } 62 | 63 | return ConvertValue(v, dst) 64 | } 65 | -------------------------------------------------------------------------------- /bees/pastebinbee/README.md: -------------------------------------------------------------------------------- 1 | # Pastebinbee 2 | 3 | This bee can post some text on pastebin as an action to some event. 4 | 5 | You can get your **api developer key** from: http://pastebin.com/api 6 | 7 | ## Configuration 8 | 9 | Due to admin interface limitations here are available options 10 | for exposure and expiration of the paste: 11 | * exposure: 12 | * 0 - Public 13 | * 1 - Unlisted 14 | * 2 - Private 15 | * expire: 16 | * N - Never 17 | * 10M - 10 minutes 18 | * 1H - 1 hour 19 | * 1D - 1 day 20 | * 1W - 1 week 21 | * 2W - 2 weeks 22 | * 1M - 1 month 23 | 24 | ### Options 25 | ```json 26 | "Bees": [ 27 | { 28 | "Name": "Pastebin example", 29 | "Class": "pastebinbee", 30 | "Description": "This is example of pastebinbee", 31 | "Options": [ 32 | { 33 | "Name": "api_dev_key", 34 | "Value": "API_DEVELOPER_KEY" 35 | } 36 | ] 37 | }, 38 | ] 39 | ``` 40 | 41 | ### Actions 42 | 43 | ```json 44 | "Actions": [ 45 | { 46 | "Bee": "Paste", 47 | "Name": "post", 48 | "Options": [ 49 | { 50 | "Name": "title", 51 | "Type": "string", 52 | "Value": "beehive" 53 | }, 54 | { 55 | "Name": "content", 56 | "Type": "string", 57 | "Value": "testing beehive passed!" 58 | }, 59 | { 60 | "Name": "expire", 61 | "Type": "string", 62 | "Value": "1H" 63 | }, 64 | { 65 | "Name": "exposure", 66 | "Type": "string", 67 | "Value": "2" 68 | } 69 | ] 70 | }, 71 | ] 72 | ``` 73 | -------------------------------------------------------------------------------- /bees/pastebinbee/pastebinbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Sebastian Ławniczak 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sebastian Ławniczak 19 | */ 20 | 21 | // Package pastebinbee is a Bee that can interface with Pastebin. 22 | package pastebinbee 23 | 24 | import ( 25 | pastebin "github.com/glaxx/go_pastebin" 26 | "github.com/muesli/beehive/bees" 27 | ) 28 | 29 | // PastebinBee is a Bee that can interface with Pastebin. 30 | type PastebinBee struct { 31 | bees.Bee 32 | 33 | client pastebin.Pastebin 34 | apiDevKey string 35 | } 36 | 37 | // Action triggers the action passed to it. 38 | func (mod *PastebinBee) Action(action bees.Action) []bees.Placeholder { 39 | outs := []bees.Placeholder{} 40 | 41 | switch action.Name { 42 | case "post": 43 | title := "" 44 | content := "" 45 | expire := "" 46 | exposure := "" 47 | 48 | action.Options.Bind("title", &title) 49 | action.Options.Bind("content", &content) 50 | action.Options.Bind("expire", &expire) 51 | action.Options.Bind("exposure", &exposure) 52 | 53 | ret, err := mod.client.PasteAnonymous(content, title, "text", expire, exposure) 54 | if err != nil { 55 | mod.LogErrorf("Error occurred during posting to Pastebin: %v", err) 56 | } else { 57 | mod.Logln("Paste URL:", ret) 58 | } 59 | 60 | default: 61 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 62 | } 63 | return outs 64 | } 65 | 66 | // Run executes the Bee's event loop. 67 | func (mod *PastebinBee) Run(eventChan chan bees.Event) { 68 | mod.client = pastebin.NewPastebin(mod.apiDevKey) 69 | } 70 | 71 | // ReloadOptions parses the config options and initializes the Bee. 72 | func (mod *PastebinBee) ReloadOptions(options bees.BeeOptions) { 73 | mod.SetOptions(options) 74 | 75 | options.Bind("api_dev_key", &mod.apiDevKey) 76 | } 77 | -------------------------------------------------------------------------------- /bees/pushoverbee/pushoverbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Raphael Mutschler 19 | */ 20 | 21 | // Package pushoverbee is a Bee that can send pushover notifications. 22 | package pushoverbee 23 | 24 | import ( 25 | "net/http" 26 | "net/url" 27 | 28 | "github.com/muesli/beehive/bees" 29 | ) 30 | 31 | // PushoverBee is a Bee that sends Pushover notifications 32 | type PushoverBee struct { 33 | bees.Bee 34 | 35 | token string 36 | userToken string 37 | } 38 | 39 | // Run executes the Bee's event loop. 40 | func (mod *PushoverBee) Run(cin chan bees.Event) { 41 | select { 42 | case <-mod.SigChan: 43 | return 44 | } 45 | } 46 | 47 | // Action triggers the action passed to it. 48 | func (mod *PushoverBee) Action(action bees.Action) []bees.Placeholder { 49 | outs := []bees.Placeholder{} 50 | 51 | switch action.Name { 52 | case "send": 53 | var message, title, nurl, urlTitle string 54 | action.Options.Bind("message", &message) 55 | action.Options.Bind("title", &title) 56 | action.Options.Bind("url", &nurl) 57 | action.Options.Bind("url_title", &urlTitle) 58 | 59 | msg := url.Values{} 60 | msg.Set("token", mod.token) 61 | msg.Set("user", mod.userToken) 62 | msg.Set("message", message) 63 | 64 | if nurl != "" { 65 | msg.Set("url", nurl) 66 | } 67 | if urlTitle != "" { 68 | msg.Set("url_title", urlTitle) 69 | } 70 | if title != "" { 71 | msg.Set("title", title) 72 | } 73 | 74 | mod.LogDebugf("Message: %s", msg) 75 | resp, err := http.PostForm("https://api.pushover.net/1/messages.json", msg) 76 | if err != nil { 77 | panic(err) 78 | } 79 | defer resp.Body.Close() 80 | if resp.StatusCode == 200 { 81 | mod.LogDebugf("Pushover send message success.") 82 | } 83 | 84 | default: 85 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 86 | } 87 | 88 | return outs 89 | } 90 | 91 | // ReloadOptions parses the config options and initializes the Bee. 92 | func (mod *PushoverBee) ReloadOptions(options bees.BeeOptions) { 93 | mod.SetOptions(options) 94 | options.Bind("token", &mod.token) 95 | options.Bind("user_token", &mod.userToken) 96 | } 97 | -------------------------------------------------------------------------------- /bees/redisbee/README.md: -------------------------------------------------------------------------------- 1 | # Redis bee 2 | 3 | Store arbitrary key/value strings in a Redis server. 4 | 5 | ## Configuration 6 | 7 | * host: Redis host (defaults to localhost) 8 | * port: Redis port (defaults to 6379) 9 | * password: Redis server password (defaults to passwordless auth) 10 | * db: Redis database to use (defaults to 0) 11 | * channel: Redis channel to subscribe to (pubsub disabled if not specified) 12 | 13 | ## Ideas 14 | 15 | * Use it in combination with the ipify hive to store your public IP history 16 | * Store URLs sent via POST to the HTTP server hive 17 | * Store all messages received in a Slack channel using the Slack hive 18 | 19 | See [beehive-youtube-dl](https://github.com/rubiojr/beehive-youtube-dl), a sample project that combines multiple hives, including this one. 20 | 21 | ## Credits 22 | 23 | [Redis Icon](https://iconscout.com/icon/redis-4) by Icon Mafia on [Iconscout]](https://iconscout.com) 24 | -------------------------------------------------------------------------------- /bees/rocketchatbee/README.md: -------------------------------------------------------------------------------- 1 | # Rocket.chat bee 2 | 3 | The [Rocket.Chat](https://rocket.chat/) bee can send messages into a Rocket.Chat channel. 4 | 5 | ## Configuration 6 | 7 | ### Options 8 | 9 | ```json 10 | "Bees":[ 11 | { 12 | "Name":"rocketchatmsg", 13 | "Class":"rocketchatbee", 14 | "Description":"my rocket.chat bee", 15 | "Options":[ 16 | { 17 | "Name":"url", 18 | "Value":"http://localhost:3000" 19 | }, 20 | { 21 | "Name":"user_id", 22 | "Value":"YOUR_USER_ID" 23 | }, 24 | { 25 | "Name":"auth_token", 26 | "Value":"YOUR_AUTH_TOKEN" 27 | } 28 | ] 29 | } 30 | ] 31 | ``` 32 | 33 | See https://rocket.chat/docs/developer-guides/rest-api/personal-access-tokens/ for reference on how to create a `user_id` and `auth_token`. 34 | 35 | ### Actions 36 | 37 | **send**: send a message to a Rocket.Chat channel. This needs the name of the `channel`, and the `text` to send. If you specify an `alias`, messages posted appear under that username. 38 | 39 | ```json 40 | "Elements":[ 41 | { 42 | "Action":{ 43 | "Bee":"rocketchatmsg", 44 | "Name":"send", 45 | "Options":[ 46 | { 47 | "Name":"channel", 48 | "Value":"info" 49 | }, 50 | { 51 | "Name":"text", 52 | "Value":"This is the latest info!" 53 | }, 54 | { 55 | "Name":"alias", 56 | "Value":"Informer" 57 | } 58 | ] 59 | ] 60 | } 61 | } 62 | ] 63 | ``` 64 | -------------------------------------------------------------------------------- /bees/rocketchatbee/rocketchatbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Sergio Rubio 3 | * 2017 Christian Muehlhaeuser 4 | * 2019 David Schneider 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Sergio Rubio 21 | * Christian Muehlhaeuser 22 | * David Schneider 23 | */ 24 | 25 | // Package rocketchatbee is a Bee that can connect to Rocketchat. 26 | package rocketchatbee 27 | 28 | import ( 29 | "github.com/muesli/beehive/bees" 30 | ) 31 | 32 | // RocketchatBee is a Bee that can connect to Rocketchat. 33 | type RocketchatBee struct { 34 | bees.Bee 35 | 36 | client *Client 37 | } 38 | 39 | // Action triggers the action passed to it. 40 | func (mod *RocketchatBee) Action(action bees.Action) []bees.Placeholder { 41 | outs := []bees.Placeholder{} 42 | 43 | switch action.Name { 44 | case "send": 45 | var ( 46 | text string 47 | channel string 48 | alias string 49 | ) 50 | 51 | action.Options.Bind("text", &text) 52 | action.Options.Bind("channel", &channel) 53 | action.Options.Bind("alias", &alias) 54 | 55 | err := mod.client.SendMessage(channel, text, alias) 56 | if err != nil { 57 | mod.LogErrorf("Failed to send message: %s", err) 58 | return outs 59 | } 60 | 61 | default: 62 | mod.LogErrorf("Unknown action triggered in " + mod.Name() + ": " + action.Name) 63 | } 64 | 65 | return outs 66 | } 67 | 68 | // ReloadOptions parses the config options and initializes the Bee. 69 | func (mod *RocketchatBee) ReloadOptions(options bees.BeeOptions) { 70 | var ( 71 | url string 72 | userID string 73 | authToken string 74 | ) 75 | 76 | mod.SetOptions(options) 77 | 78 | options.Bind("url", &url) 79 | options.Bind("user_id", &userID) 80 | options.Bind("auth_token", &authToken) 81 | 82 | mod.client = NewClient(url, userID, authToken) 83 | 84 | err := mod.client.TestConnection() 85 | if err != nil { 86 | mod.LogErrorf("Connection to Rocket.Chat failed: %s", err) 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /bees/s3bee/README.md: -------------------------------------------------------------------------------- 1 | # S3 Bee 2 | 3 | Uploads files to S3 compatible storage: 4 | 5 | * AWS Signature Version 4 6 | * Amazon S3 7 | * Minio 8 | 9 | * AWS Signature Version 2 10 | * Google Cloud Storage (Compatibility Mode) 11 | * Openstack Swift + Swift3 middleware 12 | * Ceph Object Gateway 13 | * Riak CS 14 | 15 | See https://github.com/minio/minio-go 16 | 17 | ## Configuration 18 | 19 | * endpoint: S3 host (Path to monitor (file or directory). 20 | * access_key_id: S3 access key. Prefix the value with `env://` to retrieve the key from the environment. 21 | Example: `env://AWS_ACCESS_KEY_ID` or `ASDFWERSDF123WERF` 22 | * secret_access_key: S3 secret access key. Prefix the value with `env://` to retrieve the key from the environment. 23 | Example: `env://AWS_SECRET_ACCESS_KEY` or `vASiudxSHReo4elkajsdklfu827389234sdfsdf` 24 | * use_ssl: Defaults to `true`. 25 | * region: AWS region. Defaults to `us-east-1`. 26 | 27 | ## Actions 28 | 29 | **upload** 30 | 31 | * bucket: target bucket to upload the file. 32 | * path: Source file path. 33 | * object_path: Destination file path. Defaults to the source file name. 34 | 35 | ## Credits 36 | 37 | AWS logo: https://hu.wikipedia.org/wiki/Amazon_S3#/media/File:AWS_Simple_Icons_AWS_Cloud.svg 38 | -------------------------------------------------------------------------------- /bees/s3bee/s3bee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package s3bee 22 | 23 | import ( 24 | "mime" 25 | "os" 26 | "path/filepath" 27 | "strings" 28 | 29 | "github.com/minio/minio-go" 30 | "github.com/muesli/beehive/bees" 31 | ) 32 | 33 | type S3Bee struct { 34 | bees.Bee 35 | client *minio.Client 36 | } 37 | 38 | // Action triggers the action passed to it. 39 | func (bee *S3Bee) Action(action bees.Action) []bees.Placeholder { 40 | outs := []bees.Placeholder{} 41 | 42 | switch action.Name { 43 | case "upload": 44 | bucket := "" 45 | action.Options.Bind("bucket", &bucket) 46 | 47 | path := "" 48 | action.Options.Bind("path", &path) 49 | 50 | objectPath := "" 51 | action.Options.Bind("object_path", &objectPath) 52 | 53 | if objectPath == "" { 54 | objectPath = filepath.Base(path) 55 | } 56 | 57 | _, err := bee.client.FPutObject(bucket, objectPath, path, minio.PutObjectOptions{ContentType: mime.TypeByExtension(filepath.Ext(path))}) 58 | if err != nil { 59 | bee.LogFatal(err) 60 | } 61 | default: 62 | panic("Unknown action triggered in " + bee.Name() + ": " + action.Name) 63 | } 64 | 65 | return outs 66 | } 67 | 68 | func (bee *S3Bee) ReloadOptions(options bees.BeeOptions) { 69 | bee.SetOptions(options) 70 | 71 | endpoint := getConfigValue("endpoint", &options) 72 | 73 | var useSSL bool 74 | options.Bind("use_ssl", &useSSL) 75 | 76 | accessKeyID := getConfigValue("access_key_id", &options) 77 | secretAccessKey := getConfigValue("secret_access_key", &options) 78 | 79 | client, err := minio.New(endpoint, accessKeyID, secretAccessKey, useSSL) 80 | if err != nil { 81 | panic(err) 82 | return 83 | } 84 | 85 | bee.client = client 86 | } 87 | 88 | func getConfigValue(key string, options *bees.BeeOptions) string { 89 | var value string 90 | options.Bind(key, &value) 91 | 92 | if strings.HasPrefix(value, "env://") { 93 | buf := strings.TrimPrefix(value, "env://") 94 | value = os.Getenv(string(buf)) 95 | } 96 | 97 | return strings.TrimSpace(value) 98 | } 99 | -------------------------------------------------------------------------------- /bees/simplepushbee/simplepushbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Timm Schäuble 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Timm Schäuble 19 | */ 20 | 21 | // Package simplepushbee is a Bee that is able to send push notifications to Android. 22 | package simplepushbee 23 | 24 | import ( 25 | "github.com/muesli/beehive/bees" 26 | "github.com/simplepush/simplepush-go" 27 | ) 28 | 29 | // SimplepushBee is a Bee that is able to send push notifications to Android. 30 | type SimplepushBee struct { 31 | bees.Bee 32 | 33 | key string 34 | password string 35 | salt string 36 | } 37 | 38 | // Action triggers the action passed to it. 39 | func (mod *SimplepushBee) Action(action bees.Action) []bees.Placeholder { 40 | outs := []bees.Placeholder{} 41 | 42 | switch action.Name { 43 | case "send": 44 | sm := simplepush.Message{ 45 | SimplePushKey: mod.key, 46 | Encrypt: mod.password != "", 47 | Password: mod.password, 48 | Salt: mod.salt, 49 | } 50 | action.Options.Bind("title", &sm.Title) 51 | action.Options.Bind("message", &sm.Message) 52 | action.Options.Bind("event", &sm.Event) 53 | 54 | simplepush.Send(sm) 55 | 56 | default: 57 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 58 | } 59 | 60 | return outs 61 | } 62 | 63 | // ReloadOptions parses the config options and initializes the Bee. 64 | func (mod *SimplepushBee) ReloadOptions(options bees.BeeOptions) { 65 | mod.SetOptions(options) 66 | 67 | options.Bind("key", &mod.key) 68 | options.Bind("password", &mod.password) 69 | options.Bind("salt", &mod.salt) 70 | } 71 | -------------------------------------------------------------------------------- /bees/slackbee/README.md: -------------------------------------------------------------------------------- 1 | # Slack bee 2 | 3 | The [Slack](https://slack.com) bee can send and listen to messages in a Slack channel. 4 | 5 | ## Configuration 6 | 7 | ### Options 8 | 9 | ```json 10 | "Bees":[ 11 | { 12 | "Name":"slackmsg", 13 | "Class":"slackbee", 14 | "Description":"slackbee", 15 | "Options":[ 16 | { 17 | "Name":"apiKey", 18 | "Value":"env://SLACK_KEY" 19 | }, 20 | { 21 | "Name":"channels", 22 | "Value":["rubiojr-test"] 23 | } 24 | ] 25 | } 26 | ] 27 | ``` 28 | 29 | **apiKey**: Slack API Key. You can get one from https://api.slack.com/docs/oauth-test-tokens. 30 | 31 | The API key can be added to the recipe/config as-is, via environment variable (`env://MY_API_KEY`) or read from a file (`file:///Users/rubiojr/.slack_key`). 32 | 33 | **channels**: The slack channels to listen on. 34 | 35 | ### Actions 36 | 37 | **send**: send a message to a Slack channel. Needs the name of the channel (not the channel ID), and the text to send. You can use interpolation to send something from the event received: 38 | 39 | ```json 40 | "Elements":[ 41 | { 42 | "Action":{ 43 | "Bee":"slackmsg", 44 | "Name":"send", 45 | "Options":[ 46 | { 47 | "Name":"channel", 48 | "Value":"rubiojr-test2" 49 | }, 50 | { 51 | "Name":"text", 52 | "Value":"{{.something}}" 53 | } 54 | ] 55 | } 56 | } 57 | ] 58 | ``` 59 | 60 | ## Credits 61 | 62 | Slack logo: https://remoteworkspain.slack.com/brand-guidelines 63 | -------------------------------------------------------------------------------- /bees/socketbee/socketbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package socketbee is a Bee that lets you transmit data via UDP sockets. 22 | package socketbee 23 | 24 | import ( 25 | "log" 26 | "net" 27 | "strconv" 28 | 29 | "github.com/muesli/beehive/bees" 30 | ) 31 | 32 | // SocketBee is a Bee that lets you transmit data via UDP sockets. 33 | type SocketBee struct { 34 | bees.Bee 35 | 36 | eventChan chan bees.Event 37 | } 38 | 39 | // Run executes the Bee's event loop. 40 | func (mod *SocketBee) Run(cin chan bees.Event) { 41 | mod.eventChan = cin 42 | 43 | select { 44 | case <-mod.SigChan: 45 | return 46 | } 47 | } 48 | 49 | // Action triggers the action passed to it. 50 | func (mod *SocketBee) Action(action bees.Action) []bees.Placeholder { 51 | outs := []bees.Placeholder{} 52 | 53 | var data string 54 | var addr string 55 | var port int 56 | 57 | action.Options.Bind("address", &addr) 58 | action.Options.Bind("port", &port) 59 | action.Options.Bind("data", &data) 60 | 61 | switch action.Name { 62 | case "send": 63 | // log.Println("Sending", data, "to", addr, port) 64 | 65 | sa, err := net.ResolveUDPAddr("udp", addr+":"+strconv.Itoa(port)) 66 | if err != nil { 67 | log.Panicln(err) 68 | } 69 | 70 | conn, err := net.DialUDP("udp", nil, sa) 71 | if err != nil { 72 | log.Panicln(err) 73 | } 74 | 75 | defer conn.Close() 76 | _, err = conn.Write([]byte(data)) 77 | if err != nil { 78 | log.Panicln(err) 79 | } 80 | 81 | default: 82 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 83 | } 84 | 85 | return outs 86 | } 87 | 88 | // ReloadOptions parses the config options and initializes the Bee. 89 | func (mod *SocketBee) ReloadOptions(options bees.BeeOptions) { 90 | mod.SetOptions(options) 91 | } 92 | -------------------------------------------------------------------------------- /bees/spaceapibee/spaceapibee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | * Johannes Fürmann 20 | */ 21 | 22 | // Package spaceapibee is a Bee that can query a spaceapi server. 23 | package spaceapibee 24 | 25 | import ( 26 | "encoding/json" 27 | "io/ioutil" 28 | "net/http" 29 | 30 | "github.com/muesli/beehive/bees" 31 | ) 32 | 33 | // SpaceAPIBee is a Bee that can query a spaceapi server. 34 | type SpaceAPIBee struct { 35 | bees.Bee 36 | 37 | url string 38 | 39 | evchan chan bees.Event 40 | } 41 | 42 | // Action triggers the action passed to it. 43 | func (mod *SpaceAPIBee) Action(action bees.Action) []bees.Placeholder { 44 | outs := []bees.Placeholder{} 45 | 46 | switch action.Name { 47 | case "status": 48 | type SpaceAPIResult struct { 49 | State struct { 50 | Open bool `json:"open"` 51 | } `json:"state"` 52 | } 53 | apiState := new(SpaceAPIResult) 54 | 55 | // get json data 56 | resp, err := http.Get(mod.url) 57 | if err != nil { 58 | mod.Logln("Error: SpaceAPI instance @ " + mod.url + " not reachable") 59 | } else { 60 | defer resp.Body.Close() 61 | body, _ := ioutil.ReadAll(resp.Body) 62 | 63 | err = json.Unmarshal(body, apiState) 64 | if err != nil { 65 | mod.Logln("Sorry, couldn't unmarshal the JSON data from SpaceAPI Instance @ " + mod.url) 66 | apiState.State.Open = false 67 | } 68 | } 69 | 70 | ev := bees.Event{ 71 | Bee: mod.Name(), 72 | Name: "result", 73 | Options: []bees.Placeholder{ 74 | { 75 | Name: "open", 76 | Type: "bool", 77 | Value: apiState.State.Open, 78 | }, 79 | }, 80 | } 81 | mod.evchan <- ev 82 | 83 | default: 84 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 85 | } 86 | 87 | return outs 88 | } 89 | 90 | // Run executes the Bee's event loop. 91 | func (mod *SpaceAPIBee) Run(eventChan chan bees.Event) { 92 | mod.evchan = eventChan 93 | } 94 | 95 | // ReloadOptions parses the config options and initializes the Bee. 96 | func (mod *SpaceAPIBee) ReloadOptions(options bees.BeeOptions) { 97 | mod.SetOptions(options) 98 | 99 | options.Bind("url", &mod.url) 100 | } 101 | -------------------------------------------------------------------------------- /bees/sunbee/README.md: -------------------------------------------------------------------------------- 1 | # Sunrise/Sunset Bee 2 | 3 | Sends an event when the Sun raises or goes down. 4 | 5 | ## Configuration 6 | 7 | * query: the city that should match the sunrise/sunset event. The query is sent to https://nominatim.openstreetmap.org so your query 8 | should return the latitude, longitude for a valid place. 9 | * offset: the number of seconds to alert before the event happens. Defaults to 2 minutes. 10 | 11 | ## Credits 12 | 13 | Logo: Icon Lauk https://www.iconfinder.com/icons/3859148/forecast_sun_sunrise_sunset_weather_icon 14 | -------------------------------------------------------------------------------- /bees/sunbee/sunbeefactory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Sergio Rubio 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Sergio Rubio 19 | */ 20 | 21 | package sunbee 22 | 23 | import ( 24 | "github.com/muesli/beehive/bees" 25 | ) 26 | 27 | // SunBeeFactory is a factory for SunBees. 28 | type SunBeeFactory struct { 29 | bees.BeeFactory 30 | } 31 | 32 | // New returns a new Bee instance configured with the supplied options. 33 | func (factory *SunBeeFactory) New(name, description string, options bees.BeeOptions) bees.BeeInterface { 34 | bee := SunBee{ 35 | Bee: bees.NewBee(name, factory.ID(), description, options), 36 | } 37 | bee.ReloadOptions(options) 38 | 39 | return &bee 40 | } 41 | 42 | // ID returns the ID of this Bee. 43 | func (factory *SunBeeFactory) ID() string { 44 | return "sunbee" 45 | } 46 | 47 | // Name returns the name of this Bee. 48 | func (factory *SunBeeFactory) Name() string { 49 | return "Sunset/Sunrise" 50 | } 51 | 52 | // Description returns the description of this Bee. 53 | func (factory *SunBeeFactory) Description() string { 54 | return "Send an event when the Sun raises or goes down" 55 | } 56 | 57 | // Image returns the filename of an image for this Bee. 58 | func (factory *SunBeeFactory) Image() string { 59 | return factory.ID() + ".png" 60 | } 61 | 62 | // Options returns the options available to configure this Bee. 63 | func (factory *SunBeeFactory) Options() []bees.BeeOptionDescriptor { 64 | opts := []bees.BeeOptionDescriptor{ 65 | { 66 | Name: "query", 67 | Description: "The name of the city where the sunrise/sunset will happen", 68 | Type: "string", 69 | Mandatory: true, 70 | }, 71 | { 72 | Name: "offset", 73 | Description: "Fire the event this number of seconds before sunset/sunrise", 74 | Type: "int", 75 | Default: 0, 76 | Mandatory: false, 77 | }, 78 | } 79 | return opts 80 | } 81 | 82 | func (factory *SunBeeFactory) Events() []bees.EventDescriptor { 83 | events := []bees.EventDescriptor{ 84 | { 85 | Namespace: factory.Name(), 86 | Name: "sunrise", 87 | Description: "Sunrise is happening", 88 | Options: []bees.PlaceholderDescriptor{}, 89 | }, 90 | { 91 | Namespace: factory.Name(), 92 | Name: "sunset", 93 | Description: "Sunset is happening", 94 | Options: []bees.PlaceholderDescriptor{}, 95 | }, 96 | } 97 | return events 98 | } 99 | 100 | func init() { 101 | f := SunBeeFactory{} 102 | bees.RegisterFactory(&f) 103 | } 104 | -------------------------------------------------------------------------------- /bees/telegrambee/README.md: -------------------------------------------------------------------------------- 1 | # Telegram Bees 2 | 3 | [Telegram](https://telegram.org) bot that sends and receives messages to/from Telegram chats and groups. 4 | 5 | 6 | ## Configuration 7 | 8 | Bee options: 9 | 10 | ```json 11 | "Bees": [{ 12 | "Name": "telegram", 13 | "Class": "telegrambee", 14 | "Description": "Telegram bot bee", 15 | "Options": [{ 16 | "Name": "apiKey", 17 | "Value": "file:///Users/lalotone/.telegramapi" 18 | }] 19 | }] 20 | ``` 21 | 22 | **apiKey**: [Telegram bot](https://core.telegram.org/bots) API Key. Can be added 23 | to the recipe, via environment variable (`env://MY_API_KEY`) or read from a file (`file:///Users/lalotone/.telegram_key`) 24 | 25 | ## Credits 26 | 27 | Telegram image by Telegram Messenger LLP - User:Javitomad, Public Domain, https://commons.wikimedia.org/w/index.php?curid=36861817 28 | -------------------------------------------------------------------------------- /bees/transmissionbee/transmissionbee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Gonzalo Izquierdo 3 | * 2017 Christian Muehlhaeuser 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published 7 | * by the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Authors: 19 | * Gonzalo Izquierdo 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | // Package transmissionbee is a Bee that can send torrents to Transmission. 24 | package transmissionbee 25 | 26 | import ( 27 | "github.com/kr/pretty" 28 | "github.com/odwrtw/transmission" 29 | 30 | "github.com/muesli/beehive/bees" 31 | ) 32 | 33 | // TransmissionBee is a Bee that can send torrents to Transmission. 34 | type TransmissionBee struct { 35 | bees.Bee 36 | 37 | client *transmission.Client 38 | } 39 | 40 | // Action triggers the action passed to it. 41 | func (mod *TransmissionBee) Action(action bees.Action) []bees.Placeholder { 42 | outs := []bees.Placeholder{} 43 | switch action.Name { 44 | case "add_torrent": 45 | torrentMsg := "" 46 | action.Options.Bind("torrent", &torrentMsg) 47 | 48 | _, err := mod.client.Add(torrentMsg) 49 | if err != nil { 50 | mod.LogErrorf("Error adding torrent/magnet: %s", err) 51 | } 52 | } 53 | return outs 54 | } 55 | 56 | // ReloadOptions parses the config options and initializes the Bee. 57 | func (mod *TransmissionBee) ReloadOptions(options bees.BeeOptions) { 58 | mod.SetOptions(options) 59 | 60 | conf := transmission.Config{} 61 | options.Bind("url", &conf.Address) 62 | options.Bind("username", &conf.User) 63 | options.Bind("password", &conf.Password) 64 | 65 | t, err := transmission.New(conf) 66 | if err != nil { 67 | pretty.Println(err) 68 | } 69 | mod.client = t 70 | } 71 | -------------------------------------------------------------------------------- /bees/twiliobee/README.md: -------------------------------------------------------------------------------- 1 | # Twilio bee 2 | 3 | The [Twilio](https://twilio.com) bee can send SMS messages to a phone. 4 | 5 | ## Configuration 6 | 7 | ### Options 8 | 9 | ```json 10 | "Bees": [ 11 | { 12 | "Name":"Twilio Example Bee", 13 | "Class":"twiliobee", 14 | "Description":"A bee to demonstrate Twilio with Beehive", 15 | "Options":[ 16 | { 17 | "Name": "account_sid", 18 | "Value": "YOUR_TWILIO_ACCOUNT_SID" 19 | }, 20 | { 21 | "Name": "auth_token", 22 | "Value": "YOUR_TWILIO_AUTH_TOKEN" 23 | }, 24 | { 25 | "Name": "from_number", 26 | "Value": "+15551234567" 27 | }, 28 | { 29 | "Name": "to_number", 30 | "Value": "+15559876543" 31 | } 32 | ] 33 | } 34 | ] 35 | ``` 36 | 37 | **account_sid** and **auth_token**: Twilio Account SID and Authentication Token. You can sign up and get them from https://www.twilio.com/try-twilio. 38 | 39 | These can be added to the recipe/config as-is (`XXXXXXXX`), via environment variable (`env://MY_ACCOUNT_SID`) or read from a file (`file:///home/james//.twilio_config`). 40 | 41 | **from_number**: Your Twilio phone number. Must be in the format `+15558675309`. 42 | 43 | **to_number**: The phone number to send an SMS message to. 44 | 45 | ### Actions 46 | 47 | **send**: send an SMS message. Needs the body of the message to send. You can use interpolation to send somthing from the event received: 48 | 49 | ```json 50 | "Actions": [ 51 | { 52 | "Bee":"Twilio Example Bee", 53 | "Name":"send", 54 | "Options":[ 55 | { 56 | "Name":"body", 57 | "Value":"Example body with interpolation: {{.something_from_event}}" 58 | } 59 | ] 60 | } 61 | ] 62 | ``` 63 | 64 | ## Credits 65 | 66 | Twilio logo: https://www.twilio.com/press 67 | -------------------------------------------------------------------------------- /bees/twiliobee/twiliobee.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 James Vaughan 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * James Vaughan 19 | */ 20 | 21 | // Package twiliobee is a Bee that is able to send SMS messages. 22 | package twiliobee 23 | 24 | import ( 25 | twilio "github.com/carlosdp/twiliogo" 26 | "github.com/muesli/beehive/bees" 27 | ) 28 | 29 | // TwilioBee is a Bee that is able to send SMS messages. 30 | type TwilioBee struct { 31 | bees.Bee 32 | 33 | client *twilio.TwilioClient 34 | accountsid string 35 | authtoken string 36 | fromNumber string 37 | toNumber string 38 | } 39 | 40 | // Action triggers the action passed to it. 41 | func (mod *TwilioBee) Action(action bees.Action) []bees.Placeholder { 42 | outs := []bees.Placeholder{} 43 | 44 | switch action.Name { 45 | case "send": 46 | body := "" 47 | action.Options.Bind("body", &body) 48 | 49 | _, err := twilio.NewMessage(mod.client, mod.fromNumber, mod.toNumber, twilio.Body(body)) 50 | if err != nil { 51 | mod.LogErrorf("Error sending twilio SMS: %s", err) 52 | } 53 | 54 | default: 55 | panic("Unknown action triggered in " + mod.Name() + ": " + action.Name) 56 | } 57 | 58 | return outs 59 | } 60 | 61 | // Run executes the Bee's event loop. 62 | func (mod *TwilioBee) Run(eventChan chan bees.Event) { 63 | mod.client = twilio.NewClient(mod.accountsid, mod.authtoken) 64 | } 65 | 66 | // ReloadOptions parses the config options and initializes the Bee. 67 | func (mod *TwilioBee) ReloadOptions(options bees.BeeOptions) { 68 | mod.SetOptions(options) 69 | 70 | options.Bind("account_sid", &mod.accountsid) 71 | options.Bind("auth_token", &mod.authtoken) 72 | options.Bind("from_number", &mod.fromNumber) 73 | options.Bind("to_number", &mod.toNumber) 74 | } 75 | -------------------------------------------------------------------------------- /build-constants.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var ( 4 | Version = "0.0.0" 5 | CommitSHA = "unknown" 6 | ) 7 | -------------------------------------------------------------------------------- /cfg/config_test.go: -------------------------------------------------------------------------------- 1 | package cfg 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | "testing" 7 | ) 8 | 9 | func TestNew(t *testing.T) { 10 | conf, err := New("/foobar") 11 | if err != nil { 12 | t.Fatal("cannot create config from path") 13 | } 14 | if _, ok := conf.Backend().(*FileBackend); !ok { 15 | t.Error("Backend for '/foobar' should be a FileBackend") 16 | } 17 | 18 | conf, err = New("file:///foobar") 19 | if err != nil { 20 | t.Fatal("cannot create config from file:// path") 21 | } 22 | if _, ok := conf.Backend().(*FileBackend); !ok { 23 | t.Error("Backend for 'file:///foobar' should be a FileBackend") 24 | } 25 | 26 | cwd, _ := os.Getwd() 27 | p := filepath.Join(cwd, "testdata/beehive-crypto.conf") 28 | conf, err = New(p) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | if _, ok := conf.Backend().(*AESBackend); !ok { 33 | t.Errorf("Backend for '%s' should be an AESBackend", p) 34 | } 35 | 36 | conf, err = New("mem:") 37 | if err != nil { 38 | t.Fatal("cannot create config from memory") 39 | } 40 | if _, ok := conf.Backend().(*MemBackend); !ok { 41 | t.Error("Backend for 'mem:' should be a MemoryBackend") 42 | } 43 | 44 | _, err = New("c:\\foobar") 45 | if err == nil { 46 | t.Error("Not a valid URL, should return an error") 47 | } 48 | 49 | _, err = New("") 50 | if err == nil { 51 | t.Error("Not a valid URL, should return an error") 52 | } 53 | } 54 | 55 | func TestLoad(t *testing.T) { 56 | conf, err := New("mem://") 57 | if err != nil { 58 | t.Fatal(err) 59 | } 60 | err = conf.Load() 61 | if err != nil { 62 | t.Error("Failed loading the configuration") 63 | } 64 | if conf.URL().Scheme != "mem" { 65 | t.Error("Config URL didn't change") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cfg/filebackend.go: -------------------------------------------------------------------------------- 1 | package cfg 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "net/url" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "gopkg.in/yaml.v2" 12 | ) 13 | 14 | type Format int 15 | 16 | const ( 17 | FormatJSON Format = iota 18 | FormatYAML = iota 19 | ) 20 | 21 | // FileBackend implements a filesystem backend for the configuration 22 | type FileBackend struct { 23 | format Format 24 | } 25 | 26 | // NewFileBackend returns a FileBackend that handles loading and 27 | // saving files from the local filesytem. 28 | func NewFileBackend() *FileBackend { 29 | return &FileBackend{format: FormatJSON} 30 | } 31 | 32 | // Load loads chains from config 33 | func (fs *FileBackend) Load(u *url.URL) (*Config, error) { 34 | var config Config 35 | 36 | // detect file format by extension 37 | if strings.HasSuffix(u.Path, ".yaml") { 38 | fs.format = FormatYAML 39 | } else if strings.HasSuffix(u.Path, ".yml") { 40 | fs.format = FormatYAML 41 | } else { 42 | fs.format = FormatJSON 43 | } 44 | 45 | if !exist(u.Path) { 46 | return &Config{url: u}, nil 47 | } 48 | 49 | content, err := ioutil.ReadFile(u.Path) 50 | if err != nil { 51 | return &config, err 52 | } 53 | 54 | if fs.format == FormatYAML { 55 | err = yaml.Unmarshal(content, &config) 56 | } else { 57 | err = json.Unmarshal(content, &config) 58 | } 59 | if err != nil { 60 | return nil, err 61 | } 62 | config.backend = fs 63 | config.url = u 64 | 65 | return &config, nil 66 | } 67 | 68 | // Save saves chains to config 69 | func (fs *FileBackend) Save(config *Config) error { 70 | cfgDir := filepath.Dir(config.URL().Path) 71 | if !exist(cfgDir) { 72 | err := os.MkdirAll(cfgDir, 0755) 73 | if err != nil { 74 | return err 75 | } 76 | } 77 | 78 | var content []byte 79 | var err error 80 | if fs.format == FormatYAML { 81 | content, err = yaml.Marshal(config) 82 | } else { 83 | content, err = json.MarshalIndent(config, "", " ") 84 | } 85 | if err != nil { 86 | return err 87 | } 88 | return ioutil.WriteFile(config.URL().Path, content, 0644) 89 | } 90 | -------------------------------------------------------------------------------- /cfg/membackend.go: -------------------------------------------------------------------------------- 1 | package cfg 2 | 3 | import "net/url" 4 | 5 | // MemBackend implements a dummy memory backend for the configuration 6 | type MemBackend struct { 7 | conf *Config 8 | } 9 | 10 | // NewMemBackend returns a backend that handles loading and saving 11 | // the configuration from memory 12 | func NewMemBackend() *MemBackend { 13 | return &MemBackend{conf: &Config{}} 14 | } 15 | 16 | // Load the config from memory 17 | // 18 | // No need to do anything here, already loaded 19 | func (m *MemBackend) Load(u *url.URL) (*Config, error) { 20 | return m.conf, nil 21 | } 22 | 23 | // Save the config to memory 24 | // 25 | // No need to do anything special here, already in memory 26 | func (m *MemBackend) Save(config *Config) error { 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /cfg/membackend_test.go: -------------------------------------------------------------------------------- 1 | package cfg 2 | 3 | import ( 4 | "net/url" 5 | "path/filepath" 6 | "testing" 7 | ) 8 | 9 | func TestMemLoad(t *testing.T) { 10 | u, _ := url.Parse("mem://") 11 | backend := NewMemBackend() 12 | _, err := backend.Load(u) 13 | if err != nil { 14 | t.Error("Loading an invalid config file should return an error") 15 | } 16 | } 17 | 18 | func TestMemSave(t *testing.T) { 19 | path := filepath.Join("testdata", "foobar") 20 | u, _ := url.Parse(filepath.Join("testdata", "foobar")) 21 | backend := NewMemBackend() 22 | conf := &Config{url: u} 23 | err := backend.Save(conf) 24 | if err != nil { 25 | t.Errorf("Failed to save the config to memory") 26 | } 27 | 28 | if exist(path) { 29 | t.Error("Configuration file should not exist") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cfg/testdata/beehive-crypto.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/beehive/d636b697737dae0523a8c9972c01dbe6227d89ec/cfg/testdata/beehive-crypto.conf -------------------------------------------------------------------------------- /cfg/testdata/beehive.conf: -------------------------------------------------------------------------------- 1 | { 2 | "Bees": [ 3 | { 4 | "Name": "echo", 5 | "Class": "execbee", 6 | "Description": "echo", 7 | "Options": [] 8 | } 9 | ], 10 | "Actions": null, 11 | "Chains": [] 12 | } -------------------------------------------------------------------------------- /cfg/testdata/beehive.yaml: -------------------------------------------------------------------------------- 1 | bees: 2 | - name: echo 3 | class: execbee 4 | description: echo 5 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '3' 3 | 4 | services: 5 | beehive: 6 | image: fribbledom/beehive 7 | ports: 8 | - 8181:8181 9 | volumes: 10 | - beehive-conf:/conf 11 | environment: 12 | # be sure not to pass quotes, just the bare url 13 | - CANONICAL_URL=http://localhost:8181 14 | 15 | volumes: 16 | beehive-conf: 17 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | Beehive 2 | ======= 3 | 4 | ## Docker Installation 5 | 6 | You can install beehive with docker if you'd prefer not to set up a working Go environment. 7 | 8 | Make sure you have docker installed. See the [install instructions](https://docs.docker.com/engine/getstarted/step_one/). 9 | 10 | ### Using a prebuilt container image 11 | 12 | The simplest way to set up beehive with docker is to simply pull a prebuilt image. 13 | 14 | docker pull fribbledom/beehive 15 | 16 | ### Building your own container image (skip if using a prebuilt image) 17 | 18 | Make sure you're currently in the docker directory of the repository. 19 | You can simply clone the repository with git and cd into the directory. 20 | 21 | git clone --recursive https://github.com/muesli/beehive.git 22 | cd beehive 23 | 24 | Alternatively if you have the package installed with `go get` you can navigate 25 | to `$GOPATH/src/github.com/muesli/beehive` 26 | 27 | Either way once you're there you can build the docker container 28 | 29 | docker build -t beehive . 30 | 31 | If you'd like to push the image up to docker.io so that you can use it elsewhere, you need 32 | to namespace it with your docker.io username. 33 | 34 | docker build -t /beehive . 35 | docker push /beehive 36 | 37 | ## Running a container 38 | 39 | Once you have the image on your machine, it's time to spin up an instance of it! 40 | Of course if you built the container yourself without adding your username, leave out 41 | the `/` in this command. 42 | 43 | docker run --name beehive -d -p 8181:8181 /beehive 44 | 45 | The `--name` parameter will give your container a name so that you can easily reference it with future commands. 46 | The `-d` flag specifies that the container should be run as a daemon. 47 | The `-p` parameter tells docker to map port 8181 on the host machine to port 8181 in the container. 48 | You can expose as many ports as is necessary. If you're running http server bees then you may need to 49 | add additional flags so that those servers can be seen by your machine: `-p 8181:8181 -p 12345:12345 ... -p 34343:34343` 50 | 51 | If ever you want to stop the container, run the following 52 | 53 | docker stop beehive 54 | 55 | Then you can start it again with 56 | 57 | docker start beehive 58 | 59 | #### Note 60 | 61 | This container will store the `beehive.conf` file in a persistent volume. 62 | As long as you use `docker stop` / `docker start` to stop/start the container 63 | the configuration will persist. 64 | 65 | If you'd like to have the container use an old config file, you can mount it as 66 | a volume with `docker run`. 67 | 68 | Suppose you had a config file stored in `/path/to/beehive.conf` then when running the container use 69 | 70 | docker run -d -p 8181:8181 -v /path/to/beehive.conf:/conf/beehive.conf /beehive 71 | 72 | This will tell docker to put your config file at `/conf/beehive.conf` within the container's filesystem. 73 | Thus beehive will startup using your configuration file. 74 | -------------------------------------------------------------------------------- /docs/config_encryption.md: -------------------------------------------------------------------------------- 1 | # Configuration Encryption 2 | 3 | Beehive's supports encrypting the configuration file using AES+GCM. 4 | 5 | ## Usage 6 | 7 | To encrypt the configuration for the first time, simply start Beehive using a `crypto` URL for the configuration: 8 | 9 | ``` 10 | ./beehive --config crypto://mysecret@$HOME/.config/beehive/beehive.conf` 11 | ``` 12 | 13 | You could also use the `BEEHIVE_CONFIG_PASSWORD` environment variable to define the password: 14 | 15 | ``` 16 | BEEHIVE_CONFIG_PASSWORD=mysecret ./beehive --config crypto://$HOME/.config/beehive/beehive.conf` 17 | ``` 18 | 19 | This will use the key `mysecret` to encrypt/decrypt the configuration file. 20 | 21 | Once the configuration has been encrypted, it's no longer necessary to use a `crypto:` URL, Beehive will automatically detect it's encrypted. 22 | That is, something like: 23 | 24 | ``` 25 | BEEHIVE_CONFIG_PASSWORD=mysecret beehive --config /path/to/config 26 | ``` 27 | 28 | Will happily detect and load an encrypted configuration file. 29 | 30 | ## Using user keyrings to store the password 31 | 32 | A sample wrapper script (Linux only) is provided in [tools/encrypted-config-wrapper] that will read the configuration password from the sessions's keyring. 33 | 34 | Something similar could be written to do it on macOS using Keychain and its `security(1)` CLI. 35 | 36 | ## Decrypting the configuration 37 | 38 | Use `--decrypt` with a valid password: 39 | 40 | ``` 41 | beehive --decrypt --config crypto://mysecret@/path/to/config/file 42 | ``` 43 | 44 | or using an environment variable: 45 | 46 | ``` 47 | BEEHIVE_CONFIG_PASSWORD=mysecret beehive --decrypt --config crypto:///path/to/config/file 48 | ``` 49 | 50 | You can also use omit `--config` when using the default configuration path: 51 | 52 | ``` 53 | BEEHIVE_CONFIG_PASSWORD=mysecret beehive --decrypt 54 | ``` 55 | 56 | ## Troubleshooting 57 | 58 | ``` 59 | FATA[0000] Error loading user config file /home/rubiojr/.config/beehive/beehive.conf. err: cipher: message authentication failed 60 | ``` 61 | 62 | Means the password used to decrypt the configuration file is not valid. 63 | 64 | ## Notes 65 | 66 | The encrypted configuration file includes a 12 bytes header (`beehiveconf+`) that makes it possible to identify the file as an encrypted configuration file: 67 | 68 | ``` 69 | head -c 12 beehive-encrypted.conf 70 | beehiveconf+ 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/watchdog.md: -------------------------------------------------------------------------------- 1 | # Systemd's Watchdog integration 2 | 3 | Integrates Beehive with the Systemd's watchdog. 4 | 5 | See http://0pointer.de/blog/projects/watchdog.html 6 | 7 | ## Configuration 8 | 9 | As a system service: 10 | 11 | * Add the service unit to `/etc/systemd/system/beehive.conf` 12 | 13 | Sample service unit: 14 | 15 | ``` 16 | [Unit] 17 | Description=Beehive with Systemd's watchdog 18 | [Service] 19 | Type=simple 20 | ExecStart=/usr/bin/beehive --config /path/to/beehive.conf 21 | Restart=on-failure 22 | WatchdogSec=30s 23 | 24 | [Install] 25 | WantedBy=multi-user.target 26 | ``` 27 | *Note: change `/path/to/beehive.conf` to a real path pointing to Beehive's config* 28 | 29 | * Enable the new service: `systemctl enable beehive` 30 | * Start the service: `systemctl start beehive` 31 | 32 | Beehive will automatically detect it's running under Systemd and notify Systemd's watchdog every WatchdogSec/3 seconds (10 seconds in this particular case). Note the notification interval is hardcoded to WatchdogSec/3. -------------------------------------------------------------------------------- /filters/filters.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package filters contains Beehive's filter system. 22 | package filters 23 | 24 | // FilterInterface is an interface all Filters implement. 25 | type FilterInterface interface { 26 | // Name of the filter 27 | Name() string 28 | // Description of the filter 29 | Description() string 30 | 31 | // Execute the filter 32 | Passes(data map[string]interface{}, value string) bool 33 | } 34 | 35 | var ( 36 | filters = make(map[string]*FilterInterface) 37 | ) 38 | 39 | // RegisterFilter gets called by Filters to register themselves. 40 | func RegisterFilter(filter FilterInterface) { 41 | // log.Println("Filter bee ready:", filter.Name(), "-", filter.Description()) 42 | filters[filter.Name()] = &filter 43 | } 44 | 45 | // GetFilter returns a filter with a specific name 46 | func GetFilter(identifier string) *FilterInterface { 47 | filter, ok := filters[identifier] 48 | if ok { 49 | return filter 50 | } 51 | 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /filters/template/templatefilter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | // Package templatefilter provides a template-based filter. 22 | package templatefilter 23 | 24 | import ( 25 | "bytes" 26 | "strings" 27 | "text/template" 28 | 29 | "github.com/muesli/beehive/filters" 30 | "github.com/muesli/beehive/templatehelper" 31 | ) 32 | 33 | // TemplateFilter is a template-based filter. 34 | type TemplateFilter struct { 35 | } 36 | 37 | // Name returns the name of this Filter. 38 | func (filter *TemplateFilter) Name() string { 39 | return "template" 40 | } 41 | 42 | // Description returns the description of this Filter. 43 | func (filter *TemplateFilter) Description() string { 44 | return "This filter passes when a template-if returns true" 45 | } 46 | 47 | // Passes returns true when the Filter matched the data. 48 | func (filter *TemplateFilter) Passes(data map[string]interface{}, v string) bool { 49 | var res bytes.Buffer 50 | 51 | if strings.Contains(v, "{{test") { 52 | v = strings.Replace(v, "{{test", "{{if", -1) 53 | v += "true{{end}}" 54 | } 55 | 56 | tmpl, err := template.New("_" + v).Funcs(templatehelper.FuncMap).Parse(v) 57 | if err == nil { 58 | err = tmpl.Execute(&res, data) 59 | } 60 | if err != nil { 61 | panic(err) 62 | } 63 | 64 | return strings.TrimSpace(res.String()) == "true" 65 | } 66 | 67 | func init() { 68 | f := TemplateFilter{} 69 | 70 | filters.RegisterFilter(&f) 71 | } 72 | -------------------------------------------------------------------------------- /filters/template/templatefilter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 Christian Muehlhaeuser 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU Affero General Public License as published 6 | * by the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU Affero General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Affero General Public License 15 | * along with this program. If not, see . 16 | * 17 | * Authors: 18 | * Christian Muehlhaeuser 19 | */ 20 | 21 | package templatefilter 22 | 23 | import ( 24 | "testing" 25 | ) 26 | 27 | func TestTemplateFilter(t *testing.T) { 28 | f := TemplateFilter{} 29 | 30 | o := map[string]interface{}{} 31 | o["text"] = "hello world" 32 | 33 | if !f.Passes(o, "{{$args := Split .text \" \"}}{{test eq (len $args) 2}}") { 34 | t.Error("TemplateFilter fails on string comparison") 35 | } 36 | if f.Passes(o, "{{$args := Split .text \" \"}}{{test eq (len $args) 3}}") { 37 | t.Error("TemplateFilter fails on string comparison") 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /hives_linux.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | /* 4 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | package main 24 | 25 | import ( 26 | _ "github.com/muesli/beehive/bees/notificationbee" 27 | _ "github.com/muesli/beehive/bees/serialbee" 28 | ) 29 | -------------------------------------------------------------------------------- /hives_osx.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | /* 4 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | package main 24 | 25 | import ( 26 | _ "github.com/muesli/beehive/bees/notificationbee" 27 | _ "github.com/muesli/beehive/bees/serialbee" 28 | ) 29 | -------------------------------------------------------------------------------- /hives_unix.go: -------------------------------------------------------------------------------- 1 | // +build dragonfly freebsd linux netbsd openbsd solaris 2 | 3 | /* 4 | * Copyright (C) 2014-2017 Christian Muehlhaeuser 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as published 8 | * by the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * Authors: 20 | * Christian Muehlhaeuser 21 | */ 22 | 23 | package main 24 | 25 | import ( 26 | ) 27 | -------------------------------------------------------------------------------- /templatehelper/templatehelper_test.go: -------------------------------------------------------------------------------- 1 | package templatehelper 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | "text/template" 7 | ) 8 | 9 | func executeTemplate(text string, data interface{}) (string, error) { 10 | var res bytes.Buffer 11 | tmpl, err := template.New("_test").Funcs(FuncMap).Parse(text) 12 | if err == nil { 13 | err = tmpl.Execute(&res, data) 14 | } 15 | return res.String(), err 16 | } 17 | 18 | func Test_FuncMap_Positive(t *testing.T) { 19 | t.Parallel() 20 | cases := []struct { 21 | text string 22 | expected string 23 | }{ 24 | // sanity checks 25 | 26 | {`{{if true}}ok{{end}}`, "ok"}, 27 | {`{{if false}}ok{{end}}`, ""}, 28 | 29 | // boolean filters 30 | 31 | {`{{if Matches "123" "\\d+"}}ok{{end}}`, "ok"}, 32 | {`{{if Matches "hello" "\\d+"}}ok{{end}}`, ""}, 33 | 34 | {`{{if Contains "123" "2"}}ok{{end}}`, "ok"}, 35 | {`{{if Contains "123" "4"}}ok{{end}}`, ""}, 36 | 37 | {`{{if ContainsAny "123" "24"}}ok{{end}}`, "ok"}, 38 | {`{{if ContainsAny "123" "45"}}ok{{end}}`, ""}, 39 | 40 | {`{{if EqualFold "HellO" "hello"}}ok{{end}}`, "ok"}, 41 | {`{{if EqualFold "ПривеТ" "привет"}}ok{{end}}`, "ok"}, 42 | {`{{if EqualFold "good" "goed"}}ok{{end}}`, ""}, 43 | 44 | {`{{if HasPrefix "hello" "he"}}ok{{end}}`, "ok"}, 45 | {`{{if HasPrefix "hello" "lo"}}ok{{end}}`, ""}, 46 | 47 | {`{{if HasSuffix "hello" "lo"}}ok{{end}}`, "ok"}, 48 | {`{{if HasSuffix "hello" "he"}}ok{{end}}`, ""}, 49 | 50 | // filters returning a string 51 | 52 | {`{{JSON 123}}`, "[123]"}, 53 | 54 | {`{{Left "123456" 2}}`, "12"}, 55 | {`{{Left "123456" 10}}`, "123456"}, 56 | 57 | {`{{Right "123456" 2}}`, "56"}, 58 | {`{{Right "123456" 10}}`, "123456"}, 59 | 60 | {`{{Last (Split "12,34,56" ",")}}`, "56"}, 61 | 62 | {`{{Mid "123456" 2}}`, "3456"}, 63 | {`{{Mid "123456" 10}}`, ""}, 64 | {`{{Mid "123456" 2 4}}`, "34"}, 65 | {`{{Mid "123456" 2 10}}`, "3456"}, 66 | 67 | {`{{Join (Split "12,34,56" ",") "|"}}`, "12|34|56"}, 68 | {`{{Join (Split "12" ",") "|"}}`, "12"}, 69 | 70 | {`{{Repeat "12" 3}}`, "121212"}, 71 | {`{{Repeat "12" 0}}`, ""}, 72 | {`{{Repeat "" 10}}`, ""}, 73 | 74 | {`{{Replace "1234" "23" "56" -1}}`, "1564"}, 75 | {`{{Replace "12223" "2" "5" 1}}`, "15223"}, 76 | // ... 77 | } 78 | 79 | for _, tcase := range cases { 80 | tcase := tcase // important, needed for running in parallel 81 | t.Run(tcase.text, func(t *testing.T) { 82 | t.Parallel() 83 | result, err := executeTemplate(tcase.text, nil) 84 | if err != nil { 85 | t.Errorf("error executing template: %s", err.Error()) 86 | t.FailNow() 87 | } 88 | if result != tcase.expected { 89 | t.Errorf("expected `%s` but actually `%s`", tcase.expected, result) 90 | t.FailNow() 91 | } 92 | }) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tools/encrypted-config-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Beehive shell wrapper that reads configuration password from the keyring. 3 | # Store the configuration password using secret-tool: 4 | # 5 | # secret-tool store --label "Beehive configuration password" /beehive/secrets/config password 6 | # 7 | # Linux only. 8 | # 9 | set -e 10 | 11 | export BEEHIVE_CONFIG_PASSWORD=$(secret-tool lookup /beehive/secrets/config password) 12 | if [ -z "$BEEHIVE_CONFIG_PASSWORD" ]; then 13 | echo "Beehive's config password not found in keyring." >&2 14 | echo "Add it using 'secret-tool store --label "Beehive configuration password" /beehive/secrets/config password'" >&2 15 | exit 1 16 | fi 17 | beehive --config crypto://$HOME/.config/beehive/beehive.conf 18 | -------------------------------------------------------------------------------- /tools/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! command -v goreleaser; then 4 | echo "goreleaser not found" 5 | exit 1 6 | fi 7 | 8 | # Get the highest tag number 9 | VERSION="$(git describe --abbrev=0 --tags)" 10 | VERSION=${VERSION:-'0.0.0'} 11 | 12 | # Get number parts 13 | MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" 14 | MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" 15 | PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}" 16 | 17 | # Increase version 18 | PATCH=$((PATCH+1)) 19 | 20 | TAG="${1}" 21 | 22 | if [ "${TAG}" = "" ]; then 23 | TAG="${MAJOR}.${MINOR}.${PATCH}" 24 | fi 25 | 26 | echo "Releasing ${TAG} ..." 27 | 28 | git tag -a -s -m "Release ${TAG}" "${TAG}" 29 | git push --tags 30 | goreleaser release --rm-dist 31 | -------------------------------------------------------------------------------- /watchdog_linux.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/coreos/go-systemd/daemon" 8 | "github.com/muesli/beehive/api" 9 | log "github.com/sirupsen/logrus" 10 | ) 11 | 12 | // Notifies Systemd's watchdog every WatchdogSec/3 seconds when running 13 | // under Systemd and the watchdog feature has been enabled in 14 | // the service unit. 15 | // 16 | // This will no-op when not running under Systemd. 17 | // 18 | // See http://0pointer.de/blog/projects/watchdog.html 19 | // and https://www.freedesktop.org/software/systemd/man/systemd.service.html 20 | // 21 | func init() { 22 | // returns the configured WatchdogSec in the service unit as time.Duration 23 | interval, err := daemon.SdWatchdogEnabled(false) 24 | if err != nil || interval == 0 { 25 | log.Debug("Systemd watchdog not enabled") 26 | return 27 | } 28 | 29 | // We want to notify the watchdog every WatchdogSec/3, that is, if WatchdogSec is 30 | // set to 30 seconds, we'll send a notification to systemd every 10 seconds. 31 | runEvery := interval / 3 32 | log.Debugf("Systemd watchdog notifications every %.2f seconds", runEvery.Seconds()) 33 | 34 | go func() { 35 | for { 36 | select { 37 | case <-time.After(runEvery): 38 | resp, err := http.Get(api.CanonicalURL().String()) 39 | if err == nil { 40 | resp.Body.Close() 41 | log.Debugf("Systemd watchdog notify") 42 | daemon.SdNotify(false, daemon.SdNotifyWatchdog) 43 | } 44 | } 45 | } 46 | }() 47 | } 48 | --------------------------------------------------------------------------------