Giter Club home page Giter Club logo

stream-chat-go's Introduction

Official Go SDK for Stream Chat

build godoc

Official Go API client for Stream Chat, a service for building chat applications.
Explore the docs »

Report Bug · Request Feature

📝 About Stream

You can sign up for a Stream account at our Get Started page.

You can use this library to access chat API endpoints server-side.

For the client-side integrations (web and mobile) have a look at the JavaScript, iOS and Android SDK libraries (docs).

⚙️ Installation

go get github.com/GetStream/stream-chat-go/v7

✨ Getting started

package main

import (
	"os"

	stream "github.com/GetStream/stream-chat-go/v7"
)

var APIKey = os.Getenv("STREAM_KEY")
var APISecret = os.Getenv("STREAM_SECRET")
var userID = "" // your server user id

func main() {
	// Initialize client
	client, err := stream.NewClient(APIKey, APISecret)
	
	// Or with a specific timeout
	client, err := stream.NewClient(APIKey, APISecret, WithTimeout(3 * time.Second))

	// Or using only environmental variables: (required) STREAM_KEY, (required) STREAM_SECRET,
	// (optional) STREAM_CHAT_TIMEOUT
	client, err := stream.NewClientFromEnvVars()

	// handle error

	// Define a context
	ctx := context.Background()

	// use client methods

	// create channel with users
	users := []string{"id1", "id2", "id3"}
	userID := "id1"
	channel, err := client.CreateChannelWithMembers(ctx, "messaging", "channel-id", userID, users...)

	// use channel methods
	msg, err := channel.SendMessage(ctx, &stream.Message{Text: "hello"}, userID)
}

✍️ Contributing

We welcome code changes that improve this library or fix a problem, please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. We are very happy to merge your code in the official repository. Make sure to sign our Contributor License Agreement (CLA) first. See our license file for more details.

Head over to CONTRIBUTING.md for some development tips.

🧑‍💻 We are hiring!

We've recently closed a $38 million Series B funding round and we keep actively growing. Our APIs are used by more than a billion end-users, and you'll have a chance to make a huge impact on the product within a team of the strongest engineers all over the world.

Check out our current openings and apply via Stream's website.

stream-chat-go's People

Contributors

akupila avatar anatolyrugalev avatar artyomdmitriev avatar bbigard avatar bdandy avatar bogdan-d avatar ferhatelmas avatar giautm avatar github-actions[bot] avatar guerinoni avatar gumuz avatar itsmeadi avatar jimmypettersson85 avatar keyneston avatar mahboubii avatar marco-ulge avatar martinmitrevski avatar miagilepner avatar peterdeme avatar ravlio avatar ruggi avatar ruudniew avatar shaljam avatar siddhantagarwal avatar tbarbugli avatar thesyncim avatar totalimmersion avatar vishalnarkhede avatar yaziine avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

stream-chat-go's Issues

Updating an existing user that is online throws an error

If you first grab a user record like so:

filter := map[string]interface{}{
    "id": "<user id>",
}
users, usersErr := streamClient.QueryUsers(&stream.QueryOption{
    Filter: filter,
    Limit:  1,
})

Then modify the user and attempt to save it, like ..

streamUser.Image = "<photo url>"
_, streamUpdateErr := streamClient.UpdateUser(streamUser)

It will fail with the following error:

chat-client: HTTP POST https://chat-us-east-1.stream-io-api.com/users?api_key=<secret> status 400 Bad Request: {\"code\":4,\"message\":\"UpdateUsers failed with error: \\\"users[<userid>].online is a reserved field\\\"\",\"exception_fields\":{\"users[<userid>].online\":\"users[<userid>].online is a reserved field\"}

It seems like if that is reserved, it should be omitted?

Tokens created via CreateToken are not valid for use

Tokens created using CreateToken are showing as malformed or as having an invalid Secret. The error is present when using both the CLI and the client SDKs.

Error message example (from CLI):

Error: Malformed JWT token or Stream API secret.

QueryResponse does not contain watchers

The Go SDK QueryResponse type does not include watchers which is returned from the API. This currently prevents the ability to query a channel's watchers.

Failing tests when running go test locally

If I clone this repository and run the tests, I see several test failures. I took a look at ci.yml and I don't see a reason why these would fail unless:

  • My trial account has some difference with the key/secret vs. what's used in CI?
  • Something has changed, since CI hasn't ran these tests in a few months?
❯ STREAM_KEY={my api key} STREAM_SECRET={my secret} go test
--- FAIL: TestClient_UpdateAppSettings (0.25s)
    app_test.go:27: 
        	Error Trace:	app_test.go:27
        	Error:      	Received unexpected error:
        	            	UpdateApp failed with error: "production app can not have disable_auth_checks flag enabled"
        	Test:       	TestClient_UpdateAppSettings
--- FAIL: TestClient_DeleteUsers (12.00s)
    async_tasks_test.go:81: 
        	Error Trace:	async_tasks_test.go:81
        	Error:      	Should be true
        	Test:       	TestClient_DeleteUsers
        	Messages:   	task did not succeed

--- FAIL: TestClient_Devices (0.42s)
    device_test.go:23: 
        	Error Trace:	device_test.go:23
        	Error:      	Received unexpected error:
        	            	CreateDevice failed with error: "push provider "" with type "firebase" not found"
        	Test:       	TestClient_Devices
        	Messages:   	add device
--- FAIL: TestClient_SendMessage_Pending (1.01s)
    message_test.go:39: 
        	Error Trace:	message_test.go:39
        	Error:      	Received unexpected error:
        	            	SendMessage failed with error: "pending messages not enabled for this app"
        	Test:       	TestClient_SendMessage_Pending
FAIL
exit status 1
FAIL	github.com/GetStream/stream-chat-go/v6	130.451s

API error when attempting to mute/unmute channel before querying it

I'm getting an API error when attempting to mute or unmute a channel that's been initialized without querying it:

streamClient.Channel("messaging", channelID).Mute(userID, nil)

which results in the following API error:

{
  "code": 4,
  "message": "MuteChannel failed with error: \"channel_cid 'MuteChannelRequest.channel_cid' Error:Field validation for 'channel_cid' failed on the 'required_without' tag, channel_cids 'MuteChannelRequest.channel_cids' Error:Field validation for 'channel_cids' failed on the 'required_without' tag\"",
  "exception_fields": {
    "channel_cid": "channel_cid 'MuteChannelRequest.channel_cid' Error:Field validation for 'channel_cid' failed on the 'required_without' tag",
    "channel_cids": "channel_cids 'MuteChannelRequest.channel_cids' Error:Field validation for 'channel_cids' failed on the 'required_without' tag"
  },
  "StatusCode": 400,
  "duration": "0.00ms",
  "more_info": "https://getstream.io/chat/docs/api_errors_response"
}

It appears that this is because the channel's CID is only initialized when coming from an API response, not when using the client's Channel() function to initialize one without querying for it:

"channel_cid": ch.CID,

Obviously this is easy to fix on our side (can just set CID manually), and should be an easy-ish fix to initalize CID in func (c *Client) Channel(...), but wanted to report it first since it looks like these two mute/unmute methods may be the only ones using the CID internally—thought maybe there was a reason (deprecation?).

gz#9275

Sending a message removes all user attributes?

It seems that sending a message is removing user attributes such as avatar URL. According to the message docs:

Note: calling the Send Message endpoint using server-side auth (i.e setting the user in the message object) will also trigger a user update. Please make sure to include all necessary user fields in order not to lose any information.

Currently this client doesn't seem to do this or allow it: https://github.com/GetStream/stream-chat-go/blob/v3.0.0/message.go#L191.

Anyway, I'd rather not have to send the entire user object each time. Would there be a way for the API to support simply sending the UserID so a user update isn't triggered on every message?

gz#6673

VerifyWebhook seems to not work

Using the following code:

body, bodyErr := ioutil.ReadAll(request.Body)
if bodyErr != nil {
  ...
}
isValid := streamClient.VerifyWebhook(body, []byte(signature))

The value for isValid will always be false.

I noticed that the hmac used to validate is len 32 and the signature is len 64. Not sure if that's the issue. It's possible i'm also just doing it wrong.

'400 Bad Request' error on idle HTTP channel

I started writing this code to do a support task for someone yesterday. It wasn't working so I eventually gave up and rewrote it in python in order to try and move forward with the support ticket.

I saved the code because it seems like a bug we need to solve (and there might be a couple here).

To replicate the issue:

  1. run the program with the -populate flag
  2. run the program without the `-populate flag

First issue:

2020/04/29 11:21:33 Query Channels iteration: 0
2020/04/29 11:21:33 Querying with: &stream_chat.QueryOption{Filter:map[string]interface {}{"type":main.obj{"$in":[]string{"messaging", "livestream"}}}, Limit:20, Offset:0}
2020/04/29 11:21:33 Unsolicited response received on idle HTTP channel starting with "HTTP/1.1 400 Bad Request\r\nDate: Wed, 29 Apr 2020 09:21:33 GMT\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 20\r\nConnection: close\r\n\r\nInvalid HTTP request"; err=<nil>
Got 0 channels

This is related to #74 and may also be related to #56

Code

package main

import (
	"flag"
	"fmt"
	"log"
	"os"

	chat "github.com/GetStream/stream-chat-go"
	"github.com/google/uuid"
)

type config struct {
	apiKey    string
	apiSecret string
	populate  bool

	doIt bool
}

func main() {
	conf := config{}
	flag.StringVar(&conf.apiKey, "key", "", "API Key to use to connect")
	flag.StringVar(&conf.apiSecret, "secret", "", "API Secret to use to connect")
	flag.BoolVar(&conf.populate, "populate", false, "populate channels")
	flag.Parse()

	client, err := chat.NewClient(conf.apiKey, []byte(conf.apiSecret))
	if err != nil {
		log.Fatalf("Error creating client: %v", err)
	}

	if conf.populate {
		if err := populate(client); err != nil {
			log.Fatalf("error populating: %#v", err)
		}
		os.Exit(0)
	}

	channels, err := queryChannels(client)
	if err != nil {
		log.Fatalf("Error querying channels: %v", err)
	}
	fmt.Printf("Got %d channels\n", len(channels))
	for _, c := range channels {
		log.Printf("Channel: %s", c.CID)
	}
}

func populate(client *chat.Client) error {
	for i := 0; i < 1000; i++ {
		if _, err := client.CreateChannel("messaging", uuid.New().String(), "tabs", nil); err != nil {
			return err
		}
	}
	return nil
}

type obj map[string]interface{}

func queryChannels(client *chat.Client) ([]*chat.Channel, error) {
	results := []*chat.Channel{}

	limit := 20
	lastID := ""

	opts := &chat.QueryOption{
		Limit: limit,
		Filter: obj{
			"type": obj{
				"$in": []string{
					"messaging",
					"livestream",
				},
			},
		},
	}

	for i := 0; i < 1000; i++ {
		log.Printf("Query Channels iteration: %d", i)
		if lastID != "" {
			log.Printf("Setting lastID of %q", lastID)
			opts.Filter["id_gt"] = lastID
		}

		log.Printf("Querying with: %#v", opts)
		res, err := client.QueryChannels(opts, &chat.SortOption{Field: "id", Direction: 1})
		if err != nil {
			return nil, err
		}
		if len(res) == 0 {
			break
		}
		lastID = res[len(res)-1].CID
		results = append(results, res...)
	}

	return results, nil
}

Remove SQS config

I used the library to add my SQS config on my app.
But I couldn't remove it. If I try to set it as empty string it still doesn't work.

Can you add a way to do it?

Package name inconsistencies create issues on Windows

go: 1.13.6
os: windows

Windows treats GetStream and getstream as the same thing. When vendoring the library on windows and deploying to linux-based systems (i.e. via a Google Cloud function), the vendoring process will use github.com/GetStream for all packages.

However, there is a dependency on github.com/getstream/easyjson (which uses the lowercase convention) and the build tools will fail to find the vendored dependency when interacting with case-sensitive file systems / OSes.

It would be great if the package names were consistent to avoid this issue.

Channel Query function does not expose options

Stream docs Go example uses function ch.query which is not exposed. So the example does not work.

options := map[string]interface{}{ 
	"messages": map[string]interface{}{"limit": 50, "id_lt": lastMessageId}, 
	"members":  map[string]interface{}{"limit": 10, "offset": 0}, 
	"watchers": map[string]interface{}{"limit": 20, "offset": 0}, 
} 
 
ch.query(ctx, options, nil)

Changing the function to exposed ch.Query doesn't work either since that function does not allow passing options to it.

Thus I found no way to query channel messages with pagination using the Go client.

Outdated docs

The github README for this project refers to methods that are not showing up such as CreateChannelWithMembers, i'm guessing these were removed but the docs havent been updated?

Check token validity

Do we have any way to easily check a if a token is expired server-side ?

gz#7047

NewClient panics when http.RoundTripper is *otelhttp.Transport

Expected Behavior:
I should be able to construct a Go client instance with an http.Client where http.RoundTripper is *otelhttp.Transport

Actual Behavior:
NewClient panics

getting below error on creating clent"-

panic: interface conversion: http.RoundTripper is *otelhttp.Transport, not *http.Transport
goroutine 1 [running]:
github.com/GetStream/stream-chat-go/v6.NewClient({0x13fa848, 0xc}, {0x1430def, 0x40}, {0x0, 0x0, 0x8?})
/home/Rahul/go/pkg/mod/github.com/!get!stream/stream-chat-go/[email protected]/client.go:80 +0x3ea

`"server_key is not a valid"`after updating to latest verion when calling `client.UpdateAppSettings`

I recently updated to the latest version v3.12.1 (previously it seems that i was using v1.0.0, I didn't pay attention (or it was missing) to the README which shows both an import to /v3 and an installation step with /v3 at the end.
Here's my code right now -

	streamChatClient, err := streamchat.NewClient(streamKey, streamSecret)
	if err != nil {
		return nil, nil, err
	}
	streamChatClient.BaseURL = "https://chat-proxy-dublin.stream-io-api.com"
	err := streamChatClient.UpdateAppSettings(&streamchat.AppSettings{
		FirebaseConfig: &streamchat.FirebaseConfig{
			Enabled: true,
			DataTemplate: `{
    "sender": "{{ sender.id }}",
    "dm_id": "{{ channel.id }}",
    "message": "{{ message.id }}"
}`,
			NotificationTemplate: `{
	"title": "{{ sender.nickname }}",
	"body": "{{ message.text }}",
	"sound": "default"
}`,
		},
	})

but upon starting that code I get the following error -

chat-client: HTTP PATCH https://chat-proxy-dublin.stream-io-api.com/app?api_key=<snip> status 400 Bad Request: {"code":4,"message":"UpdateApp failed with error: \"server_key is not a valid\"","StatusCode":400,"duration":"0.00ms","more_info":"https://getstream.io/chat/docs/api_errors_response"}

What were some changes from v1 to v3 that could be causing this issue?

Drop client/channel interfaces

Linked to Zendesk issue

gz#6218

These interfaces should be defined by user and adds no benefit in SDK except maintenance burden.
Additionally, there are too big.

[BUG] QueryChannel pagination limit incorrect implementation

Hi people

According to the source code, pagination parameters for the channel querying should be passed within the filter_conditions.
In docs it is suggested to pass the query parameters on the root level of the payload JSON structure (queryChannelRequest struct in Go SDK instead of QueryOption nested struct).

References
In Go SDK:
https://github.com/GetStream/stream-chat-go/blob/master/query.go#L102

In docs:
https://getstream.io/chat/docs/query_channels/#query-options

Steps to reproduce

  1. Create at least two channels
  2. Call QueryChannels method without any pagination options passed
  3. Make sure you receive your channels in the response
  4. Call QueryChannels method with explicit pagination rules (limit: 10, offset: 1)

Expected
Channels are returned respecting the provided pagination parameters

Actual
Empty channels list is returned

Mute/Unmute/Mark as Read channel users in bulk

I have been searching for a way to mute/unmute/Mark as Read users in the same channel in bulk.

Since, I have not found any way I have to do this in loop. This increases the time taken per request due to multiple network RTTs, although I solved this by unblocking other requests of queue using go routines but would like to know if something like this exists for getting this task done in bulk in one shot ?

If not, can I expect any update related to this ?

Determine Channel ID

I just notice that in the other language the Channel ID is optional. But in this library, it's mandatory. So now I got duplicate channel, which one generated by the backend and the other one is generated by the front end.

I think this is the issue about the consistency. While other language allow it to be null, but in Go the Channel ID is mandatory.

Could you please solve this inconsistency issue?

gz#11081

Add tests

  • Export user
  • Deactivate user
  • Reactivate user
  • Delete user

Will need these tests to reference for chat docs

PaginationParamsRequest ID params incorrectly typed as `string`

PaginationParamsRequest is typed as string when it should be typed as int. This causes the request to fail with this error:

error: \"expected number for field \"watchers.id_gte\" but got number `0`\nexpected number for field \"watchers.id_gte.id_lte\" but got number `0`\""

CreateToken does not accept nil value for expiration

The CreateToken function should accept nil as a value for token expiration. The expire value is a time.Time type and it cannot be set to nil.

Also, the documentation on the site it wrong. It shows: token := client.CreateToken("john", null) which is a copy error as null isn't valid Go code.

id params on watchers does not work in the REST API / SDK

Passing id_gt or any other id params does not work, see the screenshot below of my Postman request returning user with id 15 even though I passed in id_gt: 100. This seems to be an issue with the REST API and no the go SDK but could not find a more appropriate place to open an issue so let me know if there is a more appropriate place to raise this issue. Thank you!

Screenshot 2024-03-27 at 6 03 24 PM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.