var ClientPool = function ()
{
this .poolSize = 0;
this .freeClients = [];
};
ClientPool.prototype.needClient = function ()
{
this .freeClients.push( this .newClient());
this .poolSize++;
};
ClientPool.prototype.newClient = function ()
{
return http.createClient(80, 'example.com' );
};
ClientPool.prototype.request = function (method, url, headers)
{
if ( this .freeClients.length == 0)
{
this .needClient();
}
var client = this .freeClients.pop();
var req = client.request(method, url, headers);
return req;
};
ClientPool.prototype.returnToPool = function (client)
{
this .freeClients.push(client);
};
var clientPool = new ClientPool();
* This source code was highlighted with Source Code Highlighter .
var getFile = function (url, path, callback)
{
fs.open(path, 'w' , 0600, function (err, fd)
{
if (err)
{
callback(err);
return ;
}
var request = clientPool.request( 'GET' , url, { 'Host' : 'example.com' });
request.on( 'response' , function (sourceResponse)
{
var statusCode = parseInt(sourceResponse.statusCode);
if (statusCode < 200 || statusCode > 299)
{
sourceResponse.on( 'end' , function ()
{
clientPool.returnToPool(sourceResponse.client);
});
callback( 'Bad status code' );
return ;
}
var writeErr = null ;
var writesPending = 0;
var sourceEnded = false ;
var checkPendingCallback = function ()
{
if (!sourceEnded || writesPending > 0)
{
return ;
}
fs.close(fd, function (err)
{
err = err ? err : writeErr;
if (err)
{
removeFile(path);
callback(err);
return ;
}
// No errors and all written
callback( null );
});
};
var position = 0;
sourceResponse.on( 'data' , function (chunk)
{
writesPending++;
fs.write(fd, chunk, 0, chunk.length, position, function (err, written)
{
writesPending--;
if (err)
{
writeErr = err;
}
checkPendingCallback();
});
position += chunk.length;
});
sourceResponse.on( 'end' , function ()
{
sourceEnded = true ;
checkPendingCallback();
clientPool.returnToPool(sourceResponse.client);
});
});
request.end();
});
};
* This source code was highlighted with Source Code Highlighter .
upstream sprite_gen { server 127.0.0.1:14239; } location / out_folder / { alias / var / sprite-gen / out_folder /; internal; } location / { alias / var / sprite-gen / out_folder /; try_files $ uri @transcoder; } location @transcoder { proxy_pass http: // sprite_gen; }
var outPath = '' ; //
var imageUrls = []; // .
var images = []; // .
var waitCounter = images.length;
var needCache = true ; // , ,
var handlePart = function (url, pth)
{
getFile(url, pth, function (err)
{
waitCounter--;
if (err)
{
removeFile(pth);
var pth = placeholder_path;
needCache = false ;
}
if (waitCounter == 0)
{
makeSprite(images, outPath, function (err)
{
if (err)
{
response.writeHead(500, {
'Content-Type' : 'text/plain' ,
});
response.end( 'Trouble' );
return ;
}
var headers = {
'Content-Type' : 'image/png' ,
'X-Accel-Redirect' : outUrl
};
if (needCache)
{
headers[ 'Cache-Control' ] = 'max-age:315360000, public' ;
headers[ 'Expires' ] = 'Thu, 31 Dec 2037 23:55:55 GMT' ;
}
else
{
headers[ 'Cache-Control' ] = 'no-cache, no-store' ;
headers[ 'Pragma' ] = 'no-cache' ;
}
response.writeHead(200, headers);
response.end();
});
}
});
};
for ( var i = 0; i < imageUrls.length)
{
handlePart(imageUrls[i], images[i]);
}
* This source code was highlighted with Source Code Highlighter .
var spriteScript = '/usr/bin/gm' ;
var placeholder = path.join(__dirname, 'placeholder.jpg' );
var getParams = function (count)
{
return ( 'montage +frame +shadow +label -background #000000 -tile ' + count + 'x1 -geometry +0+0' ).split( ' ' );
};
var removeFile = function (path)
{
fs.unlink(path, function (err)
{
if (err)
{
console.log( 'Cannot remove ' + path);
}
});
};
var cleanup = function (inPaths, placeholder)
{
for ( var i = 0; i < inPaths.length; i++)
{
if (inPaths[i] == placeholder)
{
continue ;
}
removeFile(inPaths[i]);
}
};
var makeSprite = function (inPaths, outPath, placeholder, callback)
{
var para = getParams(inPaths.length).concat(inPaths, outPath);
console.log([ 'run' , spriteScript, para.join( ' ' )].join( ' ' ));
var spriter = child_process.spawn(spriteScript, para);
spriter.stderr.addListener( 'data' , function (data)
{
console.log(data);
});
spriter.stdout.addListener( 'data' , function (data)
{
console.log(data);
});
spriter.addListener( 'exit' , function (code, signal)
{
if (signal != null )
{
callback( 'Internal Server Error - Interrupted by signal' + signal.toString());
return ;
}
if (code != 0)
{
callback( 'Internal Server Error - Code is ' + code.toString());
return ;
}
cleanup(inPaths, placeholder);
callback( null );
});
};
* This source code was highlighted with Source Code Highlighter .
var fileExpr = /^(?:source|sprite)\-(\d+)\b/;
var storagePath = '/tmp/' ;
var cleanupOldFiles = function ()
{
fs.readdir(storagePath, function (err, files)
{
if (err)
{
console.log( 'Cannot read ' + storagePath + ' directory.' ;
return ;
}
for ( var i = 0; i < files.length; i++)
{
var fn = files[i];
m = fileExpr.exec(fn);
if (!m)
{
continue ;
}
var pid = parseInt(m[1]);
if (pid == process.pid)
{
continue ;
}
removeFile(path.join(storagePath, fn));
}
});
};
* This source code was highlighted with Source Code Highlighter .
#!/usr/bin/env node
var child_process = require( 'child_process' );
var http = require( 'http' );
var path = require( 'path' );
var fs = require( 'fs' );
var routeExpr = /^\/?(\w)\/([^\/]+)\/(\d+)\/(\d+)x(\d+)\.png$/;
var fileCounter = 0;
http.createServer( function (request, response)
{
if (request.method != 'GET' )
{
response.writeHead(405, { 'Content-Type' : 'text/plain' });
response.end( 'Method Not Allowed' );
return ;
}
var m = routeExpr.exec(request.url);
if (!m)
{
response.writeHead(400, { 'Content-Type' : 'text/plain' });
response.end( 'Bad Request' );
return ;
}
var mode = m[1];
var chapter = m[2];
var timespec = parseInt(m[3]);
var width = parseInt(m[4]);
var height = parseInt(m[5]);
fileCounter++;
var moments = [timespec];
addWantedMoments(moments, mode)
var runner = function (moments, fileCounter, width, height)
{
var waitCounter = moments.length;
var outPath = path.join(storagePath, [ 'sprite' , process.pid, fileCounter].join( '-' ) + '.png' );
var needCache = true ;
for ( var i = 0; i < moments.length; i++)
{
handlePart(i, placeholder);
}
};
request.connection.setTimeout(0);
runner([].concat(moments), fileCounter, width, height);
}).listen(8080, '127.0.0.1' );
console.log( 'Server running at 127.0.0.1:8080' );
cleanupOldFiles();
* This source code was highlighted with Source Code Highlighter .
Source: https://habr.com/ru/post/102722/
All Articles