X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=client.coffee;fp=client.coffee;h=a378480a3b05cf13ba33389fbe24b06e05d04f98;hb=d20d81a40aaf14801c8be6b94ff2e97dd54f15a1;hp=0000000000000000000000000000000000000000;hpb=6589bcee44f3a39963e630d053989b23fda16e9b;p=af-coffee.git diff --git a/client.coffee b/client.coffee new file mode 100644 index 0000000..a378480 --- /dev/null +++ b/client.coffee @@ -0,0 +1,76 @@ +fs = require 'fs' +async = require 'async' +af = require './api.coffee' + +token_file = "#{process.env.HOME}/.af-coffee-token" + +timeout = (ms, f) -> setTimeout f, ms + +# a session caches the api access token and prompts for the username and +# password if it goes stale. It re-tries API calls that fail due to +# invalid/expired token + +class Session + constructor: -> + @token = 0 + + api: (call, args..., callback) -> + async.waterfall [ + (callback) => + switch @token + when 0 + get_token callback + when -1 + login callback + else + callback null, @token + (token, callback) => + @token = token + af[call] @token, args..., callback + ], (err, result) => + # eg /app/xxx/stats sometimes returns 404 with wrong auth token + if err?.code is 403 or err?.code is 404 + @token = -1 + @api(call, args..., callback) + else + callback err, result + +ask = (opts, callback) -> + process.stdout.write opts.prompt + process.stdin.setEncoding 'utf8' + process.stdin.resume() + process.stdin.once 'data', (line) -> + if opts.silent + # send ^[[A^[[2K to move the cursor up one line, then clear that line + process.stdout.write new Buffer [27, 91, 65, 27, 91, 50, 75] + process.stdout.write opts.prompt + "***\n" + process.stdin.pause() + callback null, (line.substr 0, line.length - 1) + +get_token = (callback) -> + fs.readFile token_file, 'utf8', (err, token) -> + if err? + login callback + else + callback null, token + +login = (callback) -> + async.waterfall [ + (callback) -> async.series [ + (callback) -> ask prompt: 'username: ', callback + (callback) -> ask prompt: 'password: ', silent: true, callback + ], callback + ([username, password], callback) -> + af.login username, password, callback + (token, callback) -> + # wait for file write so there's no race condition if get_token gets called soon + fs.writeFile token_file, token, (err) -> + if err + console.log "Warning: couldn't cache auth token in #{token_file}: ", err + # don't pass on error, it's ok if we can't cache it + callback null, token + ], callback + + +exports.new_session = -> + return new Session()