GithubHelp home page GithubHelp logo

slacker's People

Contributors

emiln avatar supermomonga avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

slacker's Issues

Inappropriate NPE

Attempting to connect a bot just threw the following NullPointerException with Slacker 1.3.1:

boot.user=> (use 'slacker.client)
2015-07-08 09:05:45.355:INFO::nREPL-worker-0: Logging initialized @12086ms
nil
boot.user=> (emit! :slacker.client/connect-bot "...")
nil
boot.user=> Jul 08, 2015 9:05:47 AM clojure.tools.logging$eval650$fn__654 invoke
SEVERE: Error in ns=[slacker.client], handler=[slacker.client$eval8995$fn__8996@79b0cd8f]:
java.lang.NullPointerException: 
                                                                                 ...                     
                                                          clojure.data.json/read-str        json.clj: 278
                                                                                 ...                     
                                                          slacker.client/eval8995/fn      client.clj:  72
                                                                                 ...                     
                                                                  clojure.core/apply        core.clj: 624
slacker.client/handle/fn/state-machine--auto--/fn/inst-8925/state-machine--auto--/fn      client.clj:  48
   slacker.client/handle/fn/state-machine--auto--/fn/inst-8925/state-machine--auto--      client.clj:  44
                                clojure.core.async.impl.ioc-macros/run-state-machine  ioc_macros.clj: 940
                        clojure.core.async.impl.ioc-macros/run-state-machine-wrapped  ioc_macros.clj: 944
                         slacker.client/handle/fn/state-machine--auto--/fn/inst-8925      client.clj:  44
                                                                                 ...                     

This is very unhelpful as the user clearly hasn't supplied a null pointer.

Web interface for monitoring bot health

As a bot author it would be great if I could enable a simple webservice so I could query my running bots about their health status.

Expose REST endpoints for:

  • Checking if the bot is alive.
  • Perusing the logs.

Monitor websocket connectivity

Slacker currently stops working if the websocket connection dies and makes no attempt to reconnect. There are two critical aspects to this issue:

  • Slacker should keep track of its own connectivity.

Does the underlying websocket library support this?

Yes, gniazdo supports :on-error, :on-close, etc.

  • Slacker should take appropriate action in case of changes in connectivity.

What is that, though? It seems prudent to reconnect as quickly as possible if the connection comes back, but beyond that Slacker should probably just report connection issues in the typical emit! fashion.

Expose Slack's HTTP API through Slacker

Slack has a bunch of HTTP RPC-style methods, and it seems likely that users of Slacker will want to make use of them. As the token is already known to Slacker, it should be simple to provide a handy wrapper for calling the methods.

Some usage ideas:

1. Return a plain Clojure map

This would be a blocking call and returns everything from the server.

(slacker.method/emoji-list)
{:ok true,
 :emoji
 {:bowtie "https://my.slack.com/emoji/bowtie/46ec6f2bb0.png",
  :squirrel "https://my.slack.com/emoji/squirrel/f35f40c0e0.png",
  :shipit "alias:squirrel"}}

2. Return a promise-chan (non-blocking)

This would be a non-blocking call, and everything from the server would be put on the promise-chan when available. As a "rejected" promise-chan only contains nil, there's no way to communicate error messages, which is annoying.

(if-let [emojis @(slacker.method/emoji-list)]
  emojis
  :scary-error)

3. Register success and error handlers (non-blocking)

This would make use of the :ok value in the map to determine whether to call the success or error handler. It would pass on the content to the success-fn and the error to the error-fn. In both cases this seems to be just the map with the :ok key removed.

(slacker.method/emoji-list success-fn error-fn)

slacker.client/receive-message seems passes no arguments

I created a test branch of my slacker sample repository.

https://github.com/supermomonga/sample-slacker-pingpong/blob/1cc8a047b670c5ba1a66fd8afe3f4570e50c4dd8/src/sample_slacker_pingpong/core.clj#L16-L20

It tries to print passed args when some events happened (hello, message...).

I expect some arguments will be passed but it seems always passed no argument.

Here is the log when I run a bot with lein run command and tried some actions in my personal slack team's channel which have two members, bot and me.

hello args: nil
message args: nil
pin-added args: nil
message args: nil
pin-removed args: nil

Simple example project

Hi, I'm interested in writing slack bot in Clojure so found this project.
I'm trying to wrote a simple ping-pong example project.

https://github.com/supermomonga/sample-slacker-pingpong

But when I run lein run, the application seems immediately shutdown after (emit! :slacker.client/connect-bot api-token).

I couldn't figure out how to make the application keep alive after connected to slack, so could you advice me to make this example works?

Fix clojars deployment

The first attempt failed in several crucial ways:

  • The uploaded jar doesn't contain anything, really. Neither this library nor its dependencies.
  • There is no description, link to Github or anything.

Ditch login! and client!

I don't really see them point of having both functions publicly exposed with precisely the same returned mutable socket connection. They might as well be one call under the emit!/handle flow. You call

(emit! :slacker.client/connect "my-token")

and the client attempts to connect, emitting either

(emit! :slacker.client/connection-succeeded websocket-object)
;; or
(emit! :slacker.client/connection-failed error-message)

The application programmer can handle these events or not at their leisure. They can save the websocket-object if they need it, but they probably won't.

Report errors

Currently Slacker seems to fail silently if it can't connect to the Slack network over websocket. This failure should be reported. I will go so far as to consider this a bug as I didn't intend to hide the error.

Better testing solution

The current way of testing has several drawbacks:

  • The expectations library is shipped with the Slacker library, which shouldn't be necessary.
  • In build.boot the expectations library is loaded for absolutely every task, which isn't the intention.

Improve error handling in `handle`

Currently it's far too easy to crash the entire handle flow. If you have multiple handler for :topic and one of them fails, it can prevent the other handlers from running. This is particularly easy to achieve through simple arity mismatch.

Logging

It would be nice with a centralized logging system for Slacker. It seems obvious that all emitted events should be logged, and that any exceptions happening in handlers should be logged. It would be nice if this was handled by emit!, but was fully configurable by the bot author.

  • It should use tools.logging, which seems to be a good and easily configurable solution.
  • The README should be updated to explain logging.

Awaiting response

At times it would be great to be able to await a response to some emitted event.

(handle :add +)
(println (<!! (emit! :add 1 2 3)))

The idea is that any handler for :do-some-io can return a non-nil value, and this will be put onto the channel awaited by the function that called emit! :do-some-io. This raises a few questions, however, and answering these will be the first task of this story:

  • If multiple functions are awaiting feedback on the same topic, should they all be notified separately by all handlers of the topic?

Yes

  • When should these feedback channels close?

By the caller of emit!; warrants function split

This is actually a fairly difficult question to answer. It seems unlikely that any one handler will be able to ascertain that no future puts from other handlers could occur to the channel. This leaves the question of whether emit! should be split into two functions: one returning an open channel that handlers may communicate over, and one returning nil, opening no channels. I think this might be preferable as it does not risk leaving open channels everywhere, and does not require the caller of emit! to diligently close all open, unused feedback channels.

  • Do emit! and handle at this point provide a genuinely simpler and easier interface to the user, or are they really just reinventing core.async poorly?

They are warranted

If you wanted to do this without handle and emit!, you'd declare the following once:

(def publisher (chan))
(def publication (pub publisher first))

And the following for every pair of handle and emit! calls:

(let [handler (chan)]
  (sub publication :add handler)
  (go (let [[_ return-chan & args] (<! handler)]
        (>! return-chan (apply + args)))))

(let [return-chan (chan)]
  (go (>! publisher [:add return-chan 1 2 3])
  (println (<!! return-chan))))

While this is certainly not a big task, I do think handle and emit! provide an easy as well as simple way to deal with this very topic-centric flow.

  • What should happen when a handler returns nil? It is not legal to put on a channel.

Nothing is put

It is not safe to assume you can close the channel as more puts from other handlers may happen in the future. It is not legal to put nil on the channel either, so the sensible and most simple solution is most likely to just don't put anything on at all in this case.

More useful examples in README

I think the README should contain a simple (already has) and intermediate (lacking) example of using emit!/handle to actually achieve something. The examples should implement concepts that are relevant to bot authors.

Ideas:

  • Keep track of how often many messages the different users have sent and send this information to a channel when requested. (Intermediate)
  • Reprimand users when they use lewd language. (Simple)

Decide on event naming convention

A few suggestions:

subject-(past tense) verb

  • :connection-failed
  • :connection-succeeded
  • :message-sent

subject-noun

  • :connection-failure
  • :connection-success
  • :message-transmission

Improve unit test feedback

There's a cool new kid on the testing block and their name is matcha. It seems to provide excellent improvements on feedback so I think we should make the (simple) switch.

Rethink handle

Some questions

I think handle requires a rethink. The following questions seem to warrant some deliberation:

  • Why is handle concerned with docstrings?

I genuinely don't know. It shouldn't be.

  • Should handle return anything?

No.

That doesn't seem to make any sense. Returning a boolean regarding its success implies that failure is allowed. It should rather die horribly with whatever exception occurred if anything goes wrong, as you'd always call a failure to register a handler exceptional. If all goes well, you should receive nothing as return value.

A possible return value could be a channel onto which all emissions under the topic are put, but I would much prefer a separate function like handle-with-feedback for this. It is not really a part of the concept of registering handlers.

  • What is the simplest way to solve the task of attaching handling functions to events?

Just register a handler and return nil.

  • Could handle be divided into constituent parts? It seems to handle many things: subscribing handlers, spawning go loops, logging, error handling, spawning a go block with try/catch, computations, etc.

Probably.

Let's look into this during the refactoring taking place in this issue.

Some tasks

  • Make handle return nil.
  • Introduce handle-with-feedback (or some other name) which doesn't take a handle-fn and instead returns a channel onto which any event under the topic is pushed.

Closed

This isn't really driven by any requirement.

  • See if handle can be simplified (in terms of implementation and internals). It is currently quite messy.
  • Don't enforce (or support) supplying docstrings for handler functions.

Switch to Clojure 1.7

Clojure 1.7 has been released and the world at large is caught up in enormous celebrations. Slacker should join in, recover, and then eventually:

  • Update library from 1.6 to 1.7.
  • Figure out if transducers could improve the core code.

Needs more core.typed

The following open questions should be answered:

  • Is it possible to reason statically about matching handle and emit! calls (as described in the comment below)?

The following good-to-go tasks should just be implemented:

  • Annotate slacker.client.
  • Annotate slacker.converters
  • Annotate slacker.lookups

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.