Merge branch 'generated' into 'main'
Generated client for documented parts of protocol See merge request signald/signald-go!2
This commit is contained in:
commit
10ff70408d
24 changed files with 1965 additions and 137 deletions
|
@ -2,25 +2,27 @@ stages:
|
|||
- build
|
||||
|
||||
lint:
|
||||
image: nixery.dev/shell/go/golangci-lint
|
||||
image: nixery.dev/shell/diffutils/go/golangci-lint
|
||||
stage: build
|
||||
before_script:
|
||||
- cp /share/go/bin/go /bin && mkdir /tmp # fix weirdness from nixery image
|
||||
- mkdir -p /go/src/git.callpipe.com/finn/signald-go
|
||||
- cp -r * /go/src/git.callpipe.com/finn/signald-go
|
||||
- cd /go/src/git.callpipe.com/finn/signald-go
|
||||
- mkdir -p /go/src/src/gitlab.com/signald/signald-go
|
||||
- cp -r * /go/src/src/gitlab.com/signald/signald-go
|
||||
- cd /go/src/src/gitlab.com/signald/signald-go
|
||||
script:
|
||||
- golangci-lint run
|
||||
- go mod tidy
|
||||
- diff --color=always go.mod "${CI_PROJECT_DIR}/go.mod"
|
||||
- diff --color=always go.sum "${CI_PROJECT_DIR}/go.sum"
|
||||
|
||||
build:
|
||||
stage: build
|
||||
image: golang:latest
|
||||
before_script:
|
||||
- mkdir -p /go/src/git.callpipe.com/finn/signald-go
|
||||
- cp -r * /go/src/git.callpipe.com/finn/signald-go
|
||||
- cd /go/src/git.callpipe.com/finn/signald-go
|
||||
- mkdir -p /go/src/gitlab.com/signald/signald-go
|
||||
- cp -r * /go/src/gitlab.com/signald/signald-go
|
||||
- cd /go/src/gitlab.com/signald/signald-go
|
||||
script:
|
||||
- go get ./... # TODO: Improve how dependencies are handled
|
||||
- go build -o "${CI_PROJECT_DIR}/signald-cli" ./cmd/signald-cli
|
||||
artifacts:
|
||||
paths:
|
||||
|
|
12
Makefile
Normal file
12
Makefile
Normal file
|
@ -0,0 +1,12 @@
|
|||
signald-cli: signald/client-protocol
|
||||
go build -o signald-cli ./cmd/signald-cli
|
||||
|
||||
protocol.json:
|
||||
echo '{"type": "protocol", "version": "v1alpha1"}' | nc -q0 -U /var/run/signald/signald.sock | jq 'select(.type == "protocol").data' > protocol.json
|
||||
|
||||
signald/client-protocol: protocol.json tools/generator/*
|
||||
go run ./tools/generator < protocol.json
|
||||
|
||||
clean:
|
||||
rm -rf protocol.json
|
||||
rm -rf signald/client-protocol/*
|
|
@ -24,7 +24,7 @@ import (
|
|||
"github.com/mdp/qrterminal"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.callpipe.com/finn/signald-go/signald"
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
)
|
||||
|
||||
var uriOrQR bool
|
||||
|
@ -36,7 +36,7 @@ var linkCmd = &cobra.Command{
|
|||
Long: `Get a URI or QR code to link to an existing Signal account`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
requestID := fmt.Sprint("signald-cli-", rand.Intn(1000))
|
||||
err := s.SendRequest(signald.Request{
|
||||
err := s.RawRequest(v0.LegacyRequest{
|
||||
Type: "link",
|
||||
ID: requestID,
|
||||
})
|
||||
|
@ -44,7 +44,7 @@ var linkCmd = &cobra.Command{
|
|||
log.Fatal("error sending request: ", err)
|
||||
}
|
||||
|
||||
c := make(chan signald.Response)
|
||||
c := make(chan v0.LegacyResponse)
|
||||
go s.Listen(c)
|
||||
for {
|
||||
message := <-c
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.callpipe.com/finn/signald-go/signald"
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
)
|
||||
|
||||
// listAccountsCmd represents the listAccounts command
|
||||
|
@ -32,7 +32,7 @@ var listAccountsCmd = &cobra.Command{
|
|||
Long: `Prints a list of all users to stdout.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
requestID := fmt.Sprint("signald-cli-", rand.Intn(1000))
|
||||
err := s.SendRequest(signald.Request{
|
||||
err := s.RawRequest(v0.LegacyRequest{
|
||||
Type: "list_accounts",
|
||||
ID: requestID,
|
||||
})
|
||||
|
@ -40,7 +40,7 @@ var listAccountsCmd = &cobra.Command{
|
|||
log.Fatal("error sending request: ", err)
|
||||
}
|
||||
|
||||
c := make(chan signald.Response)
|
||||
c := make(chan v0.LegacyResponse)
|
||||
go s.Listen(c)
|
||||
for {
|
||||
message := <-c
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"git.callpipe.com/finn/signald-go/signald"
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
)
|
||||
|
||||
// listGroupsCmd represents the listGroups command
|
||||
|
@ -32,7 +32,7 @@ var listGroupsCmd = &cobra.Command{
|
|||
Long: `Prints a list of all groups the user is in to stdout.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
requestID := fmt.Sprint("signald-cli-", rand.Intn(1000))
|
||||
err := s.SendRequest(signald.Request{
|
||||
err := s.RawRequest(v0.LegacyRequest{
|
||||
Type: "list_groups",
|
||||
Username: username,
|
||||
ID: requestID,
|
||||
|
@ -41,7 +41,7 @@ var listGroupsCmd = &cobra.Command{
|
|||
log.Fatal("error sending request: ", err)
|
||||
}
|
||||
|
||||
c := make(chan signald.Response)
|
||||
c := make(chan v0.LegacyResponse)
|
||||
go s.Listen(c)
|
||||
for {
|
||||
message := <-c
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"git.callpipe.com/finn/signald-go/signald"
|
||||
"gitlab.com/signald/signald-go/signald"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
|
||||
"git.callpipe.com/finn/signald-go/signald"
|
||||
"git.callpipe.com/finn/signald-go/signald/client-protocol/v1"
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v1"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -39,13 +40,10 @@ var sendCmd = &cobra.Command{
|
|||
Short: "send a message to another user or group",
|
||||
Long: `send a message to another user or group on Signal`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
request := signald.Request{
|
||||
Type: "send",
|
||||
Username: username,
|
||||
}
|
||||
request := v1.SendRequest{Username: username}
|
||||
|
||||
if toUser != "" {
|
||||
request.RecipientAddress = v1.JsonAddress{Number: toUser}
|
||||
request.RecipientAddress = &v1.JsonAddress{Number: toUser}
|
||||
} else if toGroup != "" {
|
||||
request.RecipientGroupID = toGroup
|
||||
} else {
|
||||
|
@ -57,25 +55,16 @@ var sendCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
if attachment != "" {
|
||||
request.AttachmentFilenames = []string{attachment}
|
||||
request.Attachments = []*v0.JsonAttachment{{Filename: attachment}}
|
||||
}
|
||||
err := s.SendRequest(request)
|
||||
go s.Listen(nil)
|
||||
response, err := request.Submit(s)
|
||||
if err != nil {
|
||||
log.Fatal("error sending request: ", err)
|
||||
log.Fatal("error submitting request to signald: ", err)
|
||||
}
|
||||
|
||||
timeout := 10
|
||||
|
||||
// Wait for the response
|
||||
c := make(chan signald.Response)
|
||||
|
||||
go s.Listen(c)
|
||||
select {
|
||||
case <-c:
|
||||
log.Println("Ok.")
|
||||
case <-time.After(1 * time.Second):
|
||||
// But timeout after a while
|
||||
log.Fatalf("Timeout after %d seconds\n", timeout)
|
||||
err = json.NewEncoder(os.Stdout).Encode(response)
|
||||
if err != nil {
|
||||
log.Fatal("error encoding output ", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
49
cmd/signald-cli/cmd/version.go
Normal file
49
cmd/signald-cli/cmd/version.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Copyright © 2018 Finn Herzfeld <finn@janky.solutions>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v1"
|
||||
)
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "print the signald version",
|
||||
Long: `print the signald version`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
go s.Listen(nil)
|
||||
r := v1.VersionRequest{}
|
||||
response, err := r.Submit(s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = json.NewEncoder(os.Stdout).Encode(response)
|
||||
if err != nil {
|
||||
log.Fatal("error encoding output ", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(versionCmd)
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
package main
|
||||
|
||||
import "git.callpipe.com/finn/signald-go/cmd/signald-cli/cmd"
|
||||
import "gitlab.com/signald/signald-go/cmd/signald-cli/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
|
|
7
go.mod
7
go.mod
|
@ -1,9 +1,14 @@
|
|||
module git.callpipe.com/finn/signald-go
|
||||
module gitlab.com/signald/signald-go
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/mdp/qrterminal v1.0.1
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/viper v1.7.0
|
||||
github.com/stretchr/testify v1.4.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0 // indirect
|
||||
)
|
||||
|
|
11
go.sum
11
go.sum
|
@ -43,6 +43,8 @@ github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8
|
|||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
|
@ -184,6 +186,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
|
@ -256,6 +260,9 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
|
@ -306,6 +313,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
|
@ -315,6 +324,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
945
protocol.json
Normal file
945
protocol.json
Normal file
|
@ -0,0 +1,945 @@
|
|||
{
|
||||
"doc_version": "v1alpha1",
|
||||
"version": {
|
||||
"name": "signald",
|
||||
"version": "0.10.0+git2020-12-06rcea5cb72.51",
|
||||
"branch": "refactor-client-request-handling",
|
||||
"commit": "cea5cb720355afdca460aa30257bdd1317494c7b"
|
||||
},
|
||||
"info": "This document describes objects that may be used when communicating with signald. If this document lacks something you need to generate a client, please open an issue (https://gitlab.com/thefinn93/signald/-/issues/new). This is an initial proposal for the format, and I expect to change it before finalizing it. If it workswell, I hope to slowly move things out of the legacy request types.",
|
||||
"types": {
|
||||
"v1": {
|
||||
"JsonMessageEnvelope": {
|
||||
"fields": {
|
||||
"username": {
|
||||
"type": "String"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "String"
|
||||
},
|
||||
"source": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"sourceDevice": {
|
||||
"type": "int"
|
||||
},
|
||||
"type": {
|
||||
"type": "String"
|
||||
},
|
||||
"relay": {
|
||||
"type": "String"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"timestampISO": {
|
||||
"type": "String"
|
||||
},
|
||||
"serverTimestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"serverDeliveredTimestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"hasLegacyMessage": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasContent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isUnidentifiedSender": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"dataMessage": {
|
||||
"type": "JsonDataMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"syncMessage": {
|
||||
"type": "JsonSyncMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"callMessage": {
|
||||
"type": "JsonCallMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"receipt": {
|
||||
"type": "JsonReceiptMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"typing": {
|
||||
"type": "JsonTypingMessage",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SendRequest": {
|
||||
"fields": {
|
||||
"username": {
|
||||
"type": "String"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"recipientGroupId": {
|
||||
"type": "String"
|
||||
},
|
||||
"messageBody": {
|
||||
"type": "String"
|
||||
},
|
||||
"attachments": {
|
||||
"list": true,
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
},
|
||||
"quote": {
|
||||
"type": "JsonQuote",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "Long"
|
||||
},
|
||||
"mentions": {
|
||||
"list": true,
|
||||
"type": "JsonMention",
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SendResponse": {
|
||||
"fields": {
|
||||
"results": {
|
||||
"list": true,
|
||||
"type": "JsonSendMessageResult",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ReactRequest": {
|
||||
"fields": {
|
||||
"username": {
|
||||
"type": "String"
|
||||
},
|
||||
"recipientAddress": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"recipientGroupId": {
|
||||
"type": "String"
|
||||
},
|
||||
"reaction": {
|
||||
"type": "JsonReaction",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
},
|
||||
"doc": "react to a previous message"
|
||||
},
|
||||
"VersionRequest": {
|
||||
"fields": {}
|
||||
},
|
||||
"JsonVersionMessage": {
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"version": {
|
||||
"type": "String"
|
||||
},
|
||||
"branch": {
|
||||
"type": "String"
|
||||
},
|
||||
"commit": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonAddress": {
|
||||
"fields": {
|
||||
"number": {
|
||||
"type": "String",
|
||||
"doc": "An e164 phone number, starting with +. Currently the only available user-facing Signal identifier."
|
||||
},
|
||||
"uuid": {
|
||||
"type": "UUID",
|
||||
"doc": "A UUID, the unique identifier for a particular Signal account."
|
||||
},
|
||||
"relay": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonDataMessage": {
|
||||
"fields": {
|
||||
"timestamp": {
|
||||
"type": "long",
|
||||
"doc": "the (unix) timestamp that the message was sent at, according to the sender's device. This is used to uniquely identify this message for things like reactions and quotes."
|
||||
},
|
||||
"attachments": {
|
||||
"list": true,
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0",
|
||||
"doc": "files attached to the incoming message"
|
||||
},
|
||||
"body": {
|
||||
"type": "String",
|
||||
"doc": "the text body of the incoming message."
|
||||
},
|
||||
"group": {
|
||||
"type": "JsonGroupInfo",
|
||||
"version": "v1",
|
||||
"doc": "if the incoming message was sent to a v1 group, information about that group will be here"
|
||||
},
|
||||
"groupV2": {
|
||||
"type": "JsonGroupV2Info",
|
||||
"version": "v1",
|
||||
"doc": "is the incoming message was sent to a v2 group, basic identifying information about that group will be here. For full information, use list_groups"
|
||||
},
|
||||
"endSession": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"expiresInSeconds": {
|
||||
"type": "int",
|
||||
"doc": "the expiry timer on the incoming message. Clients should delete records of the message within this number of seconds"
|
||||
},
|
||||
"profileKeyUpdate": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"quote": {
|
||||
"type": "JsonQuote",
|
||||
"version": "v1",
|
||||
"doc": "if the incoming message is a quote or reply to another message, this will contain information about that message"
|
||||
},
|
||||
"contacts": {
|
||||
"list": true,
|
||||
"type": "SharedContact",
|
||||
"version": "v0",
|
||||
"doc": "if the incoming message has a shared contact, the contact's information will be here"
|
||||
},
|
||||
"previews": {
|
||||
"list": true,
|
||||
"type": "JsonPreview",
|
||||
"version": "v0",
|
||||
"doc": "if the incoming message has a link preview, information about that preview will be here"
|
||||
},
|
||||
"sticker": {
|
||||
"type": "JsonSticker",
|
||||
"version": "v0",
|
||||
"doc": "if the incoming message is a sticker, information about the sicker will be here"
|
||||
},
|
||||
"viewOnce": {
|
||||
"type": "boolean",
|
||||
"doc": "indicates the message is a view once message. View once messages typically include no body and a single image attachment. Official Signal clients will prevent the user from saving the image, and once the user has viewed the image once they will destroy the image."
|
||||
},
|
||||
"reaction": {
|
||||
"type": "JsonReaction",
|
||||
"version": "v1",
|
||||
"doc": "if the message adds or removes a reaction to another message, this will indicate what change is being made"
|
||||
},
|
||||
"remoteDelete": {
|
||||
"type": "RemoteDelete",
|
||||
"version": "v0",
|
||||
"doc": "if the inbound message is deleting a previously sent message, indicates which message should be deleted"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonSyncMessage": {
|
||||
"fields": {
|
||||
"sent": {
|
||||
"type": "JsonSentTranscriptMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"contacts": {
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
},
|
||||
"contactsComplete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"groups": {
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
},
|
||||
"blockedList": {
|
||||
"type": "JsonBlockedListMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"request": {
|
||||
"type": "String"
|
||||
},
|
||||
"readMessages": {
|
||||
"list": true,
|
||||
"type": "JsonReadMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"viewOnceOpen": {
|
||||
"type": "JsonViewOnceOpenMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"verified": {
|
||||
"type": "JsonVerifiedMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"configuration": {
|
||||
"type": "ConfigurationMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"stickerPackOperations": {
|
||||
"list": true,
|
||||
"type": "JsonStickerPackOperationMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"fetchType": {
|
||||
"type": "String"
|
||||
},
|
||||
"messageRequestResponse": {
|
||||
"type": "JsonMessageRequestResponseMessage",
|
||||
"version": "v1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonQuote": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
},
|
||||
"author": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"text": {
|
||||
"type": "String"
|
||||
},
|
||||
"attachments": {
|
||||
"list": true,
|
||||
"type": "JsonQuotedAttachment",
|
||||
"version": "v0"
|
||||
},
|
||||
"mentions": {
|
||||
"list": true,
|
||||
"type": "Mention",
|
||||
"version": "v0"
|
||||
}
|
||||
},
|
||||
"doc": "A quote is a reply to a previous message. ID is the sent time of the message being replied to"
|
||||
},
|
||||
"JsonMention": {
|
||||
"fields": {
|
||||
"uuid": {
|
||||
"type": "String"
|
||||
},
|
||||
"start": {
|
||||
"type": "int"
|
||||
},
|
||||
"length": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonSendMessageResult": {
|
||||
"fields": {
|
||||
"address": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"success": {
|
||||
"type": "Success",
|
||||
"version": "v0"
|
||||
},
|
||||
"networkFailure": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"unregisteredFailure": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"identityFailure": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonReaction": {
|
||||
"fields": {
|
||||
"emoji": {
|
||||
"type": "String",
|
||||
"doc": "the emoji to react with"
|
||||
},
|
||||
"remove": {
|
||||
"type": "boolean",
|
||||
"doc": "set to true to remove the reaction. requires emoji be set to previously reacted emoji"
|
||||
},
|
||||
"targetAuthor": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1",
|
||||
"doc": "the author of the message being reacted to"
|
||||
},
|
||||
"targetSentTimestamp": {
|
||||
"type": "long",
|
||||
"doc": "the client timestamp of the message being reacted to"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonGroupInfo": {
|
||||
"fields": {
|
||||
"groupId": {
|
||||
"type": "String"
|
||||
},
|
||||
"members": {
|
||||
"list": true,
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"name": {
|
||||
"type": "String"
|
||||
},
|
||||
"type": {
|
||||
"type": "String"
|
||||
},
|
||||
"avatarId": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonGroupV2Info": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "String"
|
||||
},
|
||||
"masterKey": {
|
||||
"type": "String"
|
||||
},
|
||||
"revision": {
|
||||
"type": "int"
|
||||
},
|
||||
"title": {
|
||||
"type": "String"
|
||||
},
|
||||
"timer": {
|
||||
"type": "int"
|
||||
},
|
||||
"members": {
|
||||
"list": true,
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"pendingMembers": {
|
||||
"list": true,
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"requestingMembers": {
|
||||
"list": true,
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"inviteLinkPassword": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonSentTranscriptMessage": {
|
||||
"fields": {
|
||||
"destination": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"expirationStartTimestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"message": {
|
||||
"type": "JsonDataMessage",
|
||||
"version": "v1"
|
||||
},
|
||||
"unidentifiedStatus": {
|
||||
"type": "Map"
|
||||
},
|
||||
"isRecipientUpdate": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonBlockedListMessage": {
|
||||
"fields": {
|
||||
"addresses": {
|
||||
"list": true,
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"groupIds": {
|
||||
"list": true,
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonReadMessage": {
|
||||
"fields": {
|
||||
"sender": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonViewOnceOpenMessage": {
|
||||
"fields": {
|
||||
"sender": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonVerifiedMessage": {
|
||||
"fields": {
|
||||
"destination": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"identityKey": {
|
||||
"type": "String"
|
||||
},
|
||||
"verified": {
|
||||
"type": "String"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonMessageRequestResponseMessage": {
|
||||
"fields": {
|
||||
"person": {
|
||||
"type": "JsonAddress",
|
||||
"version": "v1"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "String"
|
||||
},
|
||||
"type": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v0": {
|
||||
"JsonAccountList": {
|
||||
"fields": {
|
||||
"accounts": {
|
||||
"list": true,
|
||||
"type": "JsonAccount",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonCallMessage": {
|
||||
"fields": {
|
||||
"offerMessage": {
|
||||
"type": "OfferMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"answerMessage": {
|
||||
"type": "AnswerMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"busyMessage": {
|
||||
"type": "BusyMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"hangupMessage": {
|
||||
"type": "HangupMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"iceUpdateMessages": {
|
||||
"list": true,
|
||||
"type": "IceUpdateMessage",
|
||||
"version": "v0"
|
||||
},
|
||||
"destinationDeviceId": {
|
||||
"type": "int"
|
||||
},
|
||||
"isMultiRing": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonReceiptMessage": {
|
||||
"fields": {
|
||||
"type": {
|
||||
"type": "String"
|
||||
},
|
||||
"timestamps": {
|
||||
"list": true,
|
||||
"type": "Long"
|
||||
},
|
||||
"when": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonTypingMessage": {
|
||||
"fields": {
|
||||
"action": {
|
||||
"type": "String"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "long"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonAccount": {
|
||||
"fields": {
|
||||
"deviceId": {
|
||||
"type": "int"
|
||||
},
|
||||
"username": {
|
||||
"type": "String"
|
||||
},
|
||||
"filename": {
|
||||
"type": "String"
|
||||
},
|
||||
"uuid": {
|
||||
"type": "String"
|
||||
},
|
||||
"registered": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"has_keys": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"subscribed": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonAttachment": {
|
||||
"fields": {
|
||||
"contentType": {
|
||||
"type": "String"
|
||||
},
|
||||
"id": {
|
||||
"type": "String"
|
||||
},
|
||||
"size": {
|
||||
"type": "int"
|
||||
},
|
||||
"storedFilename": {
|
||||
"type": "String"
|
||||
},
|
||||
"filename": {
|
||||
"type": "String"
|
||||
},
|
||||
"customFilename": {
|
||||
"type": "String"
|
||||
},
|
||||
"caption": {
|
||||
"type": "String"
|
||||
},
|
||||
"width": {
|
||||
"type": "int"
|
||||
},
|
||||
"height": {
|
||||
"type": "int"
|
||||
},
|
||||
"voiceNote": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "String"
|
||||
},
|
||||
"digest": {
|
||||
"type": "String"
|
||||
},
|
||||
"blurhash": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SharedContact": {
|
||||
"fields": {
|
||||
"name": {
|
||||
"type": "Name",
|
||||
"version": "v0"
|
||||
},
|
||||
"avatar": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"phone": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"email": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"address": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"organization": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonPreview": {
|
||||
"fields": {
|
||||
"url": {
|
||||
"type": "String"
|
||||
},
|
||||
"title": {
|
||||
"type": "String"
|
||||
},
|
||||
"attachment": {
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonSticker": {
|
||||
"fields": {
|
||||
"packID": {
|
||||
"type": "String"
|
||||
},
|
||||
"packKey": {
|
||||
"type": "String"
|
||||
},
|
||||
"stickerID": {
|
||||
"type": "int"
|
||||
},
|
||||
"attachment": {
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RemoteDelete": {
|
||||
"fields": {
|
||||
"targetSentTimestamp": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ConfigurationMessage": {
|
||||
"fields": {
|
||||
"readReceipts": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"unidentifiedDeliveryIndicators": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"typingIndicators": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"linkPreviews": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonStickerPackOperationMessage": {
|
||||
"fields": {
|
||||
"packID": {
|
||||
"type": "String"
|
||||
},
|
||||
"packKey": {
|
||||
"type": "String"
|
||||
},
|
||||
"type": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OfferMessage": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
},
|
||||
"sdp": {
|
||||
"type": "String"
|
||||
},
|
||||
"type": {
|
||||
"type": "Type",
|
||||
"version": "v0"
|
||||
},
|
||||
"opaque": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"AnswerMessage": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
},
|
||||
"sdp": {
|
||||
"type": "String"
|
||||
},
|
||||
"opaque": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"BusyMessage": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HangupMessage": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
},
|
||||
"type": {
|
||||
"type": "Type",
|
||||
"version": "v0"
|
||||
},
|
||||
"deviceId": {
|
||||
"type": "int"
|
||||
},
|
||||
"legacy": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"IceUpdateMessage": {
|
||||
"fields": {
|
||||
"id": {
|
||||
"type": "long"
|
||||
},
|
||||
"opaque": {
|
||||
"type": "String"
|
||||
},
|
||||
"sdp": {
|
||||
"type": "String"
|
||||
}
|
||||
}
|
||||
},
|
||||
"JsonQuotedAttachment": {
|
||||
"fields": {
|
||||
"contentType": {
|
||||
"type": "String"
|
||||
},
|
||||
"fileName": {
|
||||
"type": "String"
|
||||
},
|
||||
"thumbnail": {
|
||||
"type": "JsonAttachment",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Mention": {
|
||||
"fields": {
|
||||
"uuid": {
|
||||
"type": "UUID"
|
||||
},
|
||||
"start": {
|
||||
"type": "int"
|
||||
},
|
||||
"length": {
|
||||
"type": "int"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Success": {
|
||||
"fields": {
|
||||
"unidentified": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"needsSync": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"duration": {
|
||||
"type": "long"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Name": {
|
||||
"fields": {
|
||||
"display": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"given": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"family": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"prefix": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"suffix": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
},
|
||||
"middle": {
|
||||
"type": "Optional",
|
||||
"version": "v0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Optional": {
|
||||
"fields": {
|
||||
"present": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Type": {
|
||||
"fields": {}
|
||||
}
|
||||
},
|
||||
"v1alpha1": {
|
||||
"ProtocolRequest": {
|
||||
"fields": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"v1": {
|
||||
"send": {
|
||||
"request": "SendRequest",
|
||||
"response": "SendResponse"
|
||||
},
|
||||
"react": {
|
||||
"request": "ReactRequest",
|
||||
"response": "SendResponse",
|
||||
"doc": "react to a previous message"
|
||||
},
|
||||
"version": {
|
||||
"request": "VersionRequest",
|
||||
"response": "JsonVersionMessage"
|
||||
}
|
||||
},
|
||||
"v1alpha1": {
|
||||
"protocol": {
|
||||
"request": "ProtocolRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,19 +13,15 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package signald
|
||||
|
||||
import (
|
||||
"git.callpipe.com/finn/signald-go/signald/client-protocol/v1"
|
||||
)
|
||||
package v0
|
||||
|
||||
// Request represents a message sent to signald
|
||||
type Request struct {
|
||||
type LegacyRequest struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
MessageBody string `json:"messageBody,omitempty"`
|
||||
RecipientAddress v1.JsonAddress `json:"recipientAddress,omitempty"`
|
||||
RecipientAddress JsonAddress `json:"recipientAddress,omitempty"`
|
||||
RecipientGroupID string `json:"recipientGroupId,omitempty"`
|
||||
Voice bool `json:"voice,omitempty"`
|
||||
Code string `json:"code,omitempty"`
|
||||
|
@ -38,11 +34,7 @@ type Request struct {
|
|||
Avatar string `json:"avatar,omitempty"`
|
||||
}
|
||||
|
||||
type JsonAttachment struct {
|
||||
Filename string `json:"filename"`
|
||||
Caption string `json:"caption"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
VoiceNote bool `json:"voiceNote"`
|
||||
Preview bool `json:"preview"`
|
||||
type JsonAddress struct {
|
||||
Number string
|
||||
UUID string
|
||||
}
|
|
@ -1,30 +1,25 @@
|
|||
package signald
|
||||
package v0
|
||||
|
||||
import (
|
||||
"git.callpipe.com/finn/signald-go/signald/client-protocol/v1"
|
||||
)
|
||||
|
||||
// Response is a response to a request to signald, or a new inbound message
|
||||
type Response struct {
|
||||
type LegacyResponse struct {
|
||||
ID string
|
||||
Data ResponseData
|
||||
Data LegacyResponseData
|
||||
Type string
|
||||
}
|
||||
|
||||
// ResponseData is where most of the data in the response is stored.
|
||||
type ResponseData struct {
|
||||
type LegacyResponseData struct {
|
||||
Groups []Group
|
||||
Accounts []Account
|
||||
URI string
|
||||
DataMessage DataMessage
|
||||
Message string
|
||||
Username string
|
||||
Source v1.JsonAddress
|
||||
Source JsonAddress
|
||||
SourceDevice int
|
||||
Type string
|
||||
IsReceipt bool
|
||||
Timestamp float64
|
||||
ServerTimestamp float64
|
||||
Timestamp int64
|
||||
ServerTimestamp int64
|
||||
}
|
||||
|
||||
// Group represents a group in signal
|
||||
|
@ -47,10 +42,10 @@ type Account struct {
|
|||
|
||||
// DataMessage is the main component of incoming text messages
|
||||
type DataMessage struct {
|
||||
Timestamp float64
|
||||
Message string
|
||||
ExpiresInSeconds float64
|
||||
GroupInfo IncomingGroupInfo
|
||||
Timestamp int64
|
||||
Body string
|
||||
ExpiresInSeconds int64
|
||||
GroupInfo IncomingGroupInfo `json:"group"`
|
||||
}
|
||||
|
||||
// IncomingGroupInfo is information about a particular group
|
164
signald/client-protocol/v0/structs.go
Normal file
164
signald/client-protocol/v0/structs.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
package v0
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
type Request struct {
|
||||
ID string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type AnswerMessage struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Opaque string `json:"opaque,omitempty"`
|
||||
Sdp string `json:"sdp,omitempty"`
|
||||
}
|
||||
|
||||
type BusyMessage struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
type ConfigurationMessage struct {
|
||||
LinkPreviews *Optional `json:"linkPreviews,omitempty"`
|
||||
ReadReceipts *Optional `json:"readReceipts,omitempty"`
|
||||
TypingIndicators *Optional `json:"typingIndicators,omitempty"`
|
||||
UnidentifiedDeliveryIndicators *Optional `json:"unidentifiedDeliveryIndicators,omitempty"`
|
||||
}
|
||||
|
||||
type HangupMessage struct {
|
||||
DeviceId int32 `json:"deviceId,omitempty"`
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Legacy bool `json:"legacy,omitempty"`
|
||||
Type *Type `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type IceUpdateMessage struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Opaque string `json:"opaque,omitempty"`
|
||||
Sdp string `json:"sdp,omitempty"`
|
||||
}
|
||||
|
||||
type JsonAccount struct {
|
||||
DeviceId int32 `json:"deviceId,omitempty"`
|
||||
Filename string `json:"filename,omitempty"`
|
||||
Has_keys bool `json:"has_keys,omitempty"`
|
||||
Registered bool `json:"registered,omitempty"`
|
||||
Subscribed bool `json:"subscribed,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
}
|
||||
|
||||
type JsonAccountList struct {
|
||||
Accounts []*JsonAccount `json:"accounts,omitempty"`
|
||||
}
|
||||
|
||||
type JsonAttachment struct {
|
||||
Blurhash string `json:"blurhash,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
CustomFilename string `json:"customFilename,omitempty"`
|
||||
Digest string `json:"digest,omitempty"`
|
||||
Filename string `json:"filename,omitempty"`
|
||||
Height int32 `json:"height,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Size int32 `json:"size,omitempty"`
|
||||
StoredFilename string `json:"storedFilename,omitempty"`
|
||||
VoiceNote bool `json:"voiceNote,omitempty"`
|
||||
Width int32 `json:"width,omitempty"`
|
||||
}
|
||||
|
||||
type JsonCallMessage struct {
|
||||
AnswerMessage *AnswerMessage `json:"answerMessage,omitempty"`
|
||||
BusyMessage *BusyMessage `json:"busyMessage,omitempty"`
|
||||
DestinationDeviceId int32 `json:"destinationDeviceId,omitempty"`
|
||||
HangupMessage *HangupMessage `json:"hangupMessage,omitempty"`
|
||||
IceUpdateMessages []*IceUpdateMessage `json:"iceUpdateMessages,omitempty"`
|
||||
IsMultiRing bool `json:"isMultiRing,omitempty"`
|
||||
OfferMessage *OfferMessage `json:"offerMessage,omitempty"`
|
||||
}
|
||||
|
||||
type JsonPreview struct {
|
||||
Attachment *JsonAttachment `json:"attachment,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
type JsonQuotedAttachment struct {
|
||||
ContentType string `json:"contentType,omitempty"`
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
Thumbnail *JsonAttachment `json:"thumbnail,omitempty"`
|
||||
}
|
||||
|
||||
type JsonReceiptMessage struct {
|
||||
Timestamps []int64 `json:"timestamps,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
When int64 `json:"when,omitempty"`
|
||||
}
|
||||
|
||||
type JsonSticker struct {
|
||||
Attachment *JsonAttachment `json:"attachment,omitempty"`
|
||||
PackID string `json:"packID,omitempty"`
|
||||
PackKey string `json:"packKey,omitempty"`
|
||||
StickerID int32 `json:"stickerID,omitempty"`
|
||||
}
|
||||
|
||||
type JsonStickerPackOperationMessage struct {
|
||||
PackID string `json:"packID,omitempty"`
|
||||
PackKey string `json:"packKey,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type JsonTypingMessage struct {
|
||||
Action string `json:"action,omitempty"`
|
||||
GroupId string `json:"groupId,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
type Mention struct {
|
||||
Length int32 `json:"length,omitempty"`
|
||||
Start int32 `json:"start,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
}
|
||||
|
||||
type Name struct {
|
||||
Display *Optional `json:"display,omitempty"`
|
||||
Family *Optional `json:"family,omitempty"`
|
||||
Given *Optional `json:"given,omitempty"`
|
||||
Middle *Optional `json:"middle,omitempty"`
|
||||
Prefix *Optional `json:"prefix,omitempty"`
|
||||
Suffix *Optional `json:"suffix,omitempty"`
|
||||
}
|
||||
|
||||
type OfferMessage struct {
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Opaque string `json:"opaque,omitempty"`
|
||||
Sdp string `json:"sdp,omitempty"`
|
||||
Type *Type `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type Optional struct {
|
||||
Present bool `json:"present,omitempty"`
|
||||
}
|
||||
|
||||
type RemoteDelete struct {
|
||||
TargetSentTimestamp int64 `json:"targetSentTimestamp,omitempty"`
|
||||
}
|
||||
|
||||
type SharedContact struct {
|
||||
Address *Optional `json:"address,omitempty"`
|
||||
Avatar *Optional `json:"avatar,omitempty"`
|
||||
Email *Optional `json:"email,omitempty"`
|
||||
Name *Name `json:"name,omitempty"`
|
||||
Organization *Optional `json:"organization,omitempty"`
|
||||
Phone *Optional `json:"phone,omitempty"`
|
||||
}
|
||||
|
||||
type Success struct {
|
||||
Duration int64 `json:"duration,omitempty"`
|
||||
NeedsSync bool `json:"needsSync,omitempty"`
|
||||
Unidentified bool `json:"unidentified,omitempty"`
|
||||
}
|
||||
|
||||
type Type struct {
|
||||
}
|
121
signald/client-protocol/v1/requests.go
Normal file
121
signald/client-protocol/v1/requests.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package v1
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
|
||||
"gitlab.com/signald/signald-go/signald"
|
||||
)
|
||||
|
||||
// Submit: react to a previous message
|
||||
func (r *ReactRequest) Submit(conn *signald.Signald) (response SendResponse, err error) {
|
||||
r.Version = "v1"
|
||||
r.Type = "react"
|
||||
if r.ID == "" {
|
||||
r.ID = generateID()
|
||||
}
|
||||
|
||||
err = conn.RawRequest(r)
|
||||
if err != nil {
|
||||
log.Println("signald-go: error submitting request to signald")
|
||||
return response, err
|
||||
}
|
||||
|
||||
responseChannel := conn.GetResponseListener(r.ID)
|
||||
defer conn.CloseResponseListener(r.ID)
|
||||
|
||||
rawResponse := <-responseChannel
|
||||
if rawResponse.Error != nil {
|
||||
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(rawResponse.Data, &response)
|
||||
if err != nil {
|
||||
rawResponseJson, _ := rawResponse.Data.MarshalJSON()
|
||||
log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson))
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *SendRequest) Submit(conn *signald.Signald) (response SendResponse, err error) {
|
||||
r.Version = "v1"
|
||||
r.Type = "send"
|
||||
if r.ID == "" {
|
||||
r.ID = generateID()
|
||||
}
|
||||
|
||||
err = conn.RawRequest(r)
|
||||
if err != nil {
|
||||
log.Println("signald-go: error submitting request to signald")
|
||||
return response, err
|
||||
}
|
||||
|
||||
responseChannel := conn.GetResponseListener(r.ID)
|
||||
defer conn.CloseResponseListener(r.ID)
|
||||
|
||||
rawResponse := <-responseChannel
|
||||
if rawResponse.Error != nil {
|
||||
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(rawResponse.Data, &response)
|
||||
if err != nil {
|
||||
rawResponseJson, _ := rawResponse.Data.MarshalJSON()
|
||||
log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson))
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
|
||||
}
|
||||
|
||||
func (r *VersionRequest) Submit(conn *signald.Signald) (response JsonVersionMessage, err error) {
|
||||
r.Version = "v1"
|
||||
r.Type = "version"
|
||||
if r.ID == "" {
|
||||
r.ID = generateID()
|
||||
}
|
||||
|
||||
err = conn.RawRequest(r)
|
||||
if err != nil {
|
||||
log.Println("signald-go: error submitting request to signald")
|
||||
return response, err
|
||||
}
|
||||
|
||||
responseChannel := conn.GetResponseListener(r.ID)
|
||||
defer conn.CloseResponseListener(r.ID)
|
||||
|
||||
rawResponse := <-responseChannel
|
||||
if rawResponse.Error != nil {
|
||||
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(rawResponse.Data, &response)
|
||||
if err != nil {
|
||||
rawResponseJson, _ := rawResponse.Data.MarshalJSON()
|
||||
log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson))
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
|
||||
}
|
||||
|
||||
const idsize = 10
|
||||
|
||||
var charset = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
func generateID() string {
|
||||
id := make([]rune, idsize)
|
||||
for i := range id {
|
||||
id[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(id)
|
||||
}
|
199
signald/client-protocol/v1/structs.go
Normal file
199
signald/client-protocol/v1/structs.go
Normal file
|
@ -0,0 +1,199 @@
|
|||
package v1
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
import (
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
ID string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type JsonAddress struct {
|
||||
Number string `json:"number,omitempty"` // An e164 phone number, starting with +. Currently the only available user-facing Signal identifier.
|
||||
Relay string `json:"relay,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"` // A UUID, the unique identifier for a particular Signal account.
|
||||
}
|
||||
|
||||
type JsonBlockedListMessage struct {
|
||||
Addresses []*JsonAddress `json:"addresses,omitempty"`
|
||||
GroupIds []string `json:"groupIds,omitempty"`
|
||||
}
|
||||
|
||||
type JsonDataMessage struct {
|
||||
Attachments []*v0.JsonAttachment `json:"attachments,omitempty"` // files attached to the incoming message
|
||||
Body string `json:"body,omitempty"` // the text body of the incoming message.
|
||||
Contacts []*v0.SharedContact `json:"contacts,omitempty"` // if the incoming message has a shared contact, the contact's information will be here
|
||||
EndSession bool `json:"endSession,omitempty"`
|
||||
ExpiresInSeconds int32 `json:"expiresInSeconds,omitempty"` // the expiry timer on the incoming message. Clients should delete records of the message within this number of seconds
|
||||
Group *JsonGroupInfo `json:"group,omitempty"` // if the incoming message was sent to a v1 group, information about that group will be here
|
||||
GroupV2 *JsonGroupV2Info `json:"groupV2,omitempty"` // is the incoming message was sent to a v2 group, basic identifying information about that group will be here. For full information, use list_groups
|
||||
Previews []*v0.JsonPreview `json:"previews,omitempty"` // if the incoming message has a link preview, information about that preview will be here
|
||||
ProfileKeyUpdate bool `json:"profileKeyUpdate,omitempty"`
|
||||
Quote *JsonQuote `json:"quote,omitempty"` // if the incoming message is a quote or reply to another message, this will contain information about that message
|
||||
Reaction *JsonReaction `json:"reaction,omitempty"` // if the message adds or removes a reaction to another message, this will indicate what change is being made
|
||||
RemoteDelete *v0.RemoteDelete `json:"remoteDelete,omitempty"` // if the inbound message is deleting a previously sent message, indicates which message should be deleted
|
||||
Sticker *v0.JsonSticker `json:"sticker,omitempty"` // if the incoming message is a sticker, information about the sicker will be here
|
||||
Timestamp int64 `json:"timestamp,omitempty"` // the (unix) timestamp that the message was sent at, according to the sender's device. This is used to uniquely identify this message for things like reactions and quotes.
|
||||
ViewOnce bool `json:"viewOnce,omitempty"` // indicates the message is a view once message. View once messages typically include no body and a single image attachment. Official Signal clients will prevent the user from saving the image, and once the user has viewed the image once they will destroy the image.
|
||||
}
|
||||
|
||||
type JsonGroupInfo struct {
|
||||
AvatarId int64 `json:"avatarId,omitempty"`
|
||||
GroupId string `json:"groupId,omitempty"`
|
||||
Members []*JsonAddress `json:"members,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type JsonGroupV2Info struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
InviteLinkPassword string `json:"inviteLinkPassword,omitempty"`
|
||||
MasterKey string `json:"masterKey,omitempty"`
|
||||
Members []*JsonAddress `json:"members,omitempty"`
|
||||
PendingMembers []*JsonAddress `json:"pendingMembers,omitempty"`
|
||||
RequestingMembers []*JsonAddress `json:"requestingMembers,omitempty"`
|
||||
Revision int32 `json:"revision,omitempty"`
|
||||
Timer int32 `json:"timer,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
}
|
||||
|
||||
type JsonMention struct {
|
||||
Length int32 `json:"length,omitempty"`
|
||||
Start int32 `json:"start,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
}
|
||||
|
||||
type JsonMessageEnvelope struct {
|
||||
CallMessage *v0.JsonCallMessage `json:"callMessage,omitempty"`
|
||||
DataMessage *JsonDataMessage `json:"dataMessage,omitempty"`
|
||||
HasContent bool `json:"hasContent,omitempty"`
|
||||
HasLegacyMessage bool `json:"hasLegacyMessage,omitempty"`
|
||||
IsUnidentifiedSender bool `json:"isUnidentifiedSender,omitempty"`
|
||||
Receipt *v0.JsonReceiptMessage `json:"receipt,omitempty"`
|
||||
Relay string `json:"relay,omitempty"`
|
||||
ServerDeliveredTimestamp int64 `json:"serverDeliveredTimestamp,omitempty"`
|
||||
ServerTimestamp int64 `json:"serverTimestamp,omitempty"`
|
||||
Source *JsonAddress `json:"source,omitempty"`
|
||||
SourceDevice int32 `json:"sourceDevice,omitempty"`
|
||||
SyncMessage *JsonSyncMessage `json:"syncMessage,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
TimestampISO string `json:"timestampISO,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Typing *v0.JsonTypingMessage `json:"typing,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
}
|
||||
|
||||
type JsonMessageRequestResponseMessage struct {
|
||||
GroupId string `json:"groupId,omitempty"`
|
||||
Person *JsonAddress `json:"person,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// JsonQuote: A quote is a reply to a previous message. ID is the sent time of the message being replied to
|
||||
type JsonQuote struct {
|
||||
Attachments []*v0.JsonQuotedAttachment `json:"attachments,omitempty"`
|
||||
Author *JsonAddress `json:"author,omitempty"`
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Mentions []*v0.Mention `json:"mentions,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
}
|
||||
|
||||
type JsonReaction struct {
|
||||
Emoji string `json:"emoji,omitempty"` // the emoji to react with
|
||||
Remove bool `json:"remove,omitempty"` // set to true to remove the reaction. requires emoji be set to previously reacted emoji
|
||||
TargetAuthor *JsonAddress `json:"targetAuthor,omitempty"` // the author of the message being reacted to
|
||||
TargetSentTimestamp int64 `json:"targetSentTimestamp,omitempty"` // the client timestamp of the message being reacted to
|
||||
}
|
||||
|
||||
type JsonReadMessage struct {
|
||||
Sender *JsonAddress `json:"sender,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
type JsonSendMessageResult struct {
|
||||
Address *JsonAddress `json:"address,omitempty"`
|
||||
IdentityFailure string `json:"identityFailure,omitempty"`
|
||||
NetworkFailure bool `json:"networkFailure,omitempty"`
|
||||
Success *v0.Success `json:"success,omitempty"`
|
||||
UnregisteredFailure bool `json:"unregisteredFailure,omitempty"`
|
||||
}
|
||||
|
||||
type JsonSentTranscriptMessage struct {
|
||||
Destination *JsonAddress `json:"destination,omitempty"`
|
||||
ExpirationStartTimestamp int64 `json:"expirationStartTimestamp,omitempty"`
|
||||
IsRecipientUpdate bool `json:"isRecipientUpdate,omitempty"`
|
||||
Message *JsonDataMessage `json:"message,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
UnidentifiedStatus map[string]string `json:"unidentifiedStatus,omitempty"`
|
||||
}
|
||||
|
||||
type JsonSyncMessage struct {
|
||||
BlockedList *JsonBlockedListMessage `json:"blockedList,omitempty"`
|
||||
Configuration *v0.ConfigurationMessage `json:"configuration,omitempty"`
|
||||
Contacts *v0.JsonAttachment `json:"contacts,omitempty"`
|
||||
ContactsComplete bool `json:"contactsComplete,omitempty"`
|
||||
FetchType string `json:"fetchType,omitempty"`
|
||||
Groups *v0.JsonAttachment `json:"groups,omitempty"`
|
||||
MessageRequestResponse *JsonMessageRequestResponseMessage `json:"messageRequestResponse,omitempty"`
|
||||
ReadMessages []*JsonReadMessage `json:"readMessages,omitempty"`
|
||||
Request string `json:"request,omitempty"`
|
||||
Sent *JsonSentTranscriptMessage `json:"sent,omitempty"`
|
||||
StickerPackOperations []*v0.JsonStickerPackOperationMessage `json:"stickerPackOperations,omitempty"`
|
||||
Verified *JsonVerifiedMessage `json:"verified,omitempty"`
|
||||
ViewOnceOpen *JsonViewOnceOpenMessage `json:"viewOnceOpen,omitempty"`
|
||||
}
|
||||
|
||||
type JsonVerifiedMessage struct {
|
||||
Destination *JsonAddress `json:"destination,omitempty"`
|
||||
IdentityKey string `json:"identityKey,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
Verified string `json:"verified,omitempty"`
|
||||
}
|
||||
|
||||
type JsonVersionMessage struct {
|
||||
Branch string `json:"branch,omitempty"`
|
||||
Commit string `json:"commit,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
type JsonViewOnceOpenMessage struct {
|
||||
Sender *JsonAddress `json:"sender,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
// ReactRequest: react to a previous message
|
||||
type ReactRequest struct {
|
||||
Request
|
||||
Reaction *JsonReaction `json:"reaction,omitempty"`
|
||||
RecipientAddress *JsonAddress `json:"recipientAddress,omitempty"`
|
||||
RecipientGroupID string `json:"recipientGroupId,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
type SendRequest struct {
|
||||
Request
|
||||
Attachments []*v0.JsonAttachment `json:"attachments,omitempty"`
|
||||
Mentions []*JsonMention `json:"mentions,omitempty"`
|
||||
MessageBody string `json:"messageBody,omitempty"`
|
||||
Quote *JsonQuote `json:"quote,omitempty"`
|
||||
RecipientAddress *JsonAddress `json:"recipientAddress,omitempty"`
|
||||
RecipientGroupID string `json:"recipientGroupId,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
type SendResponse struct {
|
||||
Results []*JsonSendMessageResult `json:"results,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
type VersionRequest struct {
|
||||
Request
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package v1
|
||||
|
||||
// JsonAddress is a signal user's contact information. a phone number, UUID or both
|
||||
type JsonAddress struct {
|
||||
UUID string `json:"uuid,omitempty"`
|
||||
Number string `json:"number"`
|
||||
}
|
||||
|
||||
type JsonMessageRequestResponseMessage struct {
|
||||
Person JsonAddress `json:"person"`
|
||||
GroupID string `json:"groupId"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type JsonReaction struct {
|
||||
Emoji string `json:"emoji"`
|
||||
Remove bool `json:"remove"`
|
||||
TargetAuthor JsonAddress `json:"targetAuthor"`
|
||||
TargetSentTimestamp uint64 `json:"targetSentTimestamp"`
|
||||
}
|
||||
|
||||
type JsonReadMessage struct {
|
||||
Sender JsonAddress `json:"sender"`
|
||||
Timestamp uint64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type JsonSendMessageResult struct {
|
||||
Address JsonAddress `json:"address"`
|
||||
Success Success `json:"success"`
|
||||
NetworkFailure bool `json:"networkFailure"`
|
||||
UnregisteredFailure bool `json:"unregisteredFailure"`
|
||||
IdentityFailure string `json:"identityFailure"`
|
||||
}
|
||||
|
||||
type Success struct {
|
||||
Unidentified bool `json:"unidentified"`
|
||||
NeedsSync bool `json:"needsSync"`
|
||||
}
|
||||
|
||||
type RequestValidationFailure struct {
|
||||
ValidationResults []string `json:"validationResults"`
|
||||
Type string `json:"type"`
|
||||
Message string `json:"message"`
|
||||
}
|
32
signald/client-protocol/v1alpha1/requests.go
Normal file
32
signald/client-protocol/v1alpha1/requests.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package v1alpha1
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
|
||||
"gitlab.com/signald/signald-go/signald"
|
||||
)
|
||||
|
||||
func (r *ProtocolRequest) Submit(conn *signald.Signald) error {
|
||||
r.Version = "v1alpha1"
|
||||
r.Type = "protocol"
|
||||
if r.ID == "" {
|
||||
r.ID = generateID()
|
||||
}
|
||||
|
||||
return conn.RawRequest(r)
|
||||
|
||||
}
|
||||
|
||||
const idsize = 10
|
||||
|
||||
var charset = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
func generateID() string {
|
||||
id := make([]rune, idsize)
|
||||
for i := range id {
|
||||
id[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(id)
|
||||
}
|
13
signald/client-protocol/v1alpha1/structs.go
Normal file
13
signald/client-protocol/v1alpha1/structs.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package v1alpha1
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
type Request struct {
|
||||
ID string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type ProtocolRequest struct {
|
||||
Request
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright © 2018 Finn Herzfeld <finn@janky.solutions>
|
||||
// Copyright © 2020 Finn Herzfeld <finn@janky.solutions>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,17 +16,39 @@
|
|||
package signald
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
|
||||
)
|
||||
|
||||
var (
|
||||
debugSignaldIO, _ = strconv.ParseBool(os.Getenv("DEBUG_SIGNALD_IO"))
|
||||
)
|
||||
|
||||
// Signald is a connection to a signald instance.
|
||||
type Signald struct {
|
||||
socket net.Conn
|
||||
listeners map[string]chan BasicResponse
|
||||
SocketPath string
|
||||
}
|
||||
|
||||
type BasicResponse struct {
|
||||
ID string
|
||||
Type string
|
||||
Error json.RawMessage
|
||||
Data json.RawMessage
|
||||
}
|
||||
|
||||
type UnexpectedError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
// Connect connects to the signad socket
|
||||
func (s *Signald) Connect() error {
|
||||
if s.SocketPath == "" {
|
||||
|
@ -37,32 +59,86 @@ func (s *Signald) Connect() error {
|
|||
return err
|
||||
}
|
||||
s.socket = socket
|
||||
log.Print("Connected to signald socket ", socket.RemoteAddr().String())
|
||||
log.Println("signald-go: Connected to signald socket ", socket.RemoteAddr().String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Listen listens for events from signald
|
||||
func (s *Signald) Listen(c chan Response) {
|
||||
// we create a decoder that reads directly from the socket
|
||||
d := json.NewDecoder(s.socket)
|
||||
|
||||
var msg Response
|
||||
|
||||
func (s *Signald) Listen(c chan v0.LegacyResponse) {
|
||||
for {
|
||||
if err := d.Decode(&msg); err != nil {
|
||||
log.Println("error decoding message from signald:", err)
|
||||
msg, err := s.readNext()
|
||||
if err == io.EOF {
|
||||
log.Println("signald-go: socket disconnected!")
|
||||
return
|
||||
}
|
||||
|
||||
if msg.Type == "unexpected_error" {
|
||||
var errorResponse UnexpectedError
|
||||
if err := json.Unmarshal(msg.Data, &errorResponse); err != nil {
|
||||
log.Println("signald-go: Error unmarshaling error response:", err.Error())
|
||||
continue
|
||||
}
|
||||
log.Println("signald-go: Unexpected error", errorResponse.Message)
|
||||
continue
|
||||
}
|
||||
|
||||
if subscribers, ok := s.listeners[msg.ID]; ok {
|
||||
subscribers <- msg
|
||||
}
|
||||
|
||||
if c != nil {
|
||||
legacyResponse := v0.LegacyResponse{
|
||||
ID: msg.ID,
|
||||
Type: msg.Type,
|
||||
}
|
||||
_ = json.Unmarshal(msg.Data, &legacyResponse.Data)
|
||||
c <- legacyResponse
|
||||
}
|
||||
c <- msg
|
||||
}
|
||||
}
|
||||
|
||||
// SendRequest sends a request to signald. Mostly used interally.
|
||||
func (s *Signald) SendRequest(request Request) error {
|
||||
b, err := json.Marshal(request)
|
||||
func (s *Signald) RawRequest(request interface{}) error {
|
||||
if debugSignaldIO {
|
||||
buffer := bytes.Buffer{}
|
||||
if err := json.NewEncoder(&buffer).Encode(request); err == nil {
|
||||
log.Println("[to signald]", buffer.String())
|
||||
}
|
||||
}
|
||||
return json.NewEncoder(s.socket).Encode(request)
|
||||
}
|
||||
|
||||
func (s *Signald) GetResponseListener(requestid string) chan BasicResponse {
|
||||
if s.listeners == nil {
|
||||
s.listeners = map[string]chan BasicResponse{}
|
||||
}
|
||||
c, ok := s.listeners[requestid]
|
||||
if !ok {
|
||||
c = make(chan BasicResponse)
|
||||
s.listeners[requestid] = c
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (s *Signald) CloseResponseListener(requestid string) {
|
||||
listener, ok := s.listeners[requestid]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
close(listener)
|
||||
delete(s.listeners, requestid)
|
||||
}
|
||||
|
||||
func (s *Signald) readNext() (b BasicResponse, err error) {
|
||||
if debugSignaldIO {
|
||||
buffer := bytes.Buffer{}
|
||||
err = json.NewDecoder(io.TeeReader(s.socket, &buffer)).Decode(&b)
|
||||
log.Println("[from signald]", buffer.String())
|
||||
} else {
|
||||
err = json.NewDecoder(s.socket).Decode(&b)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
log.Println("signald-go: error decoding message from signald:", err)
|
||||
return
|
||||
}
|
||||
log.Print("Sending ", string(b))
|
||||
e := json.NewEncoder(s.socket)
|
||||
return e.Encode(request)
|
||||
return
|
||||
}
|
||||
|
|
179
tools/generator/main.go
Normal file
179
tools/generator/main.go
Normal file
|
@ -0,0 +1,179 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Protocol struct {
|
||||
Types map[string]map[string]*Type
|
||||
Actions map[string]map[string]*Action
|
||||
}
|
||||
|
||||
type Type struct {
|
||||
Fields map[string]*DataType
|
||||
Request bool `json:"-"`
|
||||
Doc string
|
||||
}
|
||||
|
||||
type DataType struct {
|
||||
List bool
|
||||
Type string
|
||||
Version string
|
||||
FieldName string
|
||||
Doc string
|
||||
}
|
||||
|
||||
type Action struct {
|
||||
FnName string
|
||||
Request string
|
||||
Response string
|
||||
Doc string
|
||||
}
|
||||
|
||||
type StructsTemplateInput struct {
|
||||
Types map[string]*Type
|
||||
Version string
|
||||
ImportVersions []string
|
||||
}
|
||||
|
||||
type ActionsTemplateInput struct {
|
||||
Actions map[string]*Action
|
||||
Version string
|
||||
Responses bool
|
||||
}
|
||||
|
||||
var typeMap = map[string]string{
|
||||
"int": "int32",
|
||||
"Integer": "int32",
|
||||
"Boolean": "bool",
|
||||
"long": "int64",
|
||||
"Long": "int64",
|
||||
"UUID": "string",
|
||||
"boolean": "bool",
|
||||
"String": "string",
|
||||
"Map": "map[string]string", // TODO: make signald print the actual key and value types
|
||||
}
|
||||
|
||||
var fieldNameMap = map[string]string{
|
||||
"id": "ID",
|
||||
"recipientGroupId": "RecipientGroupID",
|
||||
"uuid": "UUID",
|
||||
}
|
||||
|
||||
func (d *DataType) fixForVersion(field, version string) {
|
||||
response, ok := typeMap[d.Type]
|
||||
if ok {
|
||||
if d.Type == "byte" && d.List {
|
||||
d.List = false
|
||||
}
|
||||
d.Type = response
|
||||
} else {
|
||||
if d.Version == version || d.Version == "" {
|
||||
d.Type = fmt.Sprintf("*%s", d.Type)
|
||||
} else {
|
||||
d.Type = fmt.Sprintf("*%s.%s", d.Version, d.Type)
|
||||
}
|
||||
}
|
||||
|
||||
fieldName, ok := fieldNameMap[field]
|
||||
if ok {
|
||||
d.FieldName = fieldName
|
||||
} else {
|
||||
d.FieldName = strings.Title(field)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var response Protocol
|
||||
err := json.NewDecoder(os.Stdin).Decode(&response)
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nError parsing stdin")
|
||||
}
|
||||
|
||||
tmpl, err := template.ParseGlob("tools/generator/*.tmpl")
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nError parsing templates from tools/generator/*.tmpl")
|
||||
}
|
||||
|
||||
for version, actions := range response.Actions {
|
||||
inputs := ActionsTemplateInput{Version: version, Responses: false}
|
||||
for action, a := range actions {
|
||||
actions[action].FnName = strings.Title(action)
|
||||
if a.Request != "" {
|
||||
response.Types[version][a.Request].Request = true
|
||||
}
|
||||
if a.Response != "" {
|
||||
inputs.Responses = true
|
||||
}
|
||||
}
|
||||
inputs.Actions = actions
|
||||
outputDir := fmt.Sprintf("signald/client-protocol/%s", version)
|
||||
err = os.MkdirAll(outputDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal("Error creating", outputDir, err)
|
||||
}
|
||||
outputFilename := fmt.Sprintf("%s/%s", outputDir, "requests.go")
|
||||
log.Println("Opening", outputFilename)
|
||||
f, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nfailed to open output file ", outputFilename)
|
||||
}
|
||||
err = tmpl.ExecuteTemplate(f, "requests.go.tmpl", inputs)
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nfailed to render template")
|
||||
}
|
||||
err = exec.Command("gofmt", "-w", outputFilename).Run()
|
||||
if err != nil {
|
||||
log.Fatal(err, " error running gofmt on ", outputFilename)
|
||||
}
|
||||
fmt.Println(outputFilename)
|
||||
}
|
||||
|
||||
for version, types := range response.Types {
|
||||
inputs := StructsTemplateInput{Version: version}
|
||||
for typeName, t := range types {
|
||||
for fieldName, field := range t.Fields {
|
||||
types[typeName].Fields[fieldName].fixForVersion(fieldName, version)
|
||||
if field.Version != "" && field.Version != version {
|
||||
found := false
|
||||
for _, v := range inputs.ImportVersions {
|
||||
if v == field.Version {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
inputs.ImportVersions = append(inputs.ImportVersions, field.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inputs.Types = types
|
||||
outputDir := fmt.Sprintf("signald/client-protocol/%s", version)
|
||||
err = os.MkdirAll(outputDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal("Error creating", outputDir, err)
|
||||
}
|
||||
outputFilename := fmt.Sprintf("%s/%s", outputDir, "structs.go")
|
||||
log.Println("Opening", outputFilename)
|
||||
f, err := os.Create(outputFilename)
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nfailed to open output file ", outputFilename)
|
||||
}
|
||||
err = tmpl.ExecuteTemplate(f, "structs.go.tmpl", inputs)
|
||||
if err != nil {
|
||||
log.Fatal(err, "\nfailed to render template")
|
||||
}
|
||||
err = exec.Command("gofmt", "-w", outputFilename).Run()
|
||||
if err != nil {
|
||||
log.Fatal(err, " error running gofmt on ", outputFilename)
|
||||
}
|
||||
fmt.Println(outputFilename)
|
||||
}
|
||||
}
|
67
tools/generator/requests.go.tmpl
Normal file
67
tools/generator/requests.go.tmpl
Normal file
|
@ -0,0 +1,67 @@
|
|||
package {{.Version}}
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
|
||||
import ({{if .Responses}}
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"{{end}}
|
||||
"math/rand"
|
||||
|
||||
"gitlab.com/signald/signald-go/signald"
|
||||
)
|
||||
|
||||
{{range $type, $action := .Actions}}
|
||||
{{if ne $action.Request ""}}
|
||||
{{if ne $action.Doc ""}}// Submit: {{$action.Doc}}{{end}}
|
||||
func (r *{{$action.Request}}) Submit(conn *signald.Signald) ({{if ne $action.Response ""}}response {{$action.Response}}, err {{end}}error) {
|
||||
r.Version = "{{$.Version}}"
|
||||
{{else}}
|
||||
{{if ne $action.Doc ""}}// {{$action.FnName}}: {{$action.Doc}}{{end}}
|
||||
func {{$action.FnName}}(conn *signald.Signald) ({{if ne $action.Response ""}}response {{$action.Response}}, {{end}}err error) {
|
||||
r := Request{Version: "{{.Version}}"}
|
||||
{{end}} r.Type = "{{$type}}"
|
||||
if(r.ID == "") {
|
||||
r.ID = generateID()
|
||||
}
|
||||
|
||||
{{if ne $action.Response ""}}
|
||||
err = conn.RawRequest(r)
|
||||
if err != nil {
|
||||
log.Println("signald-go: error submitting request to signald")
|
||||
return response, err
|
||||
}
|
||||
|
||||
responseChannel := conn.GetResponseListener(r.ID)
|
||||
defer conn.CloseResponseListener(r.ID)
|
||||
|
||||
rawResponse := <- responseChannel
|
||||
if rawResponse.Error != nil {
|
||||
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(rawResponse.Data, &response)
|
||||
if err != nil {
|
||||
rawResponseJson, _ := rawResponse.Data.MarshalJSON()
|
||||
log.Println("signald-go: error unmarshalling response from signald of type", rawResponse.Type, string(rawResponseJson))
|
||||
return response, err
|
||||
}
|
||||
|
||||
return response, nil
|
||||
{{else}}
|
||||
return conn.RawRequest(r)
|
||||
{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
|
||||
const idsize = 10
|
||||
var charset = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
|
||||
|
||||
func generateID() string {
|
||||
id := make([]rune, idsize)
|
||||
for i := range id {
|
||||
id[i]= charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(id)
|
||||
}
|
21
tools/generator/structs.go.tmpl
Normal file
21
tools/generator/structs.go.tmpl
Normal file
|
@ -0,0 +1,21 @@
|
|||
package {{.Version}}
|
||||
|
||||
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
|
||||
{{if gt (.ImportVersions | len) 0}}
|
||||
import (
|
||||
{{range $version := .ImportVersions}}
|
||||
"gitlab.com/signald/signald-go/signald/client-protocol/{{$version}}"{{end}}
|
||||
)
|
||||
{{end}}
|
||||
|
||||
type Request struct {
|
||||
ID string `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
{{ range $structName, $type := .Types }}{{if ne $type.Doc ""}}// {{$structName}}: {{$type.Doc}}{{end}}
|
||||
type {{ $structName }} struct {
|
||||
{{if $type.Request}} Request{{end}}
|
||||
{{ range $fieldName, $field := $type.Fields }}{{ $field.FieldName }} {{if $field.List}}[]{{end}}{{ $field.Type }} `json:"{{$fieldName}},omitempty"`{{if ne $field.Doc ""}} // {{$field.Doc}}{{end}}
|
||||
{{ end }}}
|
||||
{{ end }}
|
Loading…
Reference in a new issue