UNPKG

cloudinary

Version:

Cloudinary NPM for node.js integration

194 lines (160 loc) 6.88 kB
_ = require("underscore") https = require('https') #http = require('http') utils = require("./utils") config = require("./config") fs = require('fs') path = require('path') temp = require('temp') # Multipart support based on http://onteria.wordpress.com/2011/05/30/multipartform-data-uploads-using-node-js-and-http-request/ timestamp = -> Math.floor(new Date().getTime()/1000) build_upload_params = (options) -> params = timestamp: timestamp(), transformation: utils.generate_transformation_string(options), public_id: options.public_id, callback: options.callback, format: options.format, backup: options.backup, type: options.type, tags: options.tags ? utils.build_array(options.tags).join(",") if options.eager? params.eager = (for transformation, format of utils.build_array(options.eager) transformation = _.clone(transformation) format = transformation.format ? format _.filter([utils.generate_transformation_string(transformation), format], utils.present).join("/") ).join("|") params exports.upload_stream = (callback, options={}) -> temp_filename = temp.path() temp_file = fs.createWriteStream temp_filename, flags: 'w', encoding: 'binary', mode: 0o600 stream = write: (data) -> temp_file.write(new Buffer(data, 'binary')) end: -> temp_file.end() finish = (result) -> fs.unlink(temp_filename) callback.call(null, result) try exports.upload(temp_filename, finish, options) catch e finish(error: {message: e}) stream exports.upload = (file, callback, options={}) -> call_api "upload", callback, options, -> params = build_upload_params(options) if file.match(/^https?:/) params.file = file return params else return [params, file] exports.destroy = (public_id, callback, options={}) -> call_api "destroy", callback, options, -> return timestamp: timestamp(), type: options.type, public_id: public_id TEXT_PARAMS = ["public_id", "font_family", "font_size", "font_color", "text_align", "font_weight", "font_style", "background", "opacity", "text_decoration"] exports.text = (text, callback, options={}) -> call_api "text", callback, options, -> params = {timestamp: timestamp(), text: text} for k in TEXT_PARAMS when options[k]? params[k] = options[k] [params] exports.generate_sprite = (tag, callback, options={}) -> call_api "sprite", callback, options, -> transformation = utils.generate_transformation_string(_.extend(options, fetch_format: options.format)) return [{timestamp: timestamp(), tag: tag, transformation: transformation}] # options may include 'exclusive' (boolean) which causes clearing this tag from all other resources exports.add_tag = (tag, callback, public_ids = [], options = {}) -> exclusive = utils.option_consume("exclusive", options) command = if exclusive then "set_exclusive" else "add" call_tags_api(tag, command, callback, public_ids, options) exports.remove_tag = (tag, callback, public_ids = [], options = {}) -> call_tags_api(tag, "remove", callback, public_ids, options) exports.replace_tag = (tag, callback, public_ids = [], options = {}) -> call_tags_api(tag, "replace", callback, public_ids, options) call_tags_api = (tag, command, callback, public_ids = [], options = {}) -> call_api "tags", callback, options, -> return [{timestamp: timestamp, tag: tag, public_ids: utils.build_array(public_ids), command: command}] call_api = (action, callback, options, get_params) -> options = _.clone(options) api_key = options.api_key ? config().api_key ? throw("Must supply api_key") api_secret = options.api_secret ? config().api_secret ? throw("Must supply api_secret") [params, file] = get_params.call() params.signature = utils.api_sign_request(params, api_secret) params.api_key = api_key api_url = utils.api_url(action, options) boundary = utils.random_public_id() handle_response = (res) -> if _.include([200,400,401,500], res.statusCode) buffer = "" error = false res.on "data", (d) -> buffer += d res.on "end", -> return if error result = JSON.parse(buffer) result["error"]["http_code"] = res.statusCode if result["error"] callback(result) res.on "error", (e) -> error = true callback(error: e) else callback(error: {message: "Server returned unexpected status code - #{res.statusCode}"}) post_data = (new Buffer(EncodeFieldPart(boundary, key, value), 'ascii') for key, value of params when utils.present(value)) post api_url, post_data, boundary, file, handle_response true post = (url, post_data, boundary, file, callback) -> finish_buffer = new Buffer("--" + boundary + "--", 'ascii') length = 0 for i in [0..post_data.length-1] length += post_data[i].length length += finish_buffer.length if file? file_header = new Buffer(EncodeFilePart(boundary, 'application/octet-stream', 'file', path.basename(file)), 'binary') length += file_header.length + 2 length += fs.statSync(file).size post_options = require('url').parse(url) post_options = _.extend post_options, #host: 'localhost', #port: 8081, method: 'POST', headers: 'Content-Type': 'multipart/form-data; boundary=' + boundary, 'Content-Length': length post_request = https.request(post_options, callback) post_request.setTimeout 60 for i in [0..post_data.length-1] post_request.write(post_data[i]) done = -> post_request.write(finish_buffer) post_request.end() if file? post_request.write(file_header) file_reader = fs.createReadStream(file, {encoding: 'binary'}); file_reader.on 'data', (data) -> post_request.write(new Buffer(data, 'binary')) file_reader.on 'end', -> post_request.write(new Buffer("\r\n", 'ascii')) done() else done() EncodeFieldPart = (boundary, name, value) -> return_part = "--#{boundary}\r\n"; return_part += "Content-Disposition: form-data; name=\"#{name}\"\r\n\r\n" return_part += value + "\r\n" return_part EncodeFilePart = (boundary,type,name,filename) -> return_part = "--#{boundary}\r\n"; return_part += "Content-Disposition: form-data; name=\"#{name}\"; filename=\"#{filename}\"\r\n"; return_part += "Content-Type: #{type}\r\n\r\n"; return_part exports.direct_upload = (callback_url, options) -> params = build_upload_params(_.extend({callback: callback_url}, options)) params.signature = utils.api_sign_request(params, config().api_secret) params.api_key = config().api_key api_url = utils.api_url("upload", options) for k, v of params when not utils.present(v) delete params[k] return hidden_fields: params, form_attrs: {action: api_url, method: "POST", enctype: "multipart/form-data"}