Fix Nextcloud Talk connection failure (#1179)

Fix #1177

Signed-off-by: Gary Kim <gary@garykim.dev>
This commit is contained in:
Gary Kim 2020-07-26 20:51:07 +08:00 committed by GitHub
parent e1629994bd
commit 2d2bebe976
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 26 deletions

2
go.mod
View File

@ -54,7 +54,7 @@ require (
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
golang.org/x/image v0.0.0-20200618115811-c13761719519
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gomod.garykim.dev/nc-talk v0.0.1
gomod.garykim.dev/nc-talk v0.0.2
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

2
go.sum
View File

@ -450,6 +450,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomod.garykim.dev/nc-talk v0.0.1 h1:6mgjcAf5/HMkV0CFGeXVfYHG7FAUCQcGR8eg9oM6fCc=
gomod.garykim.dev/nc-talk v0.0.1/go.mod h1:0/Ksg0osAYmnWKs1OcCG+gBQ4HU1xiF1699g9B6jWZw=
gomod.garykim.dev/nc-talk v0.0.2 h1:QagJzL1Ie/sJDachAC42fEXlIh2mK8IDk1/ue0u8IcI=
gomod.garykim.dev/nc-talk v0.0.2/go.mod h1:0/Ksg0osAYmnWKs1OcCG+gBQ4HU1xiF1699g9B6jWZw=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=

View File

@ -5,6 +5,16 @@
A Go library that can be used to communicate with [Nextcloud Talk](https://github.com/nextcloud/spreed) instances.
### Installing
You can use this library in your Go projects by installing it with go mod:
```bash
GO111MODULE=on go get gomod.garykim.dev/nc-talk
```
Check out the documentation for the package [here](https://pkg.go.dev/gomod.garykim.dev/nc-talk).
### License
Copyright © 2020 Gary Kim &lt;<gary@garykim.dev>&gt;, All Rights Reserved

View File

@ -20,6 +20,7 @@ import (
)
// NewUser returns a TalkUser instance
// The url should be the full URL of the Nextcloud instance (e.g. https://cloud.mydomain.me)
func NewUser(url string, username string, password string) *user.TalkUser {
return &user.TalkUser{
NextcloudURL: url,
@ -29,6 +30,7 @@ func NewUser(url string, username string, password string) *user.TalkUser {
}
// NewRoom returns a new TalkRoom instance
// Token should be the Nextcloud Room Token (e.g. "d6zoa2zs" if the room URL is https://cloud.mydomain.me/call/d6zoa2zs)
func NewRoom(tuser *user.TalkUser, token string) *room.TalkRoom {
tr := &room.TalkRoom{
User: tuser,

View File

@ -0,0 +1,42 @@
// Copyright (c) 2020 Gary Kim <gary@garykim.dev>, All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ocs
// Capabilities describes the response from the capabilities request
type Capabilities struct {
ocs
Data struct {
Capabilities struct {
SpreedCapabilities SpreedCapabilities `json:"spreed"`
} `json:"capabilities"`
} `json:"data"`
}
// SpreedCapabilities describes the Nextcloud Talk capabilities response
type SpreedCapabilities struct {
Features []string `json:"features"`
Config struct {
Attachments struct {
Allowed bool `json:"allowed"`
Folder string `json:"folder"`
} `json:"attachments"`
Chat struct {
MaxLength int `json:"max-length"`
} `json:"chat"`
Conversations struct {
CanCreate bool `json:"can-create"`
} `json:"conversations"`
} `json:"config"`
}

View File

@ -15,10 +15,12 @@
package user
import (
"encoding/xml"
"reflect"
"encoding/json"
"strings"
"github.com/monaco-io/request"
"gomod.garykim.dev/nc-talk/ocs"
)
const (
@ -35,6 +37,8 @@ type TalkUser struct {
// Capabilities describes the capabilities that the Nextcloud Talk instance is capable of. Visit https://nextcloud-talk.readthedocs.io/en/latest/capabilities/ for more info.
type Capabilities struct {
AttachmentsFolder string `ocscapability:"config => attachments => folder"`
ChatMaxLength int
Audio bool `ocscapability:"audio"`
Video bool `ocscapability:"video"`
Chat bool `ocscapability:"chat"`
@ -60,18 +64,12 @@ type Capabilities struct {
ChatReplies bool `ocscapability:"chat-replies"`
CirclesSupport bool `ocscapability:"circles-support"`
AttachmentsAllowed bool `ocscapability:"config => attachments => allowed"`
AttachmentsFolder bool `ocscapability:"config => attachments => folder"`
ConversationsCanCreate bool `ocscapability:"config => conversations => can-create"`
ForceMute bool `ocscapability:"force-mute"`
ConversationV2 bool `ocscapability:"conversation-v2"`
ChatReferenceID bool `ocscapability:"chat-reference-id"`
}
type capabilitiesRequest struct {
XMLName xml.Name `xml:"ocs"`
Capabilities []string `xml:"ocs>data>capabilities>spreed>features>element"`
}
// RequestClient returns a monaco-io that is preconfigured to make OCS API calls
func (t *TalkUser) RequestClient(client request.Client) *request.Client {
if client.Header == nil {
@ -87,6 +85,12 @@ func (t *TalkUser) RequestClient(client request.Client) *request.Client {
Username: t.User,
Password: t.Pass,
}
// Set Nextcloud URL if there is no host
if !strings.HasPrefix(client.URL, t.NextcloudURL) {
client.URL = t.NextcloudURL + "/" + client.URL
}
return &client
}
@ -98,35 +102,67 @@ func (t *TalkUser) Capabilities() (*Capabilities, error) {
client := t.RequestClient(request.Client{
URL: ocsCapabilitiesEndpoint,
Header: map[string]string{
"Accept": "application/xml",
},
})
res, err := client.Do()
if err != nil {
return nil, err
}
capabilities := &capabilitiesRequest{}
err = xml.Unmarshal(res.Data, capabilities)
capabilitiesRequest := &struct {
Ocs ocs.Capabilities `json:"ocs"`
}{}
err = json.Unmarshal(res.Data, capabilitiesRequest)
if err != nil {
return nil, err
}
tr := &Capabilities{}
sc := capabilitiesRequest.Ocs.Data.Capabilities.SpreedCapabilities
c := reflect.ValueOf(tr)
for i := 0; i < c.NumField(); i++ {
field := c.Field(i)
tag := field.Type().Field(0).Tag.Get("ocscapability")
for _, capability := range capabilities.Capabilities {
if capability == tag && field.CanSet() {
field.SetBool(true)
}
}
tr := &Capabilities{
Audio: sliceContains(sc.Features, "audio"),
Video: sliceContains(sc.Features, "video"),
Chat: sliceContains(sc.Features, "chat"),
GuestSignaling: sliceContains(sc.Features, "guest-signaling"),
EmptyGroupRoom: sliceContains(sc.Features, "empty-group-room"),
GuestDisplayNames: sliceContains(sc.Features, "guest-display-names"),
MultiRoomUsers: sliceContains(sc.Features, "multi-room-users"),
ChatV2: sliceContains(sc.Features, "chat-v2"),
Favorites: sliceContains(sc.Features, "favorites"),
LastRoomActivity: sliceContains(sc.Features, "last-room-activity"),
NoPing: sliceContains(sc.Features, "no-ping"),
SystemMessages: sliceContains(sc.Features, "system-messages"),
MentionFlag: sliceContains(sc.Features, "mention-flag"),
InCallFlags: sliceContains(sc.Features, "in-call-flags"),
InviteByMail: sliceContains(sc.Features, "invite-by-mail"),
NotificationLevels: sliceContains(sc.Features, "notification-levels"),
InviteGroupsAndMails: sliceContains(sc.Features, "invite-groups-and-mails"),
LockedOneToOneRooms: sliceContains(sc.Features, "locked-one-to-one-rooms"),
ReadOnlyRooms: sliceContains(sc.Features, "read-only-rooms"),
ChatReadMarker: sliceContains(sc.Features, "chat-read-marker"),
WebinaryLobby: sliceContains(sc.Features, "webinary-lobby"),
StartCallFlag: sliceContains(sc.Features, "start-call-flag"),
ChatReplies: sliceContains(sc.Features, "chat-replies"),
CirclesSupport: sliceContains(sc.Features, "circles-support"),
AttachmentsAllowed: sc.Config.Attachments.Allowed,
AttachmentsFolder: sc.Config.Attachments.Folder,
ConversationsCanCreate: sc.Config.Conversations.CanCreate,
ForceMute: sliceContains(sc.Features, "force-mute"),
ConversationV2: sliceContains(sc.Features, "conversation-v2"),
ChatReferenceID: sliceContains(sc.Features, "chat-reference-id"),
ChatMaxLength: sc.Config.Chat.MaxLength,
}
t.capabilities = tr
return tr, nil
}
// sliceContains does the slice contain the string
func sliceContains(s []string, search string) bool {
for _, n := range s {
if n == search {
return true
}
}
return false
}

2
vendor/modules.txt vendored
View File

@ -274,7 +274,7 @@ golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm
# gomod.garykim.dev/nc-talk v0.0.1
# gomod.garykim.dev/nc-talk v0.0.2
gomod.garykim.dev/nc-talk
gomod.garykim.dev/nc-talk/constants
gomod.garykim.dev/nc-talk/ocs