profile
viewpoint
Raed Shomali shomali11 New York, NY http://www.RaedShomali.com A Software Engineer by Profession, a Photographer by Talent and a Joker by Nature.

shomali11/go-interview 2656

Collection of Technical Interview Questions solved with Go

shomali11/slacker 435

Slack Bot Framework

shomali11/util 179

A collection of useful utility functions

shomali11/parallelizer 40

Simplifies the parallelization of function calls.

shomali11/xsql 28

SQL Query Results Pretty Printing

shomali11/gridder 26

A Grid based 2D Graphics library

shomali11/fridge 12

A cache that resembles storing, restocking and retrieving items from a fridge

shomali11/commander 11

Command evaluator and parser

shomali11/xredis 11

Go Redis Client

shomali11/eventbus 6

Eventbus

pull request commentshomali11/slacker

Allow event handler to be configured

@smoya @mmcdole You are right.

I have another idea. How about we extract this switch block into its own method that returns bool and err to indicate whether a message was handled (by the internal logic), if so, no need to pass the event to the fallback handler, otherwise we do.

For example:

func (s *Slacker) isEventHandled(msg slack.RTMEvent) (bool, error) {
			switch event := msg.Data.(type) {
			case *slack.ConnectedEvent:
				if s.initHandler == nil {
					continue
				}
				go s.initHandler()
				return true, nil

			case *slack.MessageEvent:
				if s.isFromBot(event) {
					return false, nil
				}

				if !s.isBotMentioned(event) && !s.isDirectMessage(event) {
					return false, nil
				}
				go s.handleMessage(ctx, event)
				return true, nil

			case *slack.RTMError:
				if s.errorHandler == nil {
					continue
				}
				go s.errorHandler(event.Error())
				return true, nil

			case *slack.InvalidAuthEvent:
				return true, errors.New(invalidToken)

			default:
				return false, nil
			}
}

This way, the Listen method would look like this:

// Listen receives events from Slack and each is handled as needed
func (s *Slacker) Listen(ctx context.Context) error {
	s.prependHelpHandle()
	go s.rtm.ManageConnection()
	for {
		select {
		case <-ctx.Done():
			s.rtm.Disconnect()
			return ctx.Err()
		case msg, ok := <-s.rtm.IncomingEvents:
			if !ok {
				return nil
			}

			handled, err := s.isEventHandled(msg)
			if err != nil {
				return err
			}

			if handled {
				continue
			}

			if s.fallbackEventHandler == nil {
				continue
			}
			go s.fallbackEventHandler(event)
		}
	}

I think this might work for everyone? What do you guys think?

smoya

comment created time in 7 days

pull request commentshomali11/slacker

Allow event handler to be configured

I would like to hear both of your opinions on this @smoya and @mmcdole

The main issue I see is that if someone overrides the Event Handler, then the following methods are irrelevant https://github.com/shomali11/slacker/blob/master/examples/14/example14.go#L15-L29

Especially that overriding the event handler, would make those methods unusable as they are not being called internally. Moreover, the user will have to reimplement the message handling from scratch and rewriting a ton of the code to wire everything together.

It feels that this is not the right approach. So I went back and read your earlier messages about wanting to access the raw message.

What if we inserted a tracker here ... https://github.com/shomali11/slacker/blob/master/slacker.go#L143

So that things look like:

			go s.rawEventHandler(msg.Data)

			switch event := msg.Data.(type) {
			case *slack.ConnectedEvent:
				if s.initHandler == nil {
					continue
				}
				go s.initHandler()

			case *slack.MessageEvent:
				if s.isFromBot(event) {
					continue
				}

				if !s.isBotMentioned(event) && !s.isDirectMessage(event) {
					continue
				}
				go s.handleMessage(ctx, event)

			case *slack.RTMError:
				if s.errorHandler == nil {
					continue
				}
				go s.errorHandler(event.Error())

			case *slack.InvalidAuthEvent:
				return errors.New(invalidToken)

			default:
				if s.fallbackEventHandler == nil {
					continue
				}
				go s.fallbackEventHandler(event)
			}

This way you can have access to the raw event and have the ability to act upon it without having to reimplement everything else. Would this work for both of your cases?

smoya

comment created time in 9 days

issue commentshomali11/slacker

Username retrieval

I believe you will need to use the underlying slack-go library to get the "display name" Example 7 shows you how to access the library https://github.com/shomali11/slacker/blob/master/examples/7/example7.go

This is the users file https://github.com/slack-go/slack/blob/master/users.go

dmxrob

comment created time in 10 days

pull request commentshomali11/slacker

Allow event handler to be configured

@mmcdole If that is the desired behavior, I guess I am fine with @smoya's solution. Let's hope he resolves the conflicting files and we can merge it.

smoya

comment created time in 11 days

push eventshomali11/go-interview

Raed Shomali

commit sha 434db55b01dd64b99f54b5fc3efa6f7a26de3499

Print Trees in Zig Zag

view details

push time in 12 days

issue commentshomali11/slacker

This only works with "classic" slack apps

Absolutely! Some of the features here we suggested and/or created by awesome contributors! I definitely think we need to support both APIs just in case somehow. The question is how to make it as easy and intuitive to the user of slacker

I did some research. At the time when nlopes started the go-slack project, there was only support for RTM and slacker was built on top of that (https://github.com/slack-go/slack/blob/master/examples/websocket/websocket.go)

It seems that go-slack now supports an Events API as seen here (https://github.com/slack-go/slack/blob/master/examples/eventsapi/events.go). I wonder if we can leverage this somehow.

leetrout

comment created time in 17 days

issue commentshomali11/slacker

This only works with "classic" slack apps

Interesting. We will have to look into this further and see how it affects slacker and what we need to do to support both cases.

leetrout

comment created time in 17 days

issue closedshomali11/go-interview

2 is a prime number

clean implementation of prime numbers, however, 2 is a prime number :) https://github.com/shomali11/go-interview/blob/master/numbers/primes/primes.go

closed time in a month

golark

issue commentshomali11/go-interview

2 is a prime number

LOL! I am so embarrassed. Great catch!

golark

comment created time in a month

push eventshomali11/go-interview

Raed Shomali

commit sha 115de3e6efe3b18e5bca8d63b4fda1430f3100c6

Improve Prime test

view details

push time in a month

issue closedshomali11/slacker

Slack Side Setup?

What is required on the slack app setup side for the example 1 for the simple bot.Listen() to work for ping?

closed time in a month

alexcurtin

issue commentshomali11/slacker

Slack Side Setup?

Thank you @cimnine !

alexcurtin

comment created time in a month

issue closedshomali11/go-interview

Why we should set structure variable to nil after use?

Firstly, really appreciate your sharing the collection of Golang technical interview questions, which really help me to learn Golang as a beginner.

I have a question when I read your doubly lined list Implement. I found you will set the structure variable to nil after using it.

For example, in the following function: https://github.com/shomali11/go-interview/blob/master/datastructures/linkedlists/doublylinkedlists/doubly_linked_lists.go#L94

// GetIndexOf returns the index of the first occurence
func (s *DoublyLinkedList) GetIndexOf(value interface{}) int {
	index := 0
	current := s.head
	for current != nil {
		if value == current.Value {
			return index
		}
		current = current.Next
		index++
	}
	current = nil  <-- This line
	return -1
}

Will the function cause a leak if it isn't set to nil? It is probably a dumb question. Could you shed some light? Thanks in advance!

closed time in a month

horis233

issue commentshomali11/go-interview

Why we should set structure variable to nil after use?

That is probably unnecessary since the for loop will exist when the current is nil. Good catch!

horis233

comment created time in a month

issue commentshomali11/commander

Parsing of text with non-breaking space has incorrect results.

Good question. I think that this is something that slacker should be handling but I am open to learning your thoughts.

My only concern would be when does UTF-8 characters need to be handled and when should they not be. For example, when the user enters a UTF-8 character in the message.

kostrahb

comment created time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

You are most welcome! Thank you for inspiring this new change.

Hopefully this makes everything more intuitive and easier to work with

arusso

comment created time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

Ok. I pushed the changes. Check out the new examples and README.

Let me know if this is a better experience now.

arusso

comment created time in 2 months

push eventshomali11/slacker

Raed Shomali

commit sha 3156f073f291e5d57a20ce5ae792bdf038516e60

Add BotContext to clean up Handler Signatures

view details

push time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

I see what you mean.

I guess one way to clean things up for you and everyone else would be to remove the Client and RTM from the Response object and instead expand the AuthorizationFunc and Handler function to include some custom context object as a parameter which will include the Client and possibly any other future necessary stuff.

arusso

comment created time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

I am confused. Why would you need to create a new bot object?

Here is an example of what I mean:

package main

import (
	"context"
	"github.com/shomali11/slacker"
	"log"
)

func main() {
	bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

	authorizedUsers := []string{"<USER ID>"}

	authorizedDefinition := &slacker.CommandDefinition{
		Description: "Very secret stuff",
		AuthorizationFunc: func(request slacker.Request) bool {
			...
			client := bot.Client()
                         userInfo, _ := client.GetUserInfo(request.Event().User)
                         return AuthorizeFromDatabase("some-command", user.Profile.Email)
		},
		Handler: func(request slacker.Request, response slacker.ResponseWriter) {
			response.Reply("You are authorized!")
		},
	}

	bot.Command("secret", authorizedDefinition)

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	err := bot.Listen(ctx)
	if err != nil {
		log.Fatal(err)
	}
}
arusso

comment created time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

Come to think about it, we should probably remove access to the RTM and Client from the Response object since both are accessible from the Slacker object

arusso

comment created time in 2 months

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

You do not need the response object to access the Client. You can access it from the Slacker object too

https://github.com/shomali11/slacker/blob/master/slacker.go#L71

So when you do something like

bot := slacker.NewClient("<YOUR SLACK BOT TOKEN>")

You can get the client from bot.Client()

arusso

comment created time in 2 months

issue closedshomali11/slacker

Expose the slack client in AuthorizedFunc

We'd like to be able to authenticate a Slack user with a backend database that has no concept of Slack User IDs, but to get the requesting users profile details we need access to the Slack client. Simple example:

var myCommand = &slacker.CommandDefinition {
    ...
    AuthorizationFunc: func(request slacker.Request, client slack.Client) bool {
        ...
        userInfo, _ := client.GetUserInfo(request.Event().User)
        return AuthorizeFromDatabase("some-command", user.Profile.Email)
    },
    ...
}

closed time in 2 months

arusso

issue commentshomali11/slacker

Expose the slack client in AuthorizedFunc

You should be able to do that following Example 7

https://github.com/shomali11/slacker/blob/master/examples/7/example7.go

arusso

comment created time in 2 months

push eventshomali11/go-interview

Raed Shomali

commit sha 8cd7ee6c3ab2d9ea9144724467304a10cee11784

Primes

view details

push time in 2 months

push eventshomali11/gridder

Raed Shomali

commit sha cff664637ded33e0c98405d96052e3a77f3ed5c9

Improve README

view details

push time in 3 months

push eventshomali11/gridder

Raed Shomali

commit sha dfad6389320ae4d0918f1d52caf0af31dca54431

Add Dashes styles

view details

push time in 3 months

pull request commentavelino/awesome-go

Add Gridder

@panjf2000 Done. Improved it to be over 90%

shomali11

comment created time in 3 months

push eventshomali11/gridder

Raed Shomali

commit sha 1504bcaa1a5a1267ae38856a22e45e6706218d78

Add tests

view details

push time in 3 months

pull request commentavelino/awesome-go

Add Gridder

@panjf2000 Added gocover link

shomali11

comment created time in 3 months

push eventshomali11/gridder

Raed Shomali

commit sha d850b5eacca7a04f979a8bc2624115a8fadbaef2

Add tests

view details

push time in 3 months

more