From 887eff056b60f6f90843782b5859b00a3c05d23f Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Tue, 11 May 2021 18:35:24 +0200 Subject: [PATCH 1/4] Added "AUTO_RECEIVE_SCHEDULE" parameter to docker-compose.yml file * signal-cli recommends to call "receive" on a regular basis. In case "receive" is not already called periodically by the user application, add the option to invoke it at a specific schedule from within the docker container. The "AUTO_RECEIVE_SCHEDULE" parameter takes a cron schedule expression and calls "receive" at the given time. see #129 --- README.md | 8 +++++- docker-compose.yml | 2 +- src/go.mod | 1 + src/go.sum | 3 ++ src/main.go | 72 ++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d41515c..3e8e606 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,19 @@ services: image: bbernhard/signal-cli-rest-api:latest environment: - USE_NATIVE=0 - ports: + #- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below) + ports: - "8080:8080" #map docker port 8080 to host port 8080. volumes: - "./signal-cli-config:/home/.local/share/signal-cli" #map "signal-cli-config" folder on host system into docker container. the folder contains the password and cryptographic keys when a new number is registered ``` +## Auto Receive Schedule + +[signal-cli](https://github.com/AsamK/signal-cli), which this REST API wrapper is based on, recommends to call `receive` on a regular basis. So, if you are not already calling the `receive` endpoint regularily, it is recommended to set the `AUTO_RECEIVE_SCHEDULE` parameter in the docker-compose.yml file. The `AUTO_RECEIVE_SCHEDULE` accepts cron schedule expressions and automatically calls the `receive` endpoint at the given time. e.g: `0 22 * * *` calls `receive` daily at 10pm. If you are not familiar with cron schedule expressions, you can use this [website](https://crontab.guru). + + ## Native Image (EXPERIMENTAL) On Systems like the Raspberry Pi, some operations like sending messages can take quite a while. That's because signal-cli is a Java application and a significant amount of time is spent in the JVM (Java Virtual Machine) startup. signal-cli recently added the possibility to compile the Java application to a native binary (done via GraalVM). diff --git a/docker-compose.yml b/docker-compose.yml index 058313e..ae752bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,9 @@ version: "3" services: signal-cli-rest-api: image: bbernhard/signal-cli-rest-api:latest - #build: "." environment: - USE_NATIVE=0 + #- AUTO_RECEIVE_SCHEDULE=0 22 * * * - PORT=8080 ports: - "8080:8080" #map docker port 8080 to host port 8080. diff --git a/src/go.mod b/src/go.mod index 458ab57..efad5d9 100644 --- a/src/go.mod +++ b/src/go.mod @@ -13,6 +13,7 @@ require ( github.com/gofrs/uuid v3.3.0+incompatible github.com/h2non/filetype v1.1.0 github.com/mailru/easyjson v0.7.1 // indirect + github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.6.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 diff --git a/src/go.sum b/src/go.sum index 1b66949..3908cf1 100644 --- a/src/go.sum +++ b/src/go.sum @@ -94,6 +94,9 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= diff --git a/src/main.go b/src/main.go index 47414b6..c8e5d8b 100644 --- a/src/main.go +++ b/src/main.go @@ -1,21 +1,24 @@ package main import ( + "encoding/json" "flag" + "strings" + "net/http" + "os" + "path/filepath" + "io/ioutil" + "github.com/bbernhard/signal-cli-rest-api/api" + _ "github.com/bbernhard/signal-cli-rest-api/docs" + "github.com/bbernhard/signal-cli-rest-api/utils" "github.com/gin-gonic/gin" + "github.com/robfig/cron/v3" log "github.com/sirupsen/logrus" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" - "github.com/bbernhard/signal-cli-rest-api/api" - "github.com/bbernhard/signal-cli-rest-api/utils" - _ "github.com/bbernhard/signal-cli-rest-api/docs" - "os" - ) - - // @title Signal Cli REST API // @version 1.0 // @description This is the Signal Cli REST API documentation. @@ -32,10 +35,10 @@ import ( // @tag.name Messages // @tag.description Send and Receive Signal Messages. -// @tag.name Attachments +// @tag.name Attachments // @tag.description List and Delete Attachments. -// @tag.name Profiles +// @tag.name Profiles // @tag.description Update Profile. // @tag.name Identities @@ -151,6 +154,57 @@ func main() { swaggerUrl := ginSwagger.URL("http://127.0.0.1:" + string(swaggerPort) + "/swagger/doc.json") router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, swaggerUrl)) + autoReceiveSchedule := utils.GetEnv("AUTO_RECEIVE_SCHEDULE", "") + if autoReceiveSchedule != "" { + p := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow) + schedule, err := p.Parse(autoReceiveSchedule) + if err != nil { + log.Fatal("Invalid AUTO_RECEIVE_SCHEDULE: ", err.Error()) + } + + c := cron.New() + c.Schedule(schedule, cron.FuncJob(func() { + err := filepath.Walk(*signalCliConfig, func(path string, info os.FileInfo, err error) error { + filename := filepath.Base(path) + if strings.HasPrefix(filename, "+") && info.Mode().IsRegular() { + log.Debug("AUTO_RECEIVE_SCHEDULE: Calling receive for number ", filename) + resp, err := http.Get("http://127.0.0.1:8080/v1/receive/"+filename) + if err != nil { + log.Error("AUTO_RECEIVE_SCHEDULE: Couldn't call receive for number ", filename, ": ", err.Error()) + } + if resp.StatusCode != 200 { + jsonResp, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + log.Error("AUTO_RECEIVE_SCHEDULE: Couldn't read json response: ", err.Error()) + return nil + } + + type ReceiveResponse struct { + Error string `json:"error"` + } + var receiveResponse ReceiveResponse + err = json.Unmarshal(jsonResp, &receiveResponse) + if err != nil { + log.Error("AUTO_RECEIVE_SCHEDULE: Couldn't parse json response: ", err.Error()) + return nil + } + + log.Error("AUTO_RECEIVE_SCHEDULE: Couldn't call receive for number ", filename, ": ", receiveResponse) + + } + } + + return nil + }) + if err != nil { + log.Fatal("Couldn't get registered numbers") + } + })) + c.Start() + } + + router.Run() } From 8525f6b364860fbc00a4ab869612a61239cf8ec5 Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Tue, 11 May 2021 18:43:25 +0200 Subject: [PATCH 2/4] improved README see #129 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3e8e606..ca1aa56 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ services: [signal-cli](https://github.com/AsamK/signal-cli), which this REST API wrapper is based on, recommends to call `receive` on a regular basis. So, if you are not already calling the `receive` endpoint regularily, it is recommended to set the `AUTO_RECEIVE_SCHEDULE` parameter in the docker-compose.yml file. The `AUTO_RECEIVE_SCHEDULE` accepts cron schedule expressions and automatically calls the `receive` endpoint at the given time. e.g: `0 22 * * *` calls `receive` daily at 10pm. If you are not familiar with cron schedule expressions, you can use this [website](https://crontab.guru). +**WARNING** Calling `receive` will fetch all the messages for the registered Signal number from the Signal Server! So, if you are using the REST API for receiving messages, it's _not_ a good idea to use the `AUTO_RECEIVE_SCHEDULE` parameter, as you might lose some messages that way. + ## Native Image (EXPERIMENTAL) From f79c5c25988fb9f30d1d59e0e2e1a59cd269f340 Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Thu, 13 May 2021 17:41:51 +0200 Subject: [PATCH 3/4] updated signal-cli to v0.8.3 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 71fbde9..44dffd4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG SIGNAL_CLI_VERSION=0.8.1 +ARG SIGNAL_CLI_VERSION=0.8.3 ARG ZKGROUP_VERSION=0.7.0 ARG LIBSIGNAL_CLIENT_VERSION=0.2.3 From 6bd7b66e1e5bb1ca875331e964c969ae47e839ef Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Fri, 14 May 2021 08:51:36 +0200 Subject: [PATCH 4/4] improved log messages --- src/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.go b/src/main.go index c8e5d8b..f5c9102 100644 --- a/src/main.go +++ b/src/main.go @@ -159,7 +159,7 @@ func main() { p := cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow) schedule, err := p.Parse(autoReceiveSchedule) if err != nil { - log.Fatal("Invalid AUTO_RECEIVE_SCHEDULE: ", err.Error()) + log.Fatal("AUTO_RECEIVE_SCHEDULE: Invalid schedule: ", err.Error()) } c := cron.New() @@ -198,7 +198,7 @@ func main() { return nil }) if err != nil { - log.Fatal("Couldn't get registered numbers") + log.Fatal("AUTO_RECEIVE_SCHEDULE: Couldn't get registered numbers") } })) c.Start()