add support for errors in the protocol

This commit is contained in:
Finn 2021-09-30 00:39:54 -07:00
parent 0f8b17383f
commit bfcb423cdf
10 changed files with 2007 additions and 210 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,13 @@
package client_protocol
import (
"encoding/json"
)
type BasicResponse struct {
ID string
Type string
ErrorType string
Error json.RawMessage
Data json.RawMessage
}

View file

@ -158,7 +158,7 @@ type JsonMessageEnvelope struct {
HasLegacyMessage bool `json:"hasLegacyMessage,omitempty" yaml:"hasLegacyMessage,omitempty"`
IsUnidentifiedSender bool `json:"isUnidentifiedSender,omitempty" yaml:"isUnidentifiedSender,omitempty"`
Receipt *JsonReceiptMessage `json:"receipt,omitempty" yaml:"receipt,omitempty"`
Relay string `json:"relay,omitempty" yaml:"relay,omitempty"`
Relay string `json:"relay,omitempty" yaml:"relay,omitempty"` // this field is no longer available and will never be populated
ServerDeliveredTimestamp int64 `json:"serverDeliveredTimestamp,omitempty" yaml:"serverDeliveredTimestamp,omitempty"`
ServerTimestamp int64 `json:"serverTimestamp,omitempty" yaml:"serverTimestamp,omitempty"`
Source *JsonAddress `json:"source,omitempty" yaml:"source,omitempty"`
@ -307,11 +307,5 @@ type SharedContact struct {
Phone *Optional `json:"phone,omitempty" yaml:"phone,omitempty"`
}
type Success struct {
Duration int64 `json:"duration,omitempty" yaml:"duration,omitempty"`
NeedsSync bool `json:"needsSync,omitempty" yaml:"needsSync,omitempty"`
Unidentified bool `json:"unidentified,omitempty" yaml:"unidentified,omitempty"`
}
type Type struct {
}

View file

@ -0,0 +1,462 @@
package v1
import (
"encoding/json"
"fmt"
client_protocol "gitlab.com/signald/signald-go/signald/client-protocol"
)
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
func mkerr(response client_protocol.BasicResponse) error {
switch response.ErrorType {
case "AccountAlreadyVerifiedError":
result := AccountAlreadyVerifiedError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "AccountHasNoKeysError":
result := AccountHasNoKeysError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "AccountLockedError":
result := AccountLockedError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "CaptchaRequiredError":
result := CaptchaRequiredError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "FingerprintVersionMismatchError":
result := FingerprintVersionMismatchError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "GroupLinkNotActiveError":
result := GroupLinkNotActiveError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "GroupNotActiveError":
result := GroupNotActiveError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "GroupVerificationError":
result := GroupVerificationError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InternalError":
result := InternalError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidAttachmentError":
result := InvalidAttachmentError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidBase64Error":
result := InvalidBase64Error{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidFingerprintError":
result := InvalidFingerprintError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidGroupError":
result := InvalidGroupError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidGroupStateError":
result := InvalidGroupStateError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidInviteURIError":
result := InvalidInviteURIError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidProxyError":
result := InvalidProxyError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidRecipientError":
result := InvalidRecipientError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "InvalidRequestError":
result := InvalidRequestError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "NoKnownUUIDError":
result := NoKnownUUIDError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "NoSendPermissionError":
result := NoSendPermissionError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "NoSuchAccountError":
result := NoSuchAccountError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "NoSuchSessionError":
result := NoSuchSessionError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "OwnProfileKeyDoesNotExistError":
result := OwnProfileKeyDoesNotExistError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "ProfileUnavailableError":
result := ProfileUnavailableError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "ServerNotFoundError":
result := ServerNotFoundError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "UnknownGroupError":
result := UnknownGroupError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "UnknownIdentityKeyError":
result := UnknownIdentityKeyError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "UntrustedIdentityError":
result := UntrustedIdentityError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
case "UserAlreadyExistsError":
result := UserAlreadyExistsError{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result
default:
return fmt.Errorf("unexpected response type from signald: %s: %s", response.ErrorType, string(response.Error))
}
}
type AccountAlreadyVerifiedError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e AccountAlreadyVerifiedError) Error() string {
return e.Message
}
type AccountHasNoKeysError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e AccountHasNoKeysError) Error() string {
return e.Message
}
type AccountLockedError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
More string `json:"more,omitempty" yaml:"more,omitempty"`
}
func (e AccountLockedError) Error() string {
return e.Message
}
type CaptchaRequiredError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
More string `json:"more,omitempty" yaml:"more,omitempty"`
}
func (e CaptchaRequiredError) Error() string {
return e.Message
}
type FingerprintVersionMismatchError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e FingerprintVersionMismatchError) Error() string {
return e.Message
}
type GroupLinkNotActiveError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e GroupLinkNotActiveError) Error() string {
return e.Message
}
type GroupNotActiveError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e GroupNotActiveError) Error() string {
return e.Message
}
type GroupVerificationError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e GroupVerificationError) Error() string {
return e.Message
}
// InternalError: an internal error in signald has occured.
type InternalError struct {
Exceptions []string `json:"exceptions,omitempty" yaml:"exceptions,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InternalError) Error() string {
return e.Message
}
type InvalidAttachmentError struct {
Filename string `json:"filename,omitempty" yaml:"filename,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidAttachmentError) Error() string {
return e.Message
}
type InvalidBase64Error struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidBase64Error) Error() string {
return e.Message
}
type InvalidFingerprintError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidFingerprintError) Error() string {
return e.Message
}
type InvalidGroupError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidGroupError) Error() string {
return e.Message
}
type InvalidGroupStateError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidGroupStateError) Error() string {
return e.Message
}
type InvalidInviteURIError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidInviteURIError) Error() string {
return e.Message
}
type InvalidProxyError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidProxyError) Error() string {
return e.Message
}
type InvalidRecipientError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidRecipientError) Error() string {
return e.Message
}
type InvalidRequestError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e InvalidRequestError) Error() string {
return e.Message
}
type NoKnownUUIDError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e NoKnownUUIDError) Error() string {
return e.Message
}
type NoSendPermissionError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e NoSendPermissionError) Error() string {
return e.Message
}
type NoSuchAccountError struct {
Account string `json:"account,omitempty" yaml:"account,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e NoSuchAccountError) Error() string {
return e.Message
}
type NoSuchSessionError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e NoSuchSessionError) Error() string {
return e.Message
}
type OwnProfileKeyDoesNotExistError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e OwnProfileKeyDoesNotExistError) Error() string {
return e.Message
}
type ProfileUnavailableError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e ProfileUnavailableError) Error() string {
return e.Message
}
type ServerNotFoundError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`
}
func (e ServerNotFoundError) Error() string {
return e.Message
}
type UnknownGroupError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e UnknownGroupError) Error() string {
return e.Message
}
type UnknownIdentityKeyError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e UnknownIdentityKeyError) Error() string {
return e.Message
}
type UntrustedIdentityError struct {
Identifier string `json:"identifier,omitempty" yaml:"identifier,omitempty"`
IdentityKey **IdentityKey `json:"identity_key,omitempty" yaml:"identity_key,omitempty"`
Message string `json:"message,omitempty" yaml:"message,omitempty"`
}
func (e UntrustedIdentityError) Error() string {
return e.Message
}
type UserAlreadyExistsError struct {
Message string `json:"message,omitempty" yaml:"message,omitempty"`
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`
}
func (e UserAlreadyExistsError) Error() string {
return e.Message
}

View file

@ -4,7 +4,6 @@ package v1
import (
"encoding/json"
"fmt"
"log"
"gitlab.com/signald/signald-go/signald"
@ -28,7 +27,7 @@ func (r *AcceptInvitationRequest) Submit(conn *signald.Signald) (response JsonGr
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -61,7 +60,7 @@ func (r *AddLinkedDeviceRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -87,7 +86,7 @@ func (r *AddServerRequest) Submit(conn *signald.Signald) (response string, err e
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -120,7 +119,7 @@ func (r *ApproveMembershipRequest) Submit(conn *signald.Signald) (response JsonG
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -152,7 +151,7 @@ func (r *CreateGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -185,7 +184,7 @@ func (r *DeleteAccountRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -210,7 +209,7 @@ func (r *RemoveServerRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -236,7 +235,7 @@ func (r *FinishLinkRequest) Submit(conn *signald.Signald) (response Account, err
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -269,7 +268,7 @@ func (r *GenerateLinkingURIRequest) Submit(conn *signald.Signald) (response Link
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -302,7 +301,7 @@ func (r *GetAllIdentities) Submit(conn *signald.Signald) (response AllIdentityKe
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -317,7 +316,7 @@ func (r *GetAllIdentities) Submit(conn *signald.Signald) (response AllIdentityKe
}
// Submit: Query the server for the latest state of a known group. If no account in signald is a member of the group (anymore), an error with error_type: 'UnknownGroupException' is returned.
// Submit: Query the server for the latest state of a known group. If no account in signald is a member of the group (anymore), an error with error_type: 'UnknownGroupError' is returned.
func (r *GetGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2Info, err error) {
r.Version = "v1"
r.Type = "get_group"
@ -335,7 +334,7 @@ func (r *GetGroupRequest) Submit(conn *signald.Signald) (response JsonGroupV2Inf
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -368,7 +367,7 @@ func (r *GetIdentitiesRequest) Submit(conn *signald.Signald) (response IdentityK
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -401,7 +400,7 @@ func (r *GetLinkedDevicesRequest) Submit(conn *signald.Signald) (response Linked
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -434,7 +433,7 @@ func (r *GetProfileRequest) Submit(conn *signald.Signald) (response Profile, err
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -467,7 +466,7 @@ func (r *RemoteConfigRequest) Submit(conn *signald.Signald) (response RemoteConf
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -499,7 +498,7 @@ func (r *GetServersRequest) Submit(conn *signald.Signald) (response ServerList,
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -532,7 +531,7 @@ func (r *GroupLinkInfoRequest) Submit(conn *signald.Signald) (response JsonGroup
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -565,7 +564,7 @@ func (r *JoinGroupRequest) Submit(conn *signald.Signald) (response JsonGroupJoin
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -597,7 +596,7 @@ func (r *LeaveGroupRequest) Submit(conn *signald.Signald) (response GroupInfo, e
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -630,7 +629,7 @@ func (r *ListAccountsRequest) Submit(conn *signald.Signald) (response AccountLis
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -662,7 +661,7 @@ func (r *ListContactsRequest) Submit(conn *signald.Signald) (response ProfileLis
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -694,7 +693,7 @@ func (r *ListGroupsRequest) Submit(conn *signald.Signald) (response GroupList, e
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -726,7 +725,7 @@ func (r *MarkReadRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -752,7 +751,40 @@ func (r *ReactRequest) Submit(conn *signald.Signald) (response SendResponse, err
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
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
}
return response, nil
}
// Submit: deny a request to join a group
func (r *RefuseMembershipRequest) Submit(conn *signald.Signald) (response JsonGroupV2Info, err error) {
r.Version = "v1"
r.Type = "refuse_membership"
if r.ID == "" {
r.ID = signald.GenerateID()
}
err = conn.RawRequest(r)
if err != nil {
log.Println("signald-go: error submitting request to signald")
return
}
responseChannel := conn.GetResponseListener(r.ID)
defer conn.CloseResponseListener(r.ID)
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = mkerr(rawResponse)
return
}
@ -785,7 +817,7 @@ func (r *RegisterRequest) Submit(conn *signald.Signald) (response Account, err e
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -818,7 +850,7 @@ func (r *RemoteDeleteRequest) Submit(conn *signald.Signald) (response SendRespon
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -851,7 +883,7 @@ func (r *RemoveLinkedDeviceRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -877,7 +909,7 @@ func (r *RequestSyncRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -903,7 +935,7 @@ func (r *ResetSessionRequest) Submit(conn *signald.Signald) (response SendRespon
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -918,7 +950,7 @@ func (r *ResetSessionRequest) Submit(conn *signald.Signald) (response SendRespon
}
// Submit: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns
// Submit: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns.
func (r *ResolveAddressRequest) Submit(conn *signald.Signald) (response JsonAddress, err error) {
r.Version = "v1"
r.Type = "resolve_address"
@ -936,7 +968,7 @@ func (r *ResolveAddressRequest) Submit(conn *signald.Signald) (response JsonAddr
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -968,7 +1000,7 @@ func (r *SendRequest) Submit(conn *signald.Signald) (response SendResponse, err
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1001,7 +1033,7 @@ func (r *SendPaymentRequest) Submit(conn *signald.Signald) (response SendRespons
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1034,7 +1066,7 @@ func (r *SetDeviceNameRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1060,7 +1092,7 @@ func (r *SetExpirationRequest) Submit(conn *signald.Signald) (response SendRespo
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1092,7 +1124,7 @@ func (r *SetProfile) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1118,7 +1150,7 @@ func (r *SubscribeRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1144,7 +1176,7 @@ func (r *TrustRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1170,7 +1202,7 @@ func (r *TypingRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1196,7 +1228,7 @@ func (r *UnsubscribeRequest) Submit(conn *signald.Signald) (err error) {
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1222,7 +1254,7 @@ func (r *UpdateContactRequest) Submit(conn *signald.Signald) (response Profile,
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1255,7 +1287,7 @@ func (r *UpdateGroupRequest) Submit(conn *signald.Signald) (response GroupInfo,
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1288,7 +1320,7 @@ func (r *VerifyRequest) Submit(conn *signald.Signald) (response Account, err err
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}
@ -1320,7 +1352,7 @@ func (r *VersionRequest) Submit(conn *signald.Signald) (response JsonVersionMess
rawResponse := <-responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}

View file

@ -24,6 +24,7 @@ type Account struct {
AccountId string `json:"account_id,omitempty" yaml:"account_id,omitempty"` // The primary identifier on the account, included with all requests to signald for this account. Previously called 'username'
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"` // The address of this account
DeviceId int32 `json:"device_id,omitempty" yaml:"device_id,omitempty"` // The Signal device ID. Official Signal mobile clients (iPhone and Android) have device ID = 1, while linked devices such as Signal Desktop or Signal iPad have higher device IDs.
Pending bool `json:"pending,omitempty" yaml:"pending,omitempty"` // indicates the account has not completed registration
}
type AccountList struct {
@ -132,7 +133,7 @@ type GetAllIdentities struct {
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
}
// GetGroupRequest: Query the server for the latest state of a known group. If no account in signald is a member of the group (anymore), an error with error_type: 'UnknownGroupException' is returned.
// GetGroupRequest: Query the server for the latest state of a known group. If no account in signald is a member of the group (anymore), an error with error_type: 'UnknownGroupError' is returned.
type GetGroupRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
@ -254,13 +255,30 @@ type JsonAddress struct {
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` // A UUID, the unique identifier for a particular Signal account.
}
// JsonAttachment: represents a file attached to a message. When seding, only `filename` is required.
type JsonAttachment struct {
Blurhash string `json:"blurhash,omitempty" yaml:"blurhash,omitempty"`
Caption string `json:"caption,omitempty" yaml:"caption,omitempty"`
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
CustomFilename string `json:"customFilename,omitempty" yaml:"customFilename,omitempty"` // the original name of the file
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
Filename string `json:"filename,omitempty" yaml:"filename,omitempty"` // when sending, the path to the local file to upload
Height int32 `json:"height,omitempty" yaml:"height,omitempty"`
ID string `json:"id,omitempty" yaml:"id,omitempty"`
Key string `json:"key,omitempty" yaml:"key,omitempty"`
Size int32 `json:"size,omitempty" yaml:"size,omitempty"`
StoredFilename string `json:"storedFilename,omitempty" yaml:"storedFilename,omitempty"` // when receiving, the path that file has been downloaded to
VoiceNote bool `json:"voiceNote,omitempty" yaml:"voiceNote,omitempty"`
Width int32 `json:"width,omitempty" yaml:"width,omitempty"`
}
type JsonBlockedListMessage struct {
Addresses []*JsonAddress `json:"addresses,omitempty" yaml:"addresses,omitempty"`
GroupIds []string `json:"groupIds,omitempty" yaml:"groupIds,omitempty"`
}
type JsonDataMessage struct {
Attachments []*v0.JsonAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"` // files attached to the incoming message
Attachments []*JsonAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"` // files attached to the incoming message
Body string `json:"body,omitempty" yaml:"body,omitempty"` // the text body of the incoming message.
Contacts []*v0.SharedContact `json:"contacts,omitempty" yaml:"contacts,omitempty"` // if the incoming message has a shared contact, the contact's information will be here
EndSession bool `json:"endSession,omitempty" yaml:"endSession,omitempty"`
@ -270,7 +288,7 @@ type JsonDataMessage struct {
GroupCallUpdate string `json:"group_call_update,omitempty" yaml:"group_call_update,omitempty"` // the eraId string from a group call message update
Mentions []*JsonMention `json:"mentions,omitempty" yaml:"mentions,omitempty"` // list of mentions in the message
Payment *Payment `json:"payment,omitempty" yaml:"payment,omitempty"` // details about the MobileCoin payment attached to the message, if present
Previews []*v0.JsonPreview `json:"previews,omitempty" yaml:"previews,omitempty"` // if the incoming message has a link preview, information about that preview will be here
Previews []*JsonPreview `json:"previews,omitempty" yaml:"previews,omitempty"` // if the incoming message has a link preview, information about that preview will be here
ProfileKeyUpdate bool `json:"profileKeyUpdate,omitempty" yaml:"profileKeyUpdate,omitempty"`
Quote *JsonQuote `json:"quote,omitempty" yaml:"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" yaml:"reaction,omitempty"` // if the message adds or removes a reaction to another message, this will indicate what change is being made
@ -302,6 +320,7 @@ type JsonGroupJoinInfo struct {
// JsonGroupV2Info: Information about a Signal group
type JsonGroupV2Info struct {
AccessControl *GroupAccessControl `json:"accessControl,omitempty" yaml:"accessControl,omitempty"` // current access control settings for this group
Announcements string `json:"announcements,omitempty" yaml:"announcements,omitempty"` // indicates if the group is an announcements group. Only admins are allowed to send messages to announcements groups. Options are UNKNOWN, ENABLED or DISABLED
Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"` // path to the group's avatar on local disk, if available
Description string `json:"description,omitempty" yaml:"description,omitempty"`
ID string `json:"id,omitempty" yaml:"id,omitempty"`
@ -349,6 +368,15 @@ type JsonMessageRequestResponseMessage struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`
}
// JsonPreview: metadata about one of the links in a message
type JsonPreview struct {
Attachment *JsonAttachment `json:"attachment,omitempty" yaml:"attachment,omitempty"` // an optional image file attached to the preview
Date int64 `json:"date,omitempty" yaml:"date,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Url string `json:"url,omitempty" yaml:"url,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" yaml:"attachments,omitempty"` // list of files attached to the quoted message
@ -374,7 +402,7 @@ type JsonSendMessageResult struct {
Address *JsonAddress `json:"address,omitempty" yaml:"address,omitempty"`
IdentityFailure string `json:"identityFailure,omitempty" yaml:"identityFailure,omitempty"`
NetworkFailure bool `json:"networkFailure,omitempty" yaml:"networkFailure,omitempty"`
Success *v0.Success `json:"success,omitempty" yaml:"success,omitempty"`
Success *SendSuccess `json:"success,omitempty" yaml:"success,omitempty"`
UnregisteredFailure bool `json:"unregisteredFailure,omitempty" yaml:"unregisteredFailure,omitempty"`
}
@ -390,10 +418,10 @@ type JsonSentTranscriptMessage struct {
type JsonSyncMessage struct {
BlockedList *JsonBlockedListMessage `json:"blockedList,omitempty" yaml:"blockedList,omitempty"`
Configuration *v0.ConfigurationMessage `json:"configuration,omitempty" yaml:"configuration,omitempty"`
Contacts *v0.JsonAttachment `json:"contacts,omitempty" yaml:"contacts,omitempty"`
Contacts *JsonAttachment `json:"contacts,omitempty" yaml:"contacts,omitempty"`
ContactsComplete bool `json:"contactsComplete,omitempty" yaml:"contactsComplete,omitempty"`
FetchType string `json:"fetchType,omitempty" yaml:"fetchType,omitempty"`
Groups *v0.JsonAttachment `json:"groups,omitempty" yaml:"groups,omitempty"`
Groups *JsonAttachment `json:"groups,omitempty" yaml:"groups,omitempty"`
MessageRequestResponse *JsonMessageRequestResponseMessage `json:"messageRequestResponse,omitempty" yaml:"messageRequestResponse,omitempty"`
ReadMessages []*JsonReadMessage `json:"readMessages,omitempty" yaml:"readMessages,omitempty"`
Request string `json:"request,omitempty" yaml:"request,omitempty"`
@ -514,6 +542,14 @@ type ReceiptMessage struct {
When int64 `json:"when,omitempty" yaml:"when,omitempty"`
}
// RefuseMembershipRequest: deny a request to join a group
type RefuseMembershipRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The account to interact with
GroupId string `json:"group_id,omitempty" yaml:"group_id,omitempty"`
Members []*JsonAddress `json:"members,omitempty" yaml:"members,omitempty"` // list of requesting members to refuse
}
// RegisterRequest: begin the account registration process by requesting a phone number verification code. when the code is received, submit it with a verify request
type RegisterRequest struct {
Request
@ -582,7 +618,7 @@ type ResetSessionRequest struct {
Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
}
// ResolveAddressRequest: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns
// ResolveAddressRequest: Resolve a partial JsonAddress with only a number or UUID to one with both. Anywhere that signald accepts a JsonAddress will except a partial, this is a convenience function for client authors, mostly because signald doesn't resolve all the partials it returns.
type ResolveAddressRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The signal account to use
@ -603,6 +639,7 @@ type SendRequest struct {
Attachments []*v0.JsonAttachment `json:"attachments,omitempty" yaml:"attachments,omitempty"`
Mentions []*JsonMention `json:"mentions,omitempty" yaml:"mentions,omitempty"`
MessageBody string `json:"messageBody,omitempty" yaml:"messageBody,omitempty"`
Previews []*JsonPreview `json:"previews,omitempty" yaml:"previews,omitempty"`
Quote *JsonQuote `json:"quote,omitempty" yaml:"quote,omitempty"`
RecipientAddress *JsonAddress `json:"recipientAddress,omitempty" yaml:"recipientAddress,omitempty"`
RecipientGroupID string `json:"recipientGroupId,omitempty" yaml:"recipientGroupId,omitempty"`
@ -615,16 +652,28 @@ type SendResponse struct {
Timestamp int64 `json:"timestamp,omitempty" yaml:"timestamp,omitempty"`
}
type SendSuccess struct {
Devices []int32 `json:"devices,omitempty" yaml:"devices,omitempty"`
Duration int64 `json:"duration,omitempty" yaml:"duration,omitempty"`
NeedsSync bool `json:"needsSync,omitempty" yaml:"needsSync,omitempty"`
Unidentified bool `json:"unidentified,omitempty" yaml:"unidentified,omitempty"`
}
// Server: a Signal server
type Server struct {
Ca string `json:"ca,omitempty" yaml:"ca,omitempty"`
Ca string `json:"ca,omitempty" yaml:"ca,omitempty"` // base64 encoded trust store, password must be 'whisper'
CdnUrls []*ServerCDN `json:"cdn_urls,omitempty" yaml:"cdn_urls,omitempty"`
CdsMrenclave string `json:"cds_mrenclave,omitempty" yaml:"cds_mrenclave,omitempty"`
ContactDiscoveryUrl string `json:"contact_discovery_url,omitempty" yaml:"contact_discovery_url,omitempty"`
IasCa string `json:"ias_ca,omitempty" yaml:"ias_ca,omitempty"` // base64 encoded trust store, password must be 'whisper'
KeyBackupMrenclave string `json:"key_backup_mrenclave,omitempty" yaml:"key_backup_mrenclave,omitempty"`
KeyBackupServiceId string `json:"key_backup_service_id,omitempty" yaml:"key_backup_service_id,omitempty"` // base64 encoded
KeyBackupServiceName string `json:"key_backup_service_name,omitempty" yaml:"key_backup_service_name,omitempty"`
KeyBackupUrl string `json:"key_backup_url,omitempty" yaml:"key_backup_url,omitempty"`
Proxy string `json:"proxy,omitempty" yaml:"proxy,omitempty"`
ServiceUrl string `json:"service_url,omitempty" yaml:"service_url,omitempty"`
StorageUrl string `json:"storage_url,omitempty" yaml:"storage_url,omitempty"`
UnidentifiedSenderRoot string `json:"unidentified_sender_root,omitempty" yaml:"unidentified_sender_root,omitempty"`
UnidentifiedSenderRoot string `json:"unidentified_sender_root,omitempty" yaml:"unidentified_sender_root,omitempty"` // base64 encoded
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"` // A unique identifier for the server, referenced when adding accounts. Must be a valid UUID. Will be generated if not specified when creating.
ZkParam string `json:"zk_param,omitempty" yaml:"zk_param,omitempty"` // base64 encoded ZKGROUP_SERVER_PUBLIC_PARAMS value
}
@ -717,6 +766,7 @@ type UpdateGroupRequest struct {
Request
Account string `json:"account,omitempty" yaml:"account,omitempty"` // The identifier of the account to interact with
AddMembers []*JsonAddress `json:"addMembers,omitempty" yaml:"addMembers,omitempty"`
Announcements string `json:"announcements,omitempty" yaml:"announcements,omitempty"` // ENABLED to only allow admins to post messages, DISABLED to allow anyone to post
Avatar string `json:"avatar,omitempty" yaml:"avatar,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"` // A new group description. Set to empty string to remove an existing description.
GroupID string `json:"groupID,omitempty" yaml:"groupID,omitempty"` // the ID of the group to update

View file

@ -17,8 +17,8 @@ package signald
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"log"
"math/rand"
@ -28,6 +28,7 @@ import (
"strings"
"time"
client_protocol "gitlab.com/signald/signald-go/signald/client-protocol"
"gitlab.com/signald/signald-go/signald/client-protocol/v0"
)
@ -51,17 +52,10 @@ func init() {
// Signald is a connection to a signald instance.
type Signald struct {
socket net.Conn
listeners map[string]chan BasicResponse
listeners map[string]chan client_protocol.BasicResponse
SocketPath string
}
type BasicResponse struct {
ID string
Type string
Error json.RawMessage
Data json.RawMessage
}
type UnexpectedError struct {
Message string
}
@ -91,10 +85,17 @@ func (s *Signald) Connect() error {
}
func (s *Signald) connect() error {
socket, err := net.Dial("unix", s.SocketPath)
var d net.Dialer
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
addr := net.UnixAddr{Name: s.SocketPath, Net: "unix"}
socket, err := d.DialContext(ctx, "unix", addr.String())
if err != nil {
return err
}
s.socket = socket
return nil
}
@ -146,13 +147,13 @@ func (s *Signald) RawRequest(request interface{}) error {
return json.NewEncoder(s.socket).Encode(request)
}
func (s *Signald) GetResponseListener(requestid string) chan BasicResponse {
func (s *Signald) GetResponseListener(requestid string) chan client_protocol.BasicResponse {
if s.listeners == nil {
s.listeners = map[string]chan BasicResponse{}
s.listeners = map[string]chan client_protocol.BasicResponse{}
}
c, ok := s.listeners[requestid]
if !ok {
c = make(chan BasicResponse)
c = make(chan client_protocol.BasicResponse)
s.listeners[requestid] = c
}
return c
@ -167,7 +168,7 @@ func (s *Signald) CloseResponseListener(requestid string) {
delete(s.listeners, requestid)
}
func (s *Signald) readNext() (b BasicResponse, err error) {
func (s *Signald) readNext() (b client_protocol.BasicResponse, err error) {
if debugSignaldIO {
buffer := bytes.Buffer{}
err = json.NewDecoder(io.TeeReader(s.socket, &buffer)).Decode(&b)
@ -181,10 +182,3 @@ func (s *Signald) readNext() (b BasicResponse, err error) {
}
return
}
func (b BasicResponse) GetError() error {
if b.Error == nil {
return nil
}
return fmt.Errorf("signald error: %s", string(b.Error))
}

View file

@ -0,0 +1,37 @@
package {{.Version}}
import (
"encoding/json"
"fmt"
client_protocol "gitlab.com/signald/signald-go/signald/client-protocol"
)
// DO NOT EDIT: this file is automatically generated by ./tools/generator in this repo
func mkerr(response client_protocol.BasicResponse) error {
switch response.ErrorType { {{ range $structName, $type := .Types }}
case "{{ $structName }}":
result := {{ $structName }}{}
err := json.Unmarshal(response.Error, result)
if err != nil {
return err
}
return result{{ end }}
default:
return fmt.Errorf("unexpected response type from signald: %s: %s", response.ErrorType, string(response.Error))
}
}
{{ 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" yaml:"{{$fieldName}},omitempty"`{{if ne $field.Doc ""}} // {{$field.Doc}}{{end}}
{{ end }}
}
func (e {{ $structName }}) Error() string {
return e.Message
}
{{ end }}

View file

@ -19,6 +19,7 @@ type Type struct {
Fields map[string]*DataType
Request bool `json:"-"`
Doc string
Error bool
}
type DataType struct {
@ -76,12 +77,14 @@ func (d *DataType) fixForVersion(field, version string) {
}
d.Type = response
} else {
if d.Version == version || d.Version == "" {
if d.Version != "" {
if d.Version == 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 {
@ -145,7 +148,10 @@ func main() {
}
for version, types := range response.Types {
inputs := StructsTemplateInput{Version: version}
inputs := StructsTemplateInput{
Version: version,
Types: make(map[string]*Type),
}
for typeName, t := range types {
for fieldName, field := range t.Fields {
types[typeName].Fields[fieldName].fixForVersion(fieldName, version)
@ -162,8 +168,10 @@ func main() {
}
}
}
if !t.Error {
inputs.Types[typeName] = t
}
}
inputs.Types = types
outputDir := fmt.Sprintf("signald/client-protocol/%s", version)
err = os.MkdirAll(outputDir, os.ModePerm)
if err != nil {
@ -185,4 +193,56 @@ func main() {
}
fmt.Println(outputFilename)
}
// errors
for version, types := range response.Types {
inputs := StructsTemplateInput{
Version: version,
Types: make(map[string]*Type),
}
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)
}
}
}
if t.Error {
inputs.Types[typeName] = t
}
}
if len(inputs.Types) == 0 {
continue
}
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, "errors.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, "errors.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)
}
}

View file

@ -4,7 +4,6 @@ package {{.Version}}
import ({{if .Responses}}
"encoding/json"
"fmt"
"log"{{end}}
"gitlab.com/signald/signald-go/signald"
@ -34,7 +33,7 @@ func {{$action.FnName}}(conn *signald.Signald) ({{if ne $action.Response ""}}res
rawResponse := <- responseChannel
if rawResponse.Error != nil {
err = fmt.Errorf("signald error: %s", string(rawResponse.Error))
err = mkerr(rawResponse)
return
}