Compare commits

..

1 Commits

8 changed files with 66 additions and 96 deletions

View File

@ -1,13 +1,13 @@
ARG SIGNAL_CLI_VERSION=0.14.0
ARG LIBSIGNAL_CLIENT_VERSION=0.87.4
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.14.0+morph027+5
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.14.0+morph027+1
ARG SWAG_VERSION=1.16.4
ARG GRAALVM_VERSION=25.0.2
ARG BUILD_VERSION_ARG=unset
FROM golang:1.26-trixie AS buildcontainer
FROM golang:1.24-bookworm AS buildcontainer
ARG SIGNAL_CLI_VERSION
ARG LIBSIGNAL_CLIENT_VERSION
@ -31,8 +31,8 @@ RUN arch="$(uname -m)"; \
RUN dpkg-reconfigure debconf --frontend=noninteractive \
&& apt-get update \
&& apt-get -y install --no-install-recommends \
wget git locales zip unzip \
file build-essential libz-dev zlib1g-dev binutils \
wget software-properties-common git locales zip unzip \
file build-essential libz-dev zlib1g-dev \
&& rm -rf /var/lib/apt/lists/*
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
@ -90,8 +90,8 @@ RUN if [ "$(uname -m)" = "x86_64" ]; then \
&& ./gradlew -q nativeCompile; \
elif [ "$(uname -m)" = "aarch64" ] ; then \
echo "Use native image from @morph027 (https://packaging.gitlab.io/signal-cli/) for arm64 - many thanks to @morph027" \
&& curl -fsSL https://packaging.gitlab.io/signal-cli/gpg.key | gpg -o /usr/share/keyrings/signal-cli-native.pgp --dearmor \
&& echo "deb [signed-by=/usr/share/keyrings/signal-cli-native.pgp] https://packaging.gitlab.io/signal-cli signalcli main" > /etc/apt/sources.list.d/morph027-signal-cli.list \
&& curl -fsSL https://packaging.gitlab.io/signal-cli/gpg.key | apt-key add - \
&& echo "deb https://packaging.gitlab.io/signal-cli focal main" > /etc/apt/sources.list.d/morph027-signal-cli.list \
&& mkdir -p /tmp/signal-cli-native \
&& cd /tmp/signal-cli-native \
#&& wget https://gitlab.com/packaging/signal-cli/-/jobs/3716873649/artifacts/download?file_type=archive -O /tmp/signal-cli-native/archive.zip \
@ -172,7 +172,7 @@ ENV SIGNAL_CLI_REST_API_PLUGIN_SHARED_OBJ_DIR=/usr/bin/
RUN dpkg-reconfigure debconf --frontend=noninteractive \
&& apt-get update \
&& apt-get install -y --no-install-recommends util-linux supervisor openjdk-25-jre curl locales \
&& apt-get install -y --no-install-recommends util-linux supervisor netcat-openbsd openjdk-25-jre curl locales \
&& rm -rf /var/lib/apt/lists/*
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api /usr/bin/signal-cli-rest-api

View File

@ -4,8 +4,6 @@ This can be done by putting the docker container into debug mode with the follow
```curl -X POST -H "Content-Type: application/json" -d '{"logging": {"level": "debug"}}' 'http://127.0.0.1:8080/v1/configuration'```
Alternatively, you can set the `LOG_LEVEL` environment variable.
Once the docker container is in debug mode, execute the REST API command you want to debug.
e.g Let's assume we are experiencing some problems with sending messages. So, let's send a Signal message with

View File

@ -1,22 +1,11 @@
version: "3"
services:
signal-cli-rest-api:
#image: bbernhard/signal-cli-rest-api:latest-dev
build: "."
image: bbernhard/signal-cli-rest-api:latest
environment:
- MODE=normal #supported modes: json-rpc, json-rpc-native, native, normal
- ENABLE_PLUGINS=true
- DEFAULT_SIGNAL_TEXT_MODE=styled
- SWAGGER_IP=127.0.0.1
- PODMAN_USERNS=keep-id
#- JSON_RPC_IGNORE_ATTACHMENTS=true
#- JSON_RPC_IGNORE_STORIES=true
#- RECEIVE_WEBHOOK_URL=http://127.0.0.1:8089/webhook
#- JSON_RPC_TRUST_NEW_IDENTITIES=always
#- RECEIVE_WEBHOOK_URL=http://127.0.0.1:8080/v1/plugins/abc
- MODE=normal #supported modes: json-rpc, native, normal
#- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below)
#network_mode: host
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
- "./plugins:/plugins"

View File

@ -843,7 +843,6 @@ func (a *Api) AddMembersToGroup(c *gin.Context) {
err = a.signalClient.AddMembersToGroup(number, groupId, req.Members)
if err != nil {
log.Info("ERR NOT NULL")
switch err.(type) {
case *client.NotFoundError:
c.JSON(404, Error{Msg: err.Error()})

View File

@ -410,7 +410,7 @@ func (s *SignalClient) GetSignalCliMode() SignalCliMode {
return s.signalCliMode
}
func (s *SignalClient) Init(maxRetries int) error {
func (s *SignalClient) Init() error {
s.signalCliApiConfig = utils.NewSignalCliApiConfig()
err := s.signalCliApiConfig.Load(s.signalCliApiConfigPath)
if err != nil {
@ -427,7 +427,7 @@ func (s *SignalClient) Init(maxRetries int) error {
tcpPortsNumberMapping := s.jsonRpc2ClientConfig.GetTcpPortsForNumbers()
for number, tcpPort := range tcpPortsNumberMapping {
s.jsonRpc2Clients[number] = NewJsonRpc2Client(s.signalCliApiConfig, number)
err := s.jsonRpc2Clients[number].Dial("127.0.0.1:"+strconv.FormatInt(tcpPort, 10), maxRetries)
err := s.jsonRpc2Clients[number].Dial("127.0.0.1:" + strconv.FormatInt(tcpPort, 10))
if err != nil {
return err
}
@ -1349,7 +1349,7 @@ func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) {
}
pendingMembers = append(pendingMembers, identifier)
}
groupEntry.PendingInvites = pendingMembers
groupEntry.PendingRequests = pendingMembers
requestingMembers := []string{}
for _, val := range signalCliGroupEntry.RequestingMembers {
@ -1359,7 +1359,7 @@ func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) {
}
requestingMembers = append(requestingMembers, identifier)
}
groupEntry.PendingRequests = requestingMembers
groupEntry.PendingInvites = requestingMembers
admins := []string{}
for _, val := range signalCliGroupEntry.Admins {
@ -2705,6 +2705,7 @@ func (s *SignalClient) ListContacts(number string, allRecipients bool, recipient
return resp, nil
}
func (s *SignalClient) SetPin(number string, registrationLockPin string) error {
if s.signalCliMode == JsonRpc {
type Request struct {

View File

@ -2,14 +2,14 @@ package client
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"net"
"net/http"
"strconv"
"sync"
"time"
"net/http"
"bytes"
"strconv"
"github.com/bbernhard/signal-cli-rest-api/utils"
uuid "github.com/gofrs/uuid"
@ -60,11 +60,11 @@ type JsonRpc2Client struct {
conn net.Conn
receivedResponsesById map[string]chan JsonRpc2MessageResponse
receivedMessagesChannels map[string]chan JsonRpc2ReceivedMessage
lastTimeErrorMessageSent time.Time
signalCliApiConfig *utils.SignalCliApiConfig
number string
receivedMessagesMutex sync.Mutex
receivedResponsesMutex sync.Mutex
address string
}
func NewJsonRpc2Client(signalCliApiConfig *utils.SignalCliApiConfig, number string) *JsonRpc2Client {
@ -76,24 +76,10 @@ func NewJsonRpc2Client(signalCliApiConfig *utils.SignalCliApiConfig, number stri
}
}
func (r *JsonRpc2Client) Dial(address string, maxRetries int) error {
func (r *JsonRpc2Client) Dial(address string) error {
var err error
r.address = address
connected := false
for i := 0; i < maxRetries; i++ {
r.conn, err = net.Dial("tcp", address)
if err != nil {
log.Info("Waiting for signal-cli to start up in daemon mode...")
time.Sleep(2 * time.Second)
continue
}
connected = true
log.Info("Successfully connected to signal-cli in daemon mode")
break
}
if !connected {
return err
}
@ -221,14 +207,11 @@ func (r *JsonRpc2Client) ReceiveData(number string, receiveWebhookUrl string) {
for {
str, err := connbuf.ReadString('\n')
if err != nil {
log.Error("Lost connection to signal-cli...attempting to reconnect (", err.Error(), ")")
r.conn.Close()
err = r.Dial(r.address, 15)
if err != nil {
log.Fatal("Unable to reconnect to signal-cli: ", err.Error(), "...aborting")
elapsed := time.Since(r.lastTimeErrorMessageSent)
if (elapsed) > time.Duration(5*time.Minute) { //avoid spamming the log file and only log the message at max every 5 minutes
log.Error("Couldn't read data for number ", number, ": ", err.Error(), ". Is the number properly registered?")
r.lastTimeErrorMessageSent = time.Now()
}
connbuf = bufio.NewReader(r.conn)
log.Info("Successfully reconnected to signal-cli")
continue
}
log.Debug("json-rpc received data: ", str)
@ -265,7 +248,7 @@ func (r *JsonRpc2Client) ReceiveData(number string, receiveWebhookUrl string) {
}
}
} else {
log.Warn("Received unparsable message: ", str)
log.Error("Received unparsable message: ", str)
}
}
}

View File

@ -163,7 +163,7 @@ func main() {
jsonRpc2ClientConfigPathPath := *signalCliConfig + "/jsonrpc2.yml"
signalCliApiConfigPath := *signalCliConfig + "/api-config.yml"
signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir, signalCliMode, jsonRpc2ClientConfigPathPath, signalCliApiConfigPath, webhookUrl)
err = signalClient.Init(15)
err = signalClient.Init()
if err != nil {
log.Fatal("Couldn't init Signal Client: ", err.Error())
}

View File

@ -14,7 +14,7 @@ import (
const supervisorctlConfigTemplate = `
[program:%s]
process_name=%s
command=signal-cli --output=json --config %s%s daemon %s%s --tcp 127.0.0.1:%d
command=bash -c "nc -l -p %d <%s | signal-cli --output=json --config %s%s jsonRpc%s%s >%s"
autostart=true
autorestart=true
startretries=10
@ -96,7 +96,7 @@ func main() {
supervisorctlConfigFilename := "/etc/supervisor/conf.d/" + "signal-cli-json-rpc-1.conf"
supervisorctlConfig := fmt.Sprintf(supervisorctlConfigTemplate, supervisorctlProgramName, supervisorctlProgramName,
signalCliConfigDir, trustNewIdentities, signalCliIgnoreAttachments, signalCliIgnoreStories, tcpPort,
tcpPort, fifoPathname, signalCliConfigDir, trustNewIdentities, signalCliIgnoreAttachments, signalCliIgnoreStories, fifoPathname,
supervisorctlProgramName, supervisorctlProgramName)
err = ioutil.WriteFile(supervisorctlConfigFilename, []byte(supervisorctlConfig), 0644)