Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to send a message without having Message struct? #39

Open
neufeldtech opened this issue Feb 4, 2020 · 4 comments
Open

Possible to send a message without having Message struct? #39

neufeldtech opened this issue Feb 4, 2020 · 4 comments

Comments

@neufeldtech
Copy link

Thanks for putting together this library, I'm just starting to explore it.
I was wondering if there is a recommended method to send an arbitrary message to a channel without needing to "Respond" to a message that has come in.

My [first] use case is that I want to send a message to a channel after receiving a webhook via the http-server.

I suppose one way that I might be able to achieve this is to have the webhook handler publish a joe.ReceiveMessageEvent event with the desired channel that I want to send a message to, then listen for this 'silent' event emitted and respond to it. This will likely work, but it seems like quite a workaround to achieve my goal.

Any insight you can provide would be appreciated.

Thanks

@fgrosse
Copy link
Contributor

fgrosse commented Feb 4, 2020

Hey there :)

I'm not 100% sure I understand the question completely but I guess you want to emit your own custom events? If that is true you can find general instructions for how to do that here: https://joe-bot.net/basics/events/ and

To get a better understanding of the event system you should check out https://joe-bot.net/recipes/events
The use case of triggering new events from received HTTP webhooks is actually described under the second link.

Let me know if the documentation answers your question or if we should improve the documentation in that area a little :)

@neufeldtech
Copy link
Author

neufeldtech commented Feb 5, 2020

After a bit more reading I figured out what I need to do.

I was defining functions like HandleDoorbell as a standalone function and registering it as a handler. In this way, I didn't have access to the parent Bot object, so I had no way to send a message through the adapter.

By following the pattern outlined on the site and attaching methods to the Bot receiver (if I'm using the terminology correctly), I can easily send an arbitrary message through the adapter:

My solution looks like:

func (b *Bot) HandleDoorbell(ctx context.Context, evt joehttp.RequestEvent) error {
	if evt.URL.Path == "/doorbell" {
		b.Adapter.Send("Someone is at the door!", "#general")
	}
	return nil
}

Regarding documentation - the notes that you've included in the recipe guides are great in isolation, but I found that I was searching for a complete example of how to link all of these 'best practices' together. Is there an example/starter template where this kind of code lives? If desired, I could help sketch out an example bot of how to put all of these pieces together.

@fgrosse
Copy link
Contributor

fgrosse commented Feb 8, 2020

I'm glad you found a solution. For your small code snipped I want to point you at Bot.Say(…) instead of b.Adapter.Send(…). It does the same thing but also takes care of error handling for you which can be convenient. Also it enables easier printf style formatting. Given your Bot is anonymously embedded (which I suggest doing) you can then write:

func (b *Bot) HandleDoorbell(ctx context.Context, evt joehttp.RequestEvent) error {
	if evt.URL.Path == "/doorbell" {
		b.Say("#general", "Someone is at the door!")
	}
	return nil
}

It depends on the adapter implementation if you can pass channel names like this (i.e. #general) but I will try that out when I have some time hacking on my own bots. Definitively is much better than passing channel IDs such as "CDEADBEAF").

About the "receiver" terminology, that actually comes from Go and means the receiver in a function definition which is the instance that a function is called upon 🤓

The examples provided are all a bit minimal but all of them should be fully executable (i.e. they have a main function and are actually compiled as part of the test suite. I agree however that full example bot can be very helpful for documentation purposes. Maybe we can create it at _examples/08_full? Alternatively maybe a dedicated repo at https://github.com/go-joe/example-bot would be better because a full example implementation should also contain configurations, deployments and tests and that could be a bit too much in the simple examples directories.

Even better would be an example that is actually deployed somewhere and does something. In that sense I would be happy to link to existing implementations that people put together and open sourced. Another approach could be to create a bot that is used by this repository, e.g. to great new people that submit an issue (e.g. https://github.com/go-joe/github-bot). Apart from greeting people I don't really have an idea though what else it could do. What are your thoughts on this? :)

@neufeldtech
Copy link
Author

neufeldtech commented Feb 9, 2020

I found b.Say() after I had posted the last comments 😉 .

I put together a more thorough example to try to explain the issues I'm dealing with that would be helpful in a complete example. I think a separate repo is appropriate for a 'full example', and maybe even a 'ready to use' Slack example is also appropriate, where it could show basic custom functionality.

As an aside, but related, there are two things that I'm struggling with at this time:

  1. If I implement a handler as a 'standalone function' then I no longer have access to the Bot object for logging, or to access any embedded items like a custom slack client. However, doing it this way makes unit testing possible with joetest
    See https://github.com/neufeldtech/joe-example/blob/master/pkg/bot/h_open_door.go for an example of this 'Standalone' function and how it's nicely testable: https://github.com/neufeldtech/joe-example/blob/master/pkg/bot/h_open_door_test.go

  2. If I implement a handler directly on a Bot struct, I have access to the parent methods which is great, but I can't figure out how to test this properly using joetest. The HandleDoorbell function is implemented on the Bot struct: https://github.com/neufeldtech/joe-example/blob/master/pkg/bot/h_handle_doorbell.go, however I can't figure out how to test this... https://github.com/neufeldtech/joe-example/blob/master/pkg/bot/h_handle_doorbell_test.go

Any feedback you can provide on how I might structure the code to address these issues would be appreciated, then once I have these things sorted out this might serve as a starting point for what code in an example repo could look like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants