UNPKG

5.23 kBtext/coffeescriptView Raw
1
2async = require 'async'
3pkgcloud = require 'pkgcloud'
4fs = require 'fs'
5pathutil = require 'path'
6{BufferStream, extend} = require('./util')
7ClientRack = require('./.').ClientRack
8{EventEmitter} = require 'events'
9
10class exports.Rack extends EventEmitter
11 constructor: (assets, options) ->
12 super()
13 options ?= {}
14 @maxAge = options.maxAge
15 @allowNoHashCache = options.allowNoHashCache
16 @on 'complete', =>
17 @completed = true
18 @on 'newListener', (event, listener) =>
19 if event is 'complete' and @completed is true
20 listener()
21 @on 'error', (error) =>
22 throw error if @listeners('error').length is 1
23 for asset in assets
24 asset.rack = this
25 @assets = []
26 async.forEachSeries assets, (asset, next) =>
27 asset.on 'error', (error) =>
28 next error
29 asset.on 'complete', =>
30 if asset.contents?
31 @assets.push asset
32 if asset.assets?
33 @assets = @assets.concat asset.assets
34 next()
35 asset.rack = this
36 asset.emit 'start'
37 , (error) =>
38 return @emit 'error', error if error?
39 @emit 'complete'
40
41 createClientRack: ->
42 clientRack = new ClientRack
43 clientRack.rack = this
44 clientRack.emit 'start'
45 clientRack
46
47 addClientRack: (next) ->
48 clientRack = @createClientRack()
49 clientRack.on 'complete', =>
50 @assets.push clientRack
51 next()
52
53 handle: (request, response, next) ->
54 response.locals assets: this
55 handle = =>
56 for asset in @assets
57 check = asset.checkUrl request.url
58 return asset.respond request, response if check
59 next()
60 if @completed
61 handle()
62 else @on 'complete', handle
63
64 writeConfigFile: (filename) ->
65 config = {}
66 for asset in @assets
67 config[asset.url] = asset.specificUrl
68 fs.writeFileSync filename, JSON.stringify(config)
69
70 deploy: (options, next) ->
71 options.keyId = options.accessKey
72 options.key = options.secretKey
73 deploy = =>
74 client = pkgcloud.storage.createClient options
75 assets = @assets
76 # Big time hack for rackspace, first asset doesn't upload, very strange.
77 # Might be bug with pkgcloud. This hack just uploads the first file again
78 # at the end.
79 assets = @assets.concat @assets[0] if options.provider is 'rackspace'
80 async.forEachSeries assets, (asset, next) =>
81 console.log asset.url
82 stream = null
83 if asset.gzip
84 stream = new BufferStream asset.gzipContents
85 else
86 stream = new BufferStream asset.contents
87 url = asset.specificUrl.slice 1, asset.specificUrl.length
88 headers = {}
89 for key, value of asset.headers
90 headers[key] = value
91 headers['x-amz-acl'] = 'public-read' if options.provider is 'amazon'
92 clientOptions =
93 container: options.container
94 remote: url
95 headers: headers
96 stream: stream
97 client.upload clientOptions, (error) ->
98 return next error if error?
99 next()
100 , (error) =>
101 if error?
102 return next error if next?
103 throw error
104 if options.configFile?
105 @writeConfigFile options.configFile
106 next() if next?
107 if @completed
108 deploy()
109 else @on 'complete', deploy
110
111 tag: (url) ->
112 for asset in @assets
113 return asset.tag() if asset.url is url
114 throw new Error "No asset found for url: #{url}"
115
116 url: (url) ->
117 for asset in @assets
118 return asset.specificUrl if url is asset.url
119
120 @extend: extend
121
122class ConfigRack
123 constructor: (options) ->
124 throw new Error('options.configFile is required') unless options.configFile?
125 throw new Error('options.hostname is required') unless options.hostname?
126 @assetMap = require options.configFile
127 @hostname = options.hostname
128
129 handle: (request, response, next) ->
130 response.locals assets: this
131 for url, specificUrl of @assetMap
132 if request.url is url or request.url is specificUrl
133 return response.redirect "//#{@hostname}#{specificUrl}"
134 next()
135 tag: (url) ->
136 switch pathutil.extname(url)
137 when '.js'
138 tag = "\n<script type=\"text/javascript\" "
139 return tag += "src=\"//#{@hostname}#{@assetMap[url]}\"></script>"
140 when '.css'
141 return "\n<link rel=\"stylesheet\" href=\"//#{@hostname}#{@assetMap[url]}\">"
142 url: (url) ->
143 return "//#{@hostname}#{@assetMap[url]}"
144
145
146exports.fromConfigFile = (options) ->
147 return new ConfigRack(options)