Actionhero is a realtime multi-transport nodejs API Server with integrated cluster capabilities and delayed tasks
APACHE-2.0 License
Published by evantahler almost 11 years ago
You can send files from within actions using connection.sendFile()
. Here's an example:
connection.rawConnection.responseHttpCode = 404;
connection.sendFile('404.html');
next(connection, false);
Note that you can optionally modify responseCodes (for HTTP clients only). Be sure to set toRender = false
in the callback, as you have already sent data to the client, and probably don't want to do so again on a file request.
Published by evantahler almost 11 years ago
client.file('path/to/file', callback)
{
content: "<h1>ActionHero</h1>\nI am a flat file being served to you via the API from ./public/simple.html<br />",
context: "response",
error: null,
length: 101,
messageCount: 3,
mime: "text/html"
}
var client = new actionHeroClient();
client.action('cacheTest', {key: 'k', value: 'v'}, function(err, data){
// do stuff
});
client.events
hash. Do not use it any more.client.on('message')
to capture every message from the serverclient = new actionHeroClient;
client.on('connected', function(){ console.log('connected!') })
client.on('disconnected', function(){ console.log('disconnected :(') })
client.on('message', function(message){ console.log(message) })
client.on('alert', function(message){ alert(message) })
client.on('api', function(message){ alert(message) })
client.on('welcome', function(message){ appendMessage(message); })
client.on('say', function(message){ appendMessage(message); })
actionHeroClient.js
<script type="text/javascript" src="/public/javascript/actionHeroClient.js"></script>
<script type="text/javascript" src="/public/javascript/actionHeroClient.min.js"></script>
Published by evantahler almost 11 years ago
Published by evantahler almost 11 years ago
specHelper
so that spec connections can be reused between testsactionHero info
in favor of a simple 'echo' message to be more compatible across all operating systems on install.Published by evantahler almost 11 years ago
actionHero provides test helpers so that you may try your actions and tasks within a headless environment. We do this by including a specHelper
initializer which creates a server, testServer
when running within the test environment. Via the testServer
, you can easily call actions or tasks without making a real request.
We have chosen mocha as our test framework and should as our assertion tool which are included as dependancies within all new projects. You do not need to use these testing tools, but an example will be provided which makes use of them.
You also don't need to use these test helpers, and you may want to make a 'real' http or websocket request to test something specific. If this is the case, you can check out how actionHero tests its own servers for examples.
A new wiki page about testing has been created which contains much of this information
testServer
connection.messages
will contain all messages the connection has been sent (welcome messages, action responses, say messages, etc)input
can be either a api.specHelper.connection
object, or simply a hash of params, IE: {key: 'value'}
message
and connection
.api.specHelper.runAction('cacheTest', {key: 'key', value: 'value'}, function(message, connection){
// message is the normal API response;
// connection is a new connection object
})
/public
from the servermessage
and connection
where message
is a hash:var message = {
error : error, // null if everything is OK
content : (string), // string representation of the file's body
mime : mime, // file mime
length : length // bytes
}
process.env.NODE_ENV = 'test';
var should = require('should');
var actionHeroPrototype = require("actionHero").actionHeroPrototype;
var actionHero = new actionHeroPrototype();
var api;
describe('Action: Random Number', function(){
before(function(done){
actionHero.start(function(err, a){
api = a;
done();
})
});
after(function(done){
actionHero.stop(function(err){
done();
});
});
var firstNumber = null;
it('generates random numbers', function(done){
api.specHelper.runAction('randomNumber', function(response, connection){
response.randomNumber.should.be.a.Number;
response.randomNumber.should.be.within(0,1);
firstNumber = response.randomNumber;
done();
});
});
it('is unique / random', function(done){
api.specHelper.runAction('randomNumber', function(response, connection){
response.randomNumber.should.be.a.Number;
response.randomNumber.should.not.equal(firstNumber);
done();
});
});
});
test
environment, setting the shell's env with NODE_ENV=test
. You can alternatively set this explicitly in your tests with process.env.NODE_ENV = 'test'
npm test
using only mocha. This makes the test framework easier to understandactionProcessor
and cache
, we have changed from process.nextTick
to setImmediate
in an attempt to throttle incoming requests under heavy loadPublished by evantahler almost 11 years ago
simply remove the explicit call to 'node' in package.json
's scripts. This should help with cross-platform compatibility.
Published by evantahler almost 11 years ago
actionHero now uses grunt as its script-runner rather than Jake. We made the switch due to Grunt's overwhelming popularity in the node/js community so that it would be easier for new developers to feel comfortable with the actionHero ecosystem. Grunt and Jake serve a similar purpose (with similar functionality) within actionHero to run tests and provide a CLI for various commands (saving and loading the cache, enqeuing periodic tasks, etc).
A huge shoutout to Github user @nullivex for doing most of the work in this pull request. He's added Grunt's linting tools and other helpers to the project which will make actionHero even better.
Published by evantahler almost 11 years ago
Move api.cache
storage to individual redis keys rather than keeping all of the cache objects in a hash.
NONE OF YOU PREVIOUSLY CACHED OBJECTS WILL WORK WITH THIS NEW VERSION. THEY WILL BE LOST
api.config.general.cachePrefix
is now configurableapi.cache.clear
can be used to clear all items in the cacheapi.cache.dumpWrite
and api.cache.dumpRead
can be used to export and import the cache
Published by evantahler almost 11 years ago
Time for a dependent package update!
Published by evantahler almost 11 years ago
By popular request, we are changing the chat sub-system to provide more fine-grain control over access to chat rooms to API developers.
api.chatRoom.add
can be used for this, or you can append the array api.configData.general.startingChatRooms
api.chatRoom.del
api.chatRoom.setAuthenticationPatern
is used to define a room's access rules. 2 examples:api.chatRoom.setAuthenticationPatern('myRoom', 'type', 'websocket')
would only allow websocket clients inapi.chatRoom.setAuthenticationPatern('myRoom', 'auteneticated', true)
would only allow clients in which have previously been modified by connection.auteneticated = true; connection._original_connection.authenticated = true;
probably in an action or middleware.roomLeave
(socket and websocket)listenToRoom
and silenceRoom
as they had before, but listening to a room will follow the same authentication logic as joining a room (listen can now return an error)api.chatRoom.add(room, callback)
api.chatRoom.del(room, callback)
api.chatRoom.exists(room, callback)
api.chatRoom.setAuthenticationPatern(room, key, value, callback)
api.chatRoom.roomStatus(room, callback)
{
room: "myRoom",
membersCount: 2,
members: {
aaa: {id: "aaa", joinedAt: 123456789 },
bbb: {id: "bbb", joinedAt: 123456789 },
}
}
api.chatRoom.addMember(connection, room, callback)
api.chatRoom.removeMember(connection, callback)
This allows actionHero developers to crete environment-specific modifications to a general config.js
. This mirrors the config pattern in Rails and Express.
api.configData
to api.config
config.js
into a config
directory, rename it to config/config.js
confg.js
NODE_ENV
to choose environmentconfig/development.js
, config/production.js
, etc)production.json
config.js
to "file" rather than "api" so folks who boot the server will have a nicer experience. This also helps out demo.actionherojs.comA special call out is earned by @Spudz76 who took the time to go though all of acitonHero's source and clean it up for typos, formatting, readability, and other js-lint type bugs.
connection.remoteIp
and connection.remotePort
should now work behind most proxies, including those which append the port to the forwarded IP addressconnection.remoteIp
and connection.remotePort
should now work much better for IPv6 addresses, and also work behind proxies (thanks @yshaul, @genexp @macrauder, and @nullivex)api.utils.randomString
would sometimes return 'undefined' within the random string (@sylock)throw
in node v8.x.xPublished by evantahler almost 11 years ago
actionHero version 7.0.0 changes the task sub-sysem to be compatible with resque.
ok
, but was custom designed and integrating with other systems/ecosystems was hard. Resque's ecosystem is the largest redis-based task ecosystem so it was a natural fitgem install bundler
bundle install
rackup
any
and all
tasks has been sacrificed in order to move to resque. All tasks are now any
tasks, one and only one server will process that jobconfig.js
by queue name(s) to allow for more detailed control. You can still run more than 1 worker per actionHero processscheduler
daemon within actionHero. This can be toggled on in config.js
. You may run more than one scheduler in your cluster .all
tasks, there is no longer a reason for actionHero to keep an active watch on other peers in the cluster. The redis
initializer has been greatly simplified. There is no longer an explicit notion of peers
, and the related methods (api.redis.checkForDroppedPeers
and api.redis.ping
) are removedresque
initializer has been added, and the task
and taskProcessor
initializers have been removedjake
helpers for tasks have been added
api.tasks
. The complete set of public methods is now:
api.tasks.enqueue(taskName, params, queue, callback)
api.tasks.enqueueAt(timestamp, taskName, params, queue, callback)
api.tasks.enqueueIn(time, taskName, params, queue, callback)
api.tasks.del(queue, taskName, args, count, callback)
api.tasks.delDelayed(queue, taskName, args, callback)
api.tasks.enqueueRecurrentJob(taskName, callback)
api.tasks.stopRecurrentJob(taskName, callback)
api.tasks.details(callback)
api.tasks.details
should be used. api.tasks.getAllTasks
and api.tasks.getWorkerStatuses
are removedconfig.js
changes including
tasks
section for the resque workersDB
has been renamed database
HEAD
, OPTIONS
and TRACE
in the web serverprocess.exit()
when a warning is thrown (ie: a missing description). These errors will be logged and the action or task will not be loadedapi.cache
objects now will only run once a minute (previously 10 seconds)actionHero generate
will now also include the minimized version of actionHeroWebsocket.js
in the public directoryx-forwarded-for
detection for remote IP addresses has been improved (thanks @yshaul)websocket
server is now enabled by default in config.js
generateAction
will include the variable toDocument
allowing specific actions to be hidden from the documentation API responsePublished by evantahler almost 11 years ago
Having many calls to redis on each connection (to increment stats) significantly slowed down actionHero, even in an async world. We have changed how recording stats works to be on a timed buffer. We will store stat deltas locally and then write those deltas to redis at a fixed, configurable interval.
In this update, we remove the notion of 'global' and 'local' stats in favor of configurable stats storage hashes in redis. You can still emulate the behavior of 'global' and 'local' stats by supplying 2 backends of the form:
configData.stats = {
witeFrequency: 1000,
keys: [
'actionHero:stats',
'actionHero:stats:' + api.id
],
Method Updates:
api.stats.increment = function(key, count)
( no longer takes a callback )api.stats.get = function(key, collection, next)
(can optionally provide which backend hash to lookup from, collection
)api.stats.getAll = function(collections, next)
(can optionally provide which backend(s) hash to lookup from, collections
)api.stats.set
is removed
In simple tests, this speeds up the performance of actions about ~2x
exports.action
and exports.myTask
will each work.config.js
to inspect your project's paths so files are generated into the proper directory.myAction.js.coffee
. Only .js
files should be loaded inPublished by evantahler almost 11 years ago
This small release changes the behavior of mime modification released yesterday. 2 problems arose:
api.configData.servers.web.matchExtensionMime
is removed as an option from config.js
action.matchExtensionMimeType
, to be set per action you wish to modify response mime information.We have stopped removing extensions from posted params. Param sanitization can be done in a middleware or within the action. Behavior is now:
{ path: "/images/:imageName", action: "renderImage" }
site.com/images/profile.jpg
=> connection.params.imageName = "profile.jpg"
and connection.extension = "jpg"
{ path: "/ping/:url", action: "pingCheck" }
site.com/ping/google.com
=> connection.params.url = "google.com"
, and connection.extension = "com"
Published by evantahler almost 11 years ago
client.id
actionHeroWebSocket.js
. Be sure to update your projects.connection.extension
. You can access this in the actionapi.configData.servers.web.matchExtensionMime
)?OutputType
)
OutputType
removed as a reserved paramconfig.js
for new projects to automatically allow cross-origin requestsconfig.js
to enable this:
api.configData.servers.web. serverInformation
api.configData.servers.web. requestorInformation
connection.error
can now optionally be a hash or a string. This type will be maintained in the presentation back to the client for all server typesThanks to @jfgodoy for helping out with code in this release.
Published by evantahler about 11 years ago
Published by evantahler about 11 years ago
This release creates the option to break away from the traditional actionHero project structure by enabling custom paths for your project. Don't want your actions to live in __dirname + "/actions"
? No problem! You can update api.configData.general.paths
.
The default project layout doesn't change, and remains:
paths: {
"action": __dirname + "/actions",
"task": __dirname + "/tasks",
"public": __dirname + "/public",
"pids": __dirname + "/pids",
"log": __dirname + "/log",
"server": __dirname + "/servers",
"initializer": __dirname + "/initializers",
}
This replaces flatFileDirectory
and pidFileDirectory
as configuration options.
note: You will need to add the new paths section to your config.json
for your older actionHero projects to boot.
We are now using faye version 2.0.x and faye-redis version 0.2.x
This release also fixes some spelling mistakes (thanks Matt) and an issue booting the cluster on windows.
Published by evantahler about 11 years ago
This tiny release allows you to manually set PROJECT_ROOT as an environment variable to force actionHero to run from a specific directory rather than proces.cwd()
. This is useful when deploying actionHero applications on a server where symlinks will change under a running process.
Published by evantahler about 11 years ago
This release is a collection of minor fixes:
actionHero help
id
set by the server on connection, and not rely on uuid generation.actionHero startCuster
in dameon
mode. This fixes some bugs where you cluster-workers would fail to boot in certain OSsPublished by evantahler about 11 years ago
As this release contains security updates, it is recommended that all actionHero users upgrade ASAP.
api.connections.createCallback
is an array of functions to call on a new connection and api.connections.destroyCallbacks
will be called on destruction. Keep in mind that some connections persist (webSocket, socket) and some only exist for the duration of a single request. You will likely want to inspect connection.type in this middleware.connection.params
. Previously, any param allowed for any action would have made it into your action's run
method.api.configData.general.serverToken
as a key.Published by evantahler about 11 years ago
This release contains a small fix to bring back support for node v0.8.x
. This also introduces the logLevel
option on actions to set how verbose the server is when reporting the call of that action