-
Notifications
You must be signed in to change notification settings - Fork 2
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
initial development #3
Conversation
* created an abstract class for polling an api
src/abstract-api-adapter.coffee
Outdated
super | ||
@interval = 1000 | ||
@lastReport = null | ||
@clearToPoll = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does clearToPoll
control? The name isn't obvious to me and I'm wondering if there's a better alternative
src/abstract-api-adapter.coffee
Outdated
processDone: (error, response, report, done) => | ||
@clearToPoll = true | ||
@report report | ||
if done? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done?(error, response)
which will specifically check if done
is a function rather than just nullish
* made method that deals with top level methodology * relies on implementing classes to perform a couple of methods
package.json
Outdated
"description": "A base adapter for Hubot", | ||
"main": "./src/base-adapter.coffee", | ||
"name": "hubot-abstract-api-adapter", | ||
"version": "0.0.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a fairly minor point in context, but just for good practice: this is certainly a large enough change to bump to warrant a minor bump.
src/abstract-api-adapter.coffee
Outdated
class AbstractAPIAdapter extends Adapter | ||
constructor: -> | ||
super | ||
@interval = 1000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be a constant (assuming external clients aren't supposed to change this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inherited classes and situation may dictate changes to this. eg if a server is refusing due to usage limits or high load we may choose to increase our poll interval.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, if this is intended I'd make this more explicit - e.g. a constructor argument that defaults to 1000.
src/abstract-api-adapter.coffee
Outdated
@interval = 1000 | ||
@lastReport = null | ||
@allowedToPoll = true | ||
throw new TypeError('Abstract class') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What? How are subclasses supposed to be able to instantiate this? http://stackoverflow.com/a/30560792/68051 has some good suggested approaches that'll do what you're looking for.
src/abstract-api-adapter.coffee
Outdated
super | ||
@interval = 1000 | ||
@lastReport = null | ||
@allowedToPoll = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could make the usage of this clearer by flipping the boolean, and renaming it to pollInProgress
.
src/abstract-api-adapter.coffee
Outdated
if response?.statusCode in [429, 503] | ||
@report { error: error, html: response?.statusCode, url: options.url } | ||
# Retry if the error code indicates temporary outage | ||
@getUntil options, filter, each, done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You've flipped the order of filter/each here.
src/abstract-api-adapter.coffee
Outdated
if not error and headers.statusCode is 200 | ||
parseResponse(JSON.parse(body), callback) | ||
else | ||
callback(error ? headers, null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling with error makes sense, but headers is a weird fallback. It's be good behaviour for this to be an actual Error
instance. Something like: new Error("Received #{headers.statusCode} response: #{body}")
would be better.
src/abstract-api-adapter.coffee
Outdated
# Format taken from https://github.com/github/hubot/blob/master/docs/scripting.md#making-http-calls | ||
requestObject.post(JSON.stringify(requestObject.payload)) (error, headers, body) -> | ||
if not error and headers.statusCode is 200 | ||
parseResponse(JSON.parse(body), callback) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd wrap the JSON.parse
in a try/catch, and then callback with an error complaining about the body if it fails. We're not checking the headers here to check we're getting JSON atm (which isn't 'perfect', but parsing optimistically is fine for this), and eventually we'll definitely hit an issue somewhere here somebody doesn't give us JSON back (some HTML error page or something), which currently will silently kill this method - it'll never call the callback at all.
src/abstract-api-adapter.coffee
Outdated
* @param {object} ids to use. ids = {user, flow, thread?} | ||
* @param {function} function to receive (error, new ids object). ids = {thread, comment?} | ||
### | ||
postUsing: (text, ids, callback) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we're not using promises here, and for done
in getUntil
/processDone
? It'd make this code and code using this tidier and more reliable (done right, you should get automatic error -> promise error propagation, rather than having to ensure we're guaranteed to call the callback in every case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does my not knowing promises yet count as a reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It counts as an extra good reason to do it, since they're a core part of lot of the rest of the codebase, and this will be a very convenient place to learn them :D. Jake Archibald has a good intro: https://developers.google.com/web/fundamentals/getting-started/primers/promises.
To be clearer on the end goal: it'd be nice if postUsing returned a promise, and didn't take callback
, and if getUntil
and processDone
both returned promises, and didn't take done
. Ping me if you've got any questions or if you need a hand, happy to help.
src/abstract-api-adapter.coffee
Outdated
requestObject = @robot.http(requestDetails.url) | ||
requestObject.header('Accept', 'application/json') | ||
for key, value of requestObject.headers | ||
requestObject.header(key, value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...what are these two lines doing? This seems very strange. Is this supposed to be looping over requestDetails
instead?
src/abstract-api-adapter.coffee
Outdated
return | ||
if @extractNext responseObject | ||
options.url = @extractNext responseObject | ||
@getUntil options, filter, each, done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipped filter/each here too.
This does suggest we haven't really tested this code... Can we have some automated tests for this somewhere to catch these issues? Here if that's easy, or an integration test in an example extending class somewhere else would be great.
It's true, this PR is relatively untested. It originated from a time before I'd started implementing alpha branches, so at the time couldn't test until implemented, and couldn't develop from this foundation until accepted. Since then I'm trialling a slightly different branch convention that should allow me to conduct dependant development while a PR is in progress. |
closes #4 |
Do I need to ignore this as there's no mention of marshmallows? ;-) |
package.json
Outdated
"hubot-mock-adapter": "^1.0.0", | ||
"hubot-slack": "^4.3.1", | ||
"resin-lint": "^1.4.0" | ||
"hubot": "^2.19.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this in devDependencies
rather than dependencies
?
###* | ||
* Given a set of ids make best effort to publish the text and pass on the published ids | ||
* @param {string} text to publish | ||
* @param {object} ids to use. ids = {user, flow, thread?} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the mentions of flow
and thread
mean that this is specific to Flowdock, and maybe as not as "abstract" as you intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every one of our chat systems uses a different terminology to mean the same thing. It's muddling me up so much that I've got a chart of the equivalences in my exercise book.
This said, the most common comms tool in resin is Flowdock, so where I've a choice I've used Flowdock's nouns.
* @param {string} text to publish | ||
* @param {object} ids to use. ids = {user, flow, thread?} | ||
### | ||
postUsing: (text, ids) -> new Promise (resolve, reject) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know nothing about writing hubot scripts, but should there also be a getUsing
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah. This is actually nothing to do with hubot's scripts and is a utility function for without context posting. Each adapter has a way of getting without context.
closes Should work(!) #1