Skip to content

Commit e4f8c69

Browse files
committed
feat: add support to send rpc commands via topic
1 parent b80baea commit e4f8c69

File tree

4 files changed

+100
-77
lines changed

4 files changed

+100
-77
lines changed

README.md

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ Docker image to send and receive messages for the [Signal](https://signal.org/)
3232
3. Send and receive messages:
3333
```sh
3434
$ mosquitto_sub -v -h broker -t 'signal/#' &
35-
signal/receive/%2B491713920000 Incoming message
36-
$ mosquitto_pub -v -h broker -t signal/send/%2B491713920000 -m 'Outgoing message'
37-
signal/send/%2B491713920000 Outgoing message
35+
signal/in/%2B491713920000 Incoming message
36+
$ mosquitto_pub -v -h broker -t signal/out/send/recipient/%2B491713920000 -m 'Outgoing message'
37+
signal/out/send/recipient/%2B491713920000 Outgoing message
3838
```
3939

4040
## Requirements
@@ -86,64 +86,81 @@ Characters with a special meaning in the context of MQTT, base64 and percent-enc
8686

8787

8888
#### Send a text message
89-
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>/<PHONE_NUMBER>`
89+
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>/send/recipient/<PHONE_NUMBER>`
9090
* Example:
9191
```sh
92-
$ mosquitto_pub -h broker -t signal/send/%2B491713920000 -m 'Outgoing message'
92+
$ mosquitto_pub -h broker -t signal/out/send/recipient/%2B491713920000 -m 'Outgoing message'
9393
```
9494
The text _Outgoing message_ is sent to the phone.
9595

96+
#### Send a text message to a group
97+
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>/send/groupId/<GROUP_ID>`
98+
* Example:
99+
```sh
100+
$ mosquitto_pub -h broker -t signal/out/send/groupId/LS0%2BYWRtaW5zPz8%2FCg%3D%3D -m 'Outgoing message'
101+
```
102+
The text _Outgoing message_ is sent to the group _Admins_.
103+
104+
#### Send a JSON-RPC command
105+
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>/<METHOD>[/PARAM_NAME/PARAM_VALUE]...`
106+
* Example:
107+
```sh
108+
$ mosquitto_pub -h broker -t signal/out/send/recipient/%2B491713920000 -m 'Outgoing message'
109+
```
110+
The text _Outgoing message_ is sent to the phone.
111+
* Example:
112+
```sh
113+
$ mosquitto_pub -h broker -t signal/out/send/recipient/%2B491713920000/quoteAuthor/%2B491713920000/quoteTimestamp/1577882096000 -m 'Outgoing message'
114+
```
115+
The text _Outgoing message_ is sent to the phone quoting a message sent from the phone at timestamp 1577882096000.
116+
117+
#### Send a JSON-RPC message
118+
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>`
119+
* Example:
120+
```sh
121+
$ mosquitto_pub -h broker -t signal/out -m '{"jsonrpc":"2.0","method":"send","params":{"recipient":["+491713920000"],"message":"Outgoing message"}}'
122+
```
123+
The text _Outgoing message_ is sent to the phone.
124+
125+
96126
#### Receive a text message
97127
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>/timestamp/<TIMESTAMP>`
98128
* Example:
99129
The text _Incoming message_ is sent from the phone to `+493023125000`.
100130
```sh
101131
$ mosquitto_sub -v -h broker -t signal/#
102-
signal/receive/%2B491713920000/timestamp/1577882096000 Incoming message
132+
signal/in/%2B491713920000/timestamp/1577882096000 Incoming message
103133
```
104134

105135
#### Receive a text message without timestamp
106-
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>`
107136
* Required configuration option: `MQTT_PUBLISH_PER_SOURCE_TIMESTAMP: "false"`
137+
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>`
108138
* Example:
109139
The text _Incoming message_ is sent from the phone to `+493023125000`.
110140
```sh
111141
$ mosquitto_sub -v -h broker -t signal/#
112-
signal/receive/%2B491713920000 Incoming message
142+
signal/in/%2B491713920000 Incoming message
113143
```
114144

115145
#### Receive a message in JSON format
116-
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>`
117146
* Required configuration option: `MQTT_PUBLISH_PER_SOURCE_AS_JSON: "true"`
147+
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>`
118148
* Note: To suppress publishing of the same message in text format, additionally set `MQTT_PUBLISH_PER_SOURCE_AS_TEXT: "false"`
119149
* Example:
120150
The text _Incoming message_ is sent from the phone to `+493023125000`.
121151
```sh
122152
$ mosquitto_sub -v -h broker -t signal/#
123-
signal/receive/%2B491713920000 {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882096000,"dataMessage":{"timestamp":1577882096000,"message":"Incoming message","expiresInSeconds":0,"viewOnce":false}},"account":"+493023125000","subscription":0}}
124-
signal/receive/%2B491713920000/timestamp/1577882096000 Incoming message
153+
signal/in/%2B491713920000 {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882096000,"dataMessage":{"timestamp":1577882096000,"message":"Incoming message","expiresInSeconds":0,"viewOnce":false}},"account":"+493023125000","subscription":0}}
154+
signal/in/%2B491713920000/timestamp/1577882096000 Incoming message
125155
```
126156

127-
#### Send a text message to a group
128-
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>/group/<GROUP_ID>`
129-
* Note: The group-id must be percent-encoded.
130-
A group-id (which is base64 encoded) may be converted to percent encoding by applying the following replacements:
131-
- `+` (plus) becomes `%2B`
132-
- `/` (slash) becomes `%2F`
133-
- `=` (equals) becomes `%3D`
134-
* Example:
135-
```sh
136-
$ mosquitto_pub -h broker -t signal/send/group/LS0%2BYWRtaW5zPz8%2FCg%3D%3D -m 'Outgoing message'
137-
```
138-
The text _Outgoing message_ is sent to the group _Admins_.
139-
140157
#### Receive a text message from a group
141158
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>/<PHONE_NUMBER>/timestamp/<TIMESTAMP>/group/<GROUP_ID>`
142159
* Example:
143160
The text _Incoming message_ is sent from the phone to the group _Admins_.
144161
```sh
145162
$ mosquitto_sub -v -h broker -t signal/#
146-
signal/receive/%2B491713920000/timestamp/1577882096000/group/LS0%2BYWRtaW5zPz8%2FCg%3D%3D Incoming message
163+
signal/in/%2B491713920000/timestamp/1577882096000/group/LS0%2BYWRtaW5zPz8%2FCg%3D%3D Incoming message
147164
```
148165

149166
#### Receive a quotation message
@@ -152,7 +169,7 @@ Characters with a special meaning in the context of MQTT, base64 and percent-enc
152169
The text _Incoming quote_ is sent from the phone as quotation to the message _Outgoing message_ from above.
153170
```sh
154171
$ mosquitto_sub -v -h broker -t signal/#
155-
signal/receive/%2B491713920000/timestamp/1577882100000/quote/1577882096000 Incoming quote
172+
signal/in/%2B491713920000/timestamp/1577882100000/quote/1577882096000 Incoming quote
156173
```
157174
* Note: the combination of group and quotation is possible within a single message.
158175

@@ -162,17 +179,10 @@ Characters with a special meaning in the context of MQTT, base64 and percent-enc
162179
The emoji 👍 is sent from the phone as reaction to the message _Outgoing message_ from above.
163180
```sh
164181
$ mosquitto_sub -v -h broker -t signal/#
165-
signal/receive/%2B491713920000/timestamp/1577882100000/reaction/1577882096000 👍
182+
signal/in/%2B491713920000/timestamp/1577882100000/reaction/1577882096000 👍
166183
```
167184
* Note: the combination of group and reaction is possible within a single message.
168185

169-
#### Send a JSON-RPC message
170-
* Topic: `<TOPIC_PREFIX>/<MQTT_SUBSCRIBE_TOPIC>`
171-
* Example:
172-
```sh
173-
$ mosquitto_pub -h broker -t signal/send -m '{"jsonrpc":"2.0","method":"send","params":{"recipient":["+491713920000"],"message":"Outgoing message"}}'
174-
```
175-
The text _Outgoing message_ is sent to the phone.
176186

177187
#### Receive JSON-RPC messages
178188
* Topic: `<TOPIC_PREFIX>/<MQTT_PUBLISH_TOPIC>`
@@ -181,19 +191,19 @@ Characters with a special meaning in the context of MQTT, base64 and percent-enc
181191
```sh
182192
$ mosquitto_sub -v -h broker -t 'signal/#' &
183193
# The user starts to type 'Incoming message' on the phone
184-
signal/receive {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882080000,"typingMessage":{"action":"STARTED","timestamp":1577882080000}},"account":"+493023125000","subscription":0}}
194+
signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882080000,"typingMessage":{"action":"STARTED","timestamp":1577882080000}},"account":"+493023125000","subscription":0}}
185195
# The text 'Incoming message' is completed
186-
signal/receive {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882090000,"typingMessage":{"action":"STOPPED","timestamp":1577882090000}},"account":"+493023125000","subscription":0}}
196+
signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882090000,"typingMessage":{"action":"STOPPED","timestamp":1577882090000}},"account":"+493023125000","subscription":0}}
187197
# The message is sent to +493023125000
188-
signal/receive {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882096000,"dataMessage":{"timestamp":1577882096000,"message":"Incoming message","expiresInSeconds":0,"viewOnce":false}},"account":"+493023125000","subscription":0}}
189-
signal/receive/%2B491713920000 Incoming message
198+
signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882096000,"dataMessage":{"timestamp":1577882096000,"message":"Incoming message","expiresInSeconds":0,"viewOnce":false}},"account":"+493023125000","subscription":0}}
199+
signal/in/%2B491713920000 Incoming message
190200
191-
$ mosquitto_pub -h broker -t signal/send/%2B491713920000 -m 'Outgoing message'
192-
signal/send/%2B491713920000 Outgoing message
201+
$ mosquitto_pub -h broker -t signal/out/send/recipient/%2B491713920000 -m 'Outgoing message'
202+
signal/out/send/recipient/%2B491713920000 Outgoing message
193203
# The message was delivered to mobile phone +491713920000
194-
signal/receive {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882097000,"receiptMessage":{"when":1577882097000,"isDelivery":true,"isRead":false,"isViewed":false,"timestamps":[1577882098000]}},"account":"+493023125000","subscription":0}}
204+
signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882097000,"receiptMessage":{"when":1577882097000,"isDelivery":true,"isRead":false,"isViewed":false,"timestamps":[1577882098000]}},"account":"+493023125000","subscription":0}}
195205
# The message was read on mobile phone +491713920000
196-
signal/receive {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882099000,"receiptMessage":{"when":1577882099000,"isDelivery":false,"isRead":true,"isViewed":false,"timestamps":[1577882098000]}},"account":"+493023125000","subscription":0}}
206+
signal/in {"jsonrpc":"2.0","method":"receive","params":{"envelope":{"source":"+491713920000","sourceNumber":"+491713920000","sourceUuid":"3689ed97-01b2-4fa5-8ed8-18174ad5cf15","sourceName":"Sally Sender","sourceDevice":1,"timestamp":1577882099000,"receiptMessage":{"when":1577882099000,"isDelivery":false,"isRead":true,"isViewed":false,"timestamps":[1577882098000]}},"account":"+493023125000","subscription":0}}
197207
```
198208

199209
#### Run a signal-cli command
@@ -216,14 +226,14 @@ The configuration is based on environment variables.
216226
|--------|-----------|-----|-------|-------
217227
|`MQTT_TOPIC_PREFIX`|Prefix for MQTT topics|[Topic names](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106)|`signal`|`chats`
218228
|`MQTT_PUBLISH_OPTIONS`|MQTT publish options|All options [supported by `mosquitto_pub`](https://mosquitto.org/man/mosquitto_pub-1.html) except `-t` and `-m`|_none_|`-h broker -id signal-publisher`
219-
|`MQTT_PUBLISH_TOPIC`|MQTT topic for publishing messages received from Signal|[Topic names](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106)|`${MQTT_TOPIC_PREFIX}/receive`|`chats/from`
229+
|`MQTT_PUBLISH_TOPIC`|MQTT topic for publishing messages received from Signal|[Topic names](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106)|`${MQTT_TOPIC_PREFIX}/in`|`chats/from`
220230
|`MQTT_PUBLISH_JSON_RESPONSE`|Publish all json-rpc responses from signal-cli?|`true` / `false`|`false`|`true`
221231
|`MQTT_PUBLISH_PER_SOURCE`|Publish incoming messages to a separate MQTT topic per source number?|`true`/ `false`|`true`|`false`
222232
|`MQTT_PUBLISH_PER_SOURCE_AS_JSON`|Publish incoming messages in JSON format?|`true` / `false`|`false`|`true`
223233
|`MQTT_PUBLISH_PER_SOURCE_AS_TEXT`|Publish incoming messages as plain text? When enabled, metadata properties (e.g. timestamp, group) are added to the topic.|`true` / `false`|`true`|`false`
224234
|`MQTT_PUBLISH_PER_SOURCE_TIMESTAMP`|Add timestamp to MQTT topic of incoming messages? This is useful to associate a quotation or reaction to its original message.|`true` / `false`|`true`|`false`
225235
|`MQTT_SUBSCRIBE_OPTIONS`|MQTT subscribe options|All options [supported by `mosquitto_sub`](https://mosquitto.org/man/mosquitto_sub-1.html) except `-t` and formatting-related options like `-F` & `-N`|_none_|`-h broker -i signal-subscriber`
226-
|`MQTT_SUBSCRIBE_TOPIC`|MQTT topic to listen for messages that are sent to a Signal receiver|[Topic names](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106)|`${MQTT_TOPIC_PREFIX}/send`|`chats/to`
236+
|`MQTT_SUBSCRIBE_TOPIC`|MQTT topic to listen for messages that are sent to a Signal receiver|[Topic names](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106)|`${MQTT_TOPIC_PREFIX}/out`|`chats/to`
227237
|`MQTT_LOG`|Enable logging via MQTT?|`true` / `false`|`false`|`true`
228238
|`MQTT_LOG_TOPIC`|MQTT topic to publish the log to|`${MQTT_TOPIC_PREFIX}/log`|`chats/logs`
229239
|`SIGNAL_ACCOUNT`|Phone number of the signal account|International phone number format with leading `+`|Account from signal-cli configuration|`+493023125000`
@@ -238,7 +248,7 @@ This section contains example configurations to send and receive Signal messages
238248
define mosquitto MQTT2_CLIENT localhost:1883
239249

240250
define mqtt_signal MQTT2_DEVICE
241-
attr mqtt_signal readingList signal/receive/.* { return { 'from_'.(split('/', $TOPIC))[-1] => $EVTPART0 } }
251+
attr mqtt_signal readingList signal/in/.* { return { 'from_'.(split('/', $TOPIC))[-1] => $EVTPART0 } }
242252
```
243253
244254
## References

image/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
FROM alpine
22
RUN apk --no-cache add jq mosquitto-clients gcompat
33
RUN apk --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing add signal-cli
4-
COPY signal-mqtt /opt/
4+
COPY signal-mqtt url_decode.jq /opt/
55
ENV XDG_DATA_HOME=/home/.local/share
6+
WORKDIR /opt
67
CMD /opt/signal-mqtt

image/signal-mqtt

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ set -eu
66

77
signal_data="${XDG_DATA_HOME:-${HOME}/.local/share}/signal-cli/data"
88
MQTT_TOPIC_PREFIX="${MQTT_TOPIC_PREFIX:-signal}"
9-
MQTT_PUBLISH_TOPIC="${MQTT_PUBLISH_TOPIC:-${MQTT_TOPIC_PREFIX}/receive}"
10-
MQTT_SUBSCRIBE_TOPIC="${MQTT_SUBSCRIBE_TOPIC:-${MQTT_TOPIC_PREFIX}/send}"
9+
MQTT_PUBLISH_TOPIC="${MQTT_PUBLISH_TOPIC:-${MQTT_TOPIC_PREFIX}/in}"
10+
MQTT_SUBSCRIBE_TOPIC="${MQTT_SUBSCRIBE_TOPIC:-${MQTT_TOPIC_PREFIX}/out}"
1111
MQTT_LOG_TOPIC="${MQTT_LOG_TOPIC:-${MQTT_TOPIC_PREFIX}/log}"
1212
SIGNAL_ACCOUNT="${SIGNAL_ACCOUNT:-$(jq -r '.accounts[0].number' <"${signal_data}/accounts.json")}"
1313

@@ -33,21 +33,21 @@ _publish() {
3333
#######################################
3434
# Build a JSON-RPC object.
3535
# Arguments:
36-
# 1: Method
36+
# 1: Topic in the form `method[/key/value]...`
3737
# 2: Message
38-
# 3: Name of a method parameter
39-
# 4: Value of the method parameter
4038
# Outputs:
4139
# JSON-RPC object
4240
#######################################
43-
_jsonrpc_object() {
44-
local method="${1}" message="${2}" param_name="${3}" param_value="${4}"
45-
jq --null-input --compact-output \
46-
--arg method "${method}" \
47-
--arg message "${message}" \
48-
--arg param_name "${param_name}" \
49-
--arg param_value "${param_value}" \
50-
'{jsonrpc:"2.0", method:$method, params:{($param_name):$param_value, message:$message}}'
41+
to_jsonrpc() {
42+
local topic="${1}" message="${2}"
43+
printf '%s\n' "${topic}" | jq --raw-input --compact-output --arg message "${message}" '
44+
include "url_decode";
45+
split("/") + ["message", $message] | {
46+
jsonrpc: "2.0",
47+
method: .[0],
48+
params: [. as $v | range(1; length; 2) | {($v[.]): $v[(.+1)] | url_decode}] | add
49+
}
50+
'
5151
}
5252

5353
#######################################
@@ -61,17 +61,6 @@ percent_encode() {
6161
printf '%s' "${1}" | jq -sRr @uri
6262
}
6363

64-
#######################################
65-
# Decode a text from percent-encoding.
66-
# Arguments:
67-
# 1: Text in percent-encoding
68-
# Outputs:
69-
# Decoded Text
70-
#######################################
71-
percent_decode() {
72-
printf '%s' "${1}" | printf '%b\n' "$(sed -E -e 's/\+/ /g' -e 's/%([0-9a-fA-F]{2})/\\x\1/g')"
73-
}
74-
7564
#######################################
7665
# Write one or more arguments to the log
7766
# Arguments:
@@ -148,15 +137,10 @@ mqtt_subscribe() {
148137
| xargs mosquitto_sub -t "${MQTT_SUBSCRIBE_TOPIC}/#" -v \
149138
| while read -r topic payload; do
150139
case "${topic}" in
151-
"${MQTT_SUBSCRIBE_TOPIC}") printf '%s\n' "${payload}" ;;
152-
"${MQTT_SUBSCRIBE_TOPIC}"/group/*) method=send && name=groupId ;;
153-
"${MQTT_SUBSCRIBE_TOPIC}"/*) method=send && name=recipient ;;
140+
"${MQTT_SUBSCRIBE_TOPIC}") printf '%s\n' "${payload}" ;;
141+
"${MQTT_SUBSCRIBE_TOPIC}"/*) to_jsonrpc "${topic##${MQTT_SUBSCRIBE_TOPIC}/}" "${payload}" ;;
154142
*) log "Ignoring message on unsupported topic ${topic}" ;;
155143
esac
156-
if [ "${method-}" ]; then
157-
_jsonrpc_object "${method}" "${payload}" "${name}" "$(percent_decode "${topic##*/}")"
158-
fi
159-
unset method name
160144
done
161145
}
162146

image/url_decode.jq

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#
2+
# This module is required to decode a percent-encoded string
3+
# until https://github.com/stedolan/jq/issues/2261 is resolved.
4+
#
5+
# Source: https://rosettacode.org/wiki/URL_decoding#jq
6+
#
7+
def url_decode:
8+
# The helper function converts the input string written in the given
9+
# "base" to an integer
10+
def to_i(base):
11+
explode
12+
| reverse
13+
| map(if 65 <= . and . <= 90 then . + 32 else . end) # downcase
14+
| map(if . > 96 then . - 87 else . - 48 end) # "a" ~ 97 => 10 ~ 87
15+
| reduce .[] as $c
16+
# base: [power, ans]
17+
([1,0]; (.[0] * base) as $b | [$b, .[1] + (.[0] * $c)]) | .[1];
18+
19+
. as $in
20+
| length as $length
21+
| [0, ""] # i, answer
22+
| until ( .[0] >= $length;
23+
.[0] as $i
24+
| if $in[$i:$i+1] == "%"
25+
then [ $i + 3, .[1] + ([$in[$i+1:$i+3] | to_i(16)] | implode) ]
26+
else [ $i + 1, .[1] + $in[$i:$i+1] ]
27+
end)
28+
| .[1]; # answer

0 commit comments

Comments
 (0)