ability to build executables
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
[commands]
|
||||
proj = subl --project project.sublime-project
|
||||
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
[commands]
|
||||
proj = open project.tmproj
|
||||
Generated
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
[commands]
|
||||
proj = subl --project project.sublime-project
|
||||
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
n
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2011 Craig Condon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+392
@@ -0,0 +1,392 @@
|
||||
## Beanpole - Routing framework
|
||||
|
||||
|
||||
### What are some features?
|
||||
|
||||
- Syntactic sugar (see below).
|
||||
- Works with many protocols: amqp, http, websockets, etc.
|
||||
- Hooking with other applications is a breeze with [daisy](https://github.com/spiceapps/daisy).
|
||||
- Works well with coffeescript
|
||||
|
||||
|
||||
### Projects using Beanpole
|
||||
|
||||
- [celeri](https://github.com/spiceapps/celeri) - CLI library
|
||||
- [bonsai](https://github.com/spiceapps/bonsai) - application server
|
||||
- [leche](https://github.com/spiceapps/leche) - Framework to build frontend / backend applications with the same code.
|
||||
- [daisy](https://github.com/spiceapps/daisy) - Expose beanpole to: http, websockets, amqp (rabbitmq), etc.
|
||||
- [beandocs](https://github.com/spiceapps/beandocs) - Generate documentation from your beanpole route comments.
|
||||
- [beanprep](https://github.com/spiceapps/beanprep) - Scans beans in a given directory, and installs their dependencies.
|
||||
- [cupboard](https://github.com/spiceapps/beanprep) - Reverse package manager.
|
||||
|
||||
### Beanpole ports
|
||||
|
||||
- [Actionscript](https://github.com/spiceapps/beanpole.as)
|
||||
- [C++](https://github.com/spiceapps/beanpoll)
|
||||
|
||||
### Overview
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
The basic route consists of a few parts: the `type` of route, and the `channel`. Here are some examples:
|
||||
|
||||
router.on('pull hello/:name', ...);
|
||||
|
||||
and
|
||||
|
||||
router.on('push hello/:name', ...);
|
||||
|
||||
|
||||
#### Push Routes:
|
||||
|
||||
- Used to broadcast a message, or change (1 to many).
|
||||
- Doesn't expect a response.
|
||||
- Multiple listeners per route.
|
||||
|
||||
#### Pull Routes:
|
||||
|
||||
- Used to request data from a particular route (1 to 1).
|
||||
- Expects a response.
|
||||
- One listener per route.
|
||||
- examples:
|
||||
- request to http-exposed route
|
||||
|
||||
|
||||
|
||||
Using both `push`, and `pull` allows you to **bind** to a particular route. For example:
|
||||
|
||||
|
||||
````javascript
|
||||
|
||||
var _numUsers = 0;
|
||||
|
||||
|
||||
//numUser getter / setter function
|
||||
function numUsers(value)
|
||||
{
|
||||
if(!arguments.length) return _numUsers;
|
||||
|
||||
_numUsers = value;
|
||||
|
||||
router.push('users/online', value);
|
||||
}
|
||||
|
||||
|
||||
//the request handler. This could be called in-app. It's also just as easily exposable as an API to http, websockets, etc.
|
||||
router.on('pull users/online', function(request)
|
||||
{
|
||||
request.end(numUsers());
|
||||
});
|
||||
|
||||
//pull num users initially, then listen for when num users changes.
|
||||
router.on('push -pull users/online', function(response)
|
||||
{
|
||||
//handle change here..
|
||||
console.log(response); //0, 3, 10...
|
||||
});
|
||||
|
||||
|
||||
|
||||
//triggers above listener
|
||||
numUsers(3);
|
||||
numUsers(10);
|
||||
|
||||
````
|
||||
|
||||
Okay, so you might have noticed I added something funky here: `-pull` - that's a tag. Tags are structured like so:
|
||||
|
||||
router.on('pull -tagName hello/:route', ...);
|
||||
|
||||
or, you can add a value to it:
|
||||
|
||||
router.on('pull -method=GET hello/:route', ...);
|
||||
|
||||
As mentioned above, you can only have *one* listener per `pull` route. HOWEVER, you can have multiple listeners per `pull` route *if* you provide different tag values. For example:
|
||||
|
||||
````javascript
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
* returns the given user
|
||||
*/
|
||||
|
||||
'pull -method=GET users/:userId': function(request)
|
||||
{
|
||||
//get the specific user
|
||||
},
|
||||
|
||||
/**
|
||||
* updates a user
|
||||
*/
|
||||
|
||||
'pull -method=UPDATE users/:userId': function(request)
|
||||
{
|
||||
//update user here
|
||||
},
|
||||
|
||||
/**
|
||||
* deletes a user
|
||||
*/
|
||||
|
||||
'pull -method=DELETE users/:userId': function(request)
|
||||
{
|
||||
//delete user
|
||||
}
|
||||
|
||||
});
|
||||
````
|
||||
|
||||
The above chunk of code is well suited for a REST-ful api without explicilty writing it *for* an http server. It can be used for any protocol. For example - say I wanted to *delete* a user using the code above:
|
||||
|
||||
````javascript
|
||||
|
||||
router.pull('users/' + someUserId, { tag: { method: 'DELETE'} }, function()
|
||||
{
|
||||
//delete user response
|
||||
});
|
||||
|
||||
````
|
||||
|
||||
You might have guessed - tags can be used to filter routes. Okay, onto something a little more advanced: **middleware**. Here's an example:
|
||||
|
||||
````javascript
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull authorize': function(request)
|
||||
{
|
||||
if(request.data.secret != 'superSecret')
|
||||
{
|
||||
request.end('You shall not pass!');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//onto the next route
|
||||
request.next();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -method=GET authorize -> my/profile': function(request)
|
||||
{
|
||||
request.end('Super secret stuff!');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
````
|
||||
|
||||
The token `->` denotes `my/profile` must go *through* the `authorize` route. Here are a few more use-cases:
|
||||
|
||||
````javascript
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull post/body': function(request)
|
||||
{
|
||||
//post http request body here. This is implemented in daisy
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull session': function(request)
|
||||
{
|
||||
//initialize cookies for the user. Again, implemented in daisy
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -method=POST post/body -> session -> upload/video': function()
|
||||
{
|
||||
//passed through 2 routes before getting here.
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull cache/:ttl': function(request)
|
||||
{
|
||||
//used to check if the *next* route is cached. If it is, then return the value vs continuing
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull cache/10000 -> some/heavy/request': function(request)
|
||||
{
|
||||
//do some heavy stuff here, but go through the cache route so it's not called on each request
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
````
|
||||
|
||||
Middleware is especially useful for a REST-ful interface:
|
||||
|
||||
````javascript
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
* returns the given user
|
||||
* @example /users/665468459
|
||||
*/
|
||||
|
||||
'pull users/:userId': function(request)
|
||||
{
|
||||
getUser(request.data.postId, funciton(user)
|
||||
{
|
||||
request.user = user;
|
||||
|
||||
//route being used as middleware?
|
||||
if(request.hasNext()) return request.next();
|
||||
|
||||
//return the user
|
||||
request.end(user);
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a post made by a particular user
|
||||
* @example /users/665468459/posts/54353499534
|
||||
*/
|
||||
|
||||
'pull users/:userId -> users/:userId/posts/:postId': function(request)
|
||||
{
|
||||
getPosts(request.user, request.data.postId, function(posts)
|
||||
{
|
||||
request.end(posts);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
````
|
||||
|
||||
Middleware can also be specified without using the token: `->`.An example:
|
||||
|
||||
|
||||
````javascript
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull my/*': function()
|
||||
{
|
||||
//authorize user
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull my/profile': function()
|
||||
{
|
||||
//goes through authorization first
|
||||
}
|
||||
});
|
||||
|
||||
````
|
||||
|
||||
Providing a wildcard `*` tells the router that **anything** after the route must go through it.
|
||||
|
||||
|
||||
### Methods
|
||||
|
||||
#### router.on(type[,listener])
|
||||
|
||||
Listens to the given routes
|
||||
|
||||
- `type` - string or object. String would contain the route. Object would contain multiple routes / listeners
|
||||
- `listener` - function listening to the route given.
|
||||
|
||||
|
||||
#### router.push(route[, data][, options])
|
||||
|
||||
- `type` - the channel broadcast a message to.
|
||||
- `data` - the data to push to the given route
|
||||
- `options` - options for the given route
|
||||
- `meta` - tags to use to filter out listeners
|
||||
|
||||
#### router.pull(route[, data][, options][, callback])
|
||||
|
||||
same as push, but expects a response
|
||||
|
||||
#### router.channels()
|
||||
|
||||
returns all registered channels
|
||||
|
||||
#### router.getRoute(route)
|
||||
|
||||
returns route expression
|
||||
|
||||
#### request.write(chunk)
|
||||
|
||||
Initializes a streamed response. Great for sending files
|
||||
|
||||
#### request.end([chunk])
|
||||
|
||||
Ends a response
|
||||
|
||||
#### request.hasNext()
|
||||
|
||||
Returns TRUE if there's a listener after the current one.
|
||||
|
||||
#### request.next()
|
||||
|
||||
Moves onto the next route.
|
||||
|
||||
#### request.forward(channel, callback)
|
||||
|
||||
Forwards the current request to the given channel
|
||||
|
||||
#### request.thru(channel[ ,options])
|
||||
|
||||
Treats the given channel as middleware
|
||||
|
||||
#### request.data
|
||||
|
||||
Data is added here
|
||||
|
||||
|
||||
### One last goodie
|
||||
|
||||
Beanpole works well with coffeescript:
|
||||
|
||||
|
||||
````coffeescript
|
||||
|
||||
router.on
|
||||
|
||||
#
|
||||
'pull -method=GET say/hello': ->
|
||||
"hello world!"
|
||||
|
||||
````
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>currentDocument</key>
|
||||
<string>lib/core/middleware/route/pushPull/pull/request.js</string>
|
||||
<key>documents</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>expanded</key>
|
||||
<true/>
|
||||
<key>name</key>
|
||||
<string>beanpole</string>
|
||||
<key>regexFolderFilter</key>
|
||||
<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
||||
<key>sourceDirectory</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>fileHierarchyDrawerWidth</key>
|
||||
<integer>200</integer>
|
||||
<key>metaData</key>
|
||||
<dict>
|
||||
<key>examples/bean.hello/beans/hello.core/index.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>14</integer>
|
||||
<key>line</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>columnSelection</key>
|
||||
<false/>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
<key>selectFrom</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>3</integer>
|
||||
<key>line</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>selectTo</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>14</integer>
|
||||
<key>line</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>examples/bean.hook.hello/beans/test/index.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>0</integer>
|
||||
<key>line</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>examples/ws/server.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>14</integer>
|
||||
<key>line</key>
|
||||
<integer>34</integer>
|
||||
</dict>
|
||||
<key>columnSelection</key>
|
||||
<false/>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
<key>selectFrom</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>3</integer>
|
||||
<key>line</key>
|
||||
<integer>34</integer>
|
||||
</dict>
|
||||
<key>selectTo</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>14</integer>
|
||||
<key>line</key>
|
||||
<integer>34</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>lib/core/concrete/collection.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>0</integer>
|
||||
<key>line</key>
|
||||
<integer>13</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/concrete/router.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>37</integer>
|
||||
<key>line</key>
|
||||
<integer>162</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>142</integer>
|
||||
</dict>
|
||||
<key>lib/core/controller.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>1</integer>
|
||||
<key>line</key>
|
||||
<integer>8</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/middleware/meta/rotate.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>60</integer>
|
||||
<key>line</key>
|
||||
<integer>22</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/middleware/route/pushPull/pull/request.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>0</integer>
|
||||
<key>line</key>
|
||||
<integer>14</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>openDocuments</key>
|
||||
<array>
|
||||
<string>lib/core/controller.js</string>
|
||||
<string>examples/bean.hello/beans/hello.core/index.js</string>
|
||||
<string>examples/bean.hook.hello/beans/test/index.js</string>
|
||||
<string>lib/core/concrete/collection.js</string>
|
||||
<string>lib/core/concrete/router.js</string>
|
||||
<string>lib/core/middleware/meta/rotate.js</string>
|
||||
<string>lib/core/middleware/route/pushPull/pull/request.js</string>
|
||||
<string>examples/ws/server.js</string>
|
||||
</array>
|
||||
<key>showFileHierarchyDrawer</key>
|
||||
<true/>
|
||||
<key>windowFrame</key>
|
||||
<string>{{0, 4}, {1470, 1024}}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
### Beans
|
||||
|
||||
Beans are a fancy name for **plugin**.
|
||||
|
||||
### Organization
|
||||
|
||||
This is still very much a work in progress, but personally, I try to stick to a few conventions which help organize my "beans". Here are some general rules I follow:
|
||||
|
||||
- All beans are placed in a single directory. The directory name depends on what the application does.
|
||||
- If the app serves one platform, then place the beans in `app/beans`;
|
||||
- If the app serves multiple platforms, then place the beans in:
|
||||
- `app/node/beans` for node.js specific beans.
|
||||
- `app/web/beans` for web-specific beans.
|
||||
- `app/shared/beans` for beans usable across all platforms.
|
||||
|
||||
- Bean names should reflect any RESTful API used in the bean.
|
||||
- Beans in NPM have `bean` prepended to the name e.g: `bean.database.mongo`.
|
||||
|
||||
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
|
||||
Start off with the category of the bean first, and then the subject. A few examples:
|
||||
|
||||
- database.mongo
|
||||
- database.redis
|
||||
- database.mysql
|
||||
|
||||
Using `database` as the category tells that all beans share the same API. I can easily add / remove any `database` bean I want without breaking the application.
|
||||
|
||||
|
||||
If you have a plugin that uses many plugins, then try this naming convention:
|
||||
|
||||
- `category`.core
|
||||
|
||||
And for beans that make up `category.core`:
|
||||
|
||||
- `category`.part.`subject`
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
- stream.core
|
||||
- stream.part.facebook
|
||||
- stream.part.twitter
|
||||
- stream.part.google
|
||||
|
||||
|
||||
Where all the **parts** make up `stream.core`. Remember that parts shouldn't do **anything**. They make-up core plugins. If you have a plugin that serves several plugins, split it up like so:
|
||||
|
||||
- posting.part.facebook
|
||||
- friends.part.facebook
|
||||
|
||||
You could also do something like:
|
||||
|
||||
- stream.core
|
||||
- group.core
|
||||
- group.part.stream.core `part of stream.core`
|
||||
|
||||
|
||||
Try and follow a RESTful naming convention. For example:
|
||||
|
||||
|
||||
- stream.core
|
||||
- stream.part.subscription.core `listening for streamed content, and sending off to registered subscribers`
|
||||
- stream.part.subscription.email `subscription listening to stream, and sending a newsletter`
|
||||
- stream.part.subscription.facebook `subscription listening to a stream, and posting out to facebook`
|
||||
|
||||
Note that `part` was dropped after `subscription`. I find it reduntant to use it after the first instance. We already know that `stream.part.subscription.core` is nothing without `stream.core`, so anything *after* that is also useless without the root plugin.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
These notes are just so I can straighten out ideas about the architecture.
|
||||
+1
@@ -0,0 +1 @@
|
||||
- modularized skyscraper
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
---------------------------------
|
||||
Abstracting beanpole:
|
||||
---------------------------------
|
||||
|
||||
Plugins *MUST NOT* know if whether a computer is networked. That job is delegated for *one* particular module: glue.core. If a client connects to a server, and contains a hook which acts like a plugin, the backend should treat it exactly as it would with a another networked server, or even internally. Glue.core would handle the handshake / authentication.
|
||||
|
||||
Likewise, connected servers using brazen must not handle communication with other servers differently than internally.
|
||||
|
||||
|
||||
For security sake, each channel must provide metadata identifying whether it's private, protected, or public. Channels default to private if it's absent.
|
||||
|
||||
- Public channels are available to call without authentication
|
||||
- Protected channels are available to call only by other crusted servers / clients
|
||||
- Private channels can only be handled within the application.
|
||||
|
||||
All metadata is handled by the parser / router.
|
||||
|
||||
|
||||
---------------------------------
|
||||
Routing:
|
||||
---------------------------------
|
||||
|
||||
The routing mechanism should parse syntactic sugar to identify how a particular channel is handled. Each channel must be separated by backslashes to allow for parameters. This is primarily for future implementation where beanpole might support HTTP requests.
|
||||
|
||||
'[type] [meta]* [channel_name]* [channel/:param] [additional]*'
|
||||
|
||||
- type: the type of channel - push, pull, ???
|
||||
- meta: information attached to channel help glue.core, and other handlers.
|
||||
- channel_name: the name of the channel. Private use from channel. Useful if channel needs to change, like a variable name.
|
||||
- channel: the physical channel separated/by/backslashes
|
||||
- additional: additional parameters specific to the channel type.
|
||||
|
||||
on push application/ready: function(data){}
|
||||
|
||||
'push private -pull application/ready'
|
||||
|
||||
on private pull of application ready passing through application exists:
|
||||
|
||||
'pull private application/exists -> application/ready': function(pull){ }
|
||||
|
||||
|
||||
Calling back:
|
||||
|
||||
There needs to be a way for modules handling a particular request to identify where it's coming from.
|
||||
|
||||
---------------------------------
|
||||
Types of channels:
|
||||
---------------------------------
|
||||
|
||||
- pull - (getting) channels which respond to a particular request which maybe pushed out at a later time. This is from the source that makes the "push" with the same name.
|
||||
- push - (setting) channels which are pushed out are used after a particular change has occurred. This is one to many.
|
||||
|
||||
Why I chose for push/pull to be different handlers with the same name:
|
||||
|
||||
Inspiration was actually taken back in the day when I was developing in Actionscript (I know, stfu). Bindable metadata was a slick way of getting a particular property from an object, and then sticking to it for any changes. For beanpole, "pull" would be the action of getting the current value of a particular "pod" (object), and "push" is the method of sticking to it.
|
||||
|
||||
Problems:
|
||||
|
||||
How do we distinguish single pulls from multiple pulls? For instance, for multiple pulls, I may want to "pull" stats from all the servers, but for a single pull, I may want to register a particular queue, and *only* send it to one instance.
|
||||
|
||||
Possible solutions:
|
||||
|
||||
on('pull multi…')
|
||||
|
||||
proxy.pull('multi…')
|
||||
|
||||
is a different channel handing than
|
||||
|
||||
on('pull…')
|
||||
proxy.pull('…')
|
||||
|
||||
So technically, if I register
|
||||
|
||||
proxy.on('pull get.name', …')
|
||||
proxy.on('pull multi get.name')
|
||||
|
||||
there wouldn't be any complaining, since I can call only one, or the other. Where the first one can be the *only* one, and the second one can have multiple. SO
|
||||
|
||||
proxy.pull('get.name')
|
||||
|
||||
would be the first one, and
|
||||
|
||||
proxy.pull('multi get.name')
|
||||
|
||||
would be the second one.
|
||||
|
||||
|
||||
Multiple pulls also need to return to the requestor how many items are handling the request. This probably needs to take on a response, ondata, and end approach similar to node.js's streaming api
|
||||
|
||||
Streaming:
|
||||
|
||||
Without adding too much shit to the architecture, there may come a time where content is streamed to the particular requestor. This could be highly beneficial for programs which send files back and forth. Something which beanpole isn't necessarily equipped for at the moment. So, without changing the architecture, perhaps providing a method for supporting such a feature. For example:
|
||||
|
||||
This could be used:
|
||||
|
||||
proxy.pull('get.file','text.txt', {
|
||||
data: function(buffer)
|
||||
{
|
||||
},
|
||||
end: function()
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
or this could be used:
|
||||
|
||||
proxy.pull('get.file','text.txt',function(body)
|
||||
{
|
||||
});
|
||||
|
||||
|
||||
But what about pulling from multiple sources?
|
||||
|
||||
proxy.pull('multi get.file', 'text.txt', function(source) //callback multiple times
|
||||
{
|
||||
source.on('data…
|
||||
});
|
||||
|
||||
|
||||
Hmmmm…
|
||||
|
||||
|
||||
--------------------------------
|
||||
Network Topology
|
||||
--------------------------------
|
||||
|
||||
The architecture, mainly glue.core must have the ability to manage connected servers. Many of which should only communicate to particular applications. For instance: Currently there are two applications on spice.io which register queue's to the queue app . Each application has a slave which handles the cue, but the queue must know which slaves to send to. So:
|
||||
|
||||
- Each app must have an identifier shared amongst other apps it needs to communicate with (_appId)
|
||||
- Since queues are protected, the handshake to between the queue app and the requester must be authenticated.
|
||||
- The queue must receive the app id, and know what apps to send to via registered channels.
|
||||
|
||||
What if there are dozens of slaves running across a cluster of servers?
|
||||
|
||||
there *must* be a way for glue.core to use a load-balancing mechanism to send individual pulls to servers: round robin, least connected, etc. Stats from servers to see which is less busy?
|
||||
|
||||
What if there are multiple singleton pulls registered to glue.core?
|
||||
|
||||
Duh, fucking round-robin that shit when a pull-request is made.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var ebnf = require('ebnf-diagram');
|
||||
|
||||
ebnf.fromFile(__dirname + '/syntax.ebnf', __dirname + '/diagram.png',3000, 1654);
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
+5
@@ -0,0 +1,5 @@
|
||||
"" {
|
||||
syntax = ('push' | 'pull') { tag } channel { '->' channel }.
|
||||
tag = '-' name [ '=' value ].
|
||||
channel = '/' { [':'] name '/' } ['*'].
|
||||
}
|
||||
Generated
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function init()
|
||||
{
|
||||
console.log('calling plugins to say hello...');
|
||||
|
||||
mediator.pull(' -multi say/hello', function(response)
|
||||
{
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'push init': init
|
||||
});
|
||||
|
||||
}
|
||||
Generated
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function sayHello(pull)
|
||||
{
|
||||
pull.end('Hello Friend!');
|
||||
}
|
||||
|
||||
|
||||
mediator.on({
|
||||
'pull -multi -public say/hello': sayHello
|
||||
});
|
||||
}
|
||||
Generated
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function sayHello(pull)
|
||||
{
|
||||
pull.end('Hello Neighbor!');
|
||||
}
|
||||
|
||||
|
||||
mediator.on({
|
||||
'pull -multi -public say/hello': sayHello
|
||||
})
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
beanpole.require(__dirname + '/beans').push('init');
|
||||
Generated
Vendored
+72
@@ -0,0 +1,72 @@
|
||||
var lazy = require('sk/core/lazy').callback;
|
||||
|
||||
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
var ops, sent = 0, received = 0, pulls = 0, capp = 0, interval;
|
||||
|
||||
function testSend(pull)
|
||||
{
|
||||
// console.log('received: %d', ++received);
|
||||
|
||||
/*if(received != sent)
|
||||
{
|
||||
console.log(recieved-sent)
|
||||
}*/
|
||||
|
||||
|
||||
pull.end(++received);
|
||||
}
|
||||
|
||||
function pushHook(data, err, request)
|
||||
{
|
||||
console.success('starting test.');
|
||||
|
||||
timeout(data, ++capp, request);
|
||||
}
|
||||
|
||||
function timeout(data, index, request)
|
||||
{
|
||||
var margin = 0;
|
||||
|
||||
setTimeout(function()
|
||||
{
|
||||
for(var i = ops.concurrent; i--;)
|
||||
{
|
||||
// console.log('sent %d', ++sent);
|
||||
|
||||
margin++;
|
||||
|
||||
|
||||
request.from.pull('test/send', function(rcv)
|
||||
{
|
||||
// console.log('received: %d', rcv);
|
||||
|
||||
//wait till everything's done. Stop if anything's missed.
|
||||
if(!(--margin))
|
||||
{
|
||||
console.log('#%d: done pulling %d requests from app #%d', ++pulls, ops.concurrent, index);
|
||||
timeout(request, index);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}, ops.speed);
|
||||
}
|
||||
|
||||
function init(op)
|
||||
{
|
||||
ops = op;
|
||||
console.success('ready: speed=%d, concurrent=%d', ops.speed, ops.concurrent);
|
||||
|
||||
console.success('Now open another terminal window with the same script'.underline);
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'push init': init,
|
||||
'pull -public test/send': testSend,
|
||||
'push hook/connection': pushHook
|
||||
});
|
||||
|
||||
}
|
||||
Generated
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
cli = require('sk/node/cli');
|
||||
|
||||
var ops = {};
|
||||
|
||||
process.stdout.write('num concurrent calls: ');
|
||||
|
||||
cli.next(function(arg)
|
||||
{
|
||||
ops.concurrent = Number(arg) || 10;
|
||||
|
||||
process.stdout.write('speed (ms): ');
|
||||
|
||||
cli.next(function(arg)
|
||||
{
|
||||
ops.speed = Number(arg) || 200;
|
||||
|
||||
|
||||
beanpole.require(['hook.core','hook.http.mesh']).
|
||||
require(__dirname + '/beans').push('init', ops);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
var lazy = require('sk/core/lazy').callback;
|
||||
|
||||
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
var myName;
|
||||
|
||||
function pushSayHello(guestName)
|
||||
{
|
||||
console.log('hello %s!', guestName);
|
||||
|
||||
if(this.from)
|
||||
{
|
||||
this.from.push('say/hello/back', myName);
|
||||
}
|
||||
}
|
||||
|
||||
function pushSayHelloBack(guestName, err, push)
|
||||
{
|
||||
console.log('%s said hello back!', guestName);
|
||||
}
|
||||
|
||||
function pushHook(data, err, push)
|
||||
{
|
||||
console.success('A person decided to join the partayyy.');
|
||||
push.from.push('say/hello', myName)
|
||||
}
|
||||
|
||||
function init(n)
|
||||
{
|
||||
myName = n;
|
||||
pushSayHello(n);
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'push init': init,
|
||||
'push hook/connection': pushHook,
|
||||
'push -public say/hello': pushSayHello,
|
||||
'push -public say/hello/back': pushSayHelloBack,
|
||||
})
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
argv = process.argv.concat();
|
||||
|
||||
argv.splice(0,2);
|
||||
|
||||
var name = argv[0];
|
||||
|
||||
function onName(name)
|
||||
{
|
||||
beanpole.require(['hook.core','hook.http.mesh']).
|
||||
require(__dirname + '/beans').push('init', name.toString().replace('\n',''));
|
||||
|
||||
process.stdin.removeListener('data', onName);
|
||||
};
|
||||
|
||||
if(name)
|
||||
{
|
||||
onName(name)
|
||||
}
|
||||
else
|
||||
{
|
||||
process.stdout.write('Name: ');
|
||||
process.stdin.on('data', onName);
|
||||
|
||||
process.openStdin();
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
var lazy = require('sk/core/lazy').callback;
|
||||
|
||||
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
var myName;
|
||||
|
||||
function pushSayHello(guestName)
|
||||
{
|
||||
console.log('hello %s!', guestName);
|
||||
|
||||
if(this.from)
|
||||
{
|
||||
this.from.push('say/hello/back', myName);
|
||||
}
|
||||
}
|
||||
|
||||
function pushSayHelloBack(guestName, push)
|
||||
{
|
||||
console.log('%s said hello back!', guestName);
|
||||
}
|
||||
|
||||
function pushHook(data, push)
|
||||
{
|
||||
console.success('A person decided to join the partayyy.');
|
||||
push.from.push('say/hello', myName)
|
||||
}
|
||||
|
||||
function init(n)
|
||||
{
|
||||
myName = n;
|
||||
pushSayHello(n);
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'push init': init,
|
||||
'push hook/connection': pushHook,
|
||||
'push -public say/hello': pushSayHello,
|
||||
'push -public say/hello/back': pushSayHelloBack,
|
||||
})
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
argv = process.argv.concat();
|
||||
|
||||
beanpole.require(['hook.http.mesh','hook.core']);
|
||||
|
||||
beanpole.on({
|
||||
'pull -public hook2': function()
|
||||
{
|
||||
this.next();
|
||||
},
|
||||
'pull -public hook2 -> thru/hook2 -> test/hook': function()
|
||||
{
|
||||
console.log("fetching account...");
|
||||
|
||||
return "Successfuly passed through remote middleware";
|
||||
},
|
||||
'push -public hook2/ready': function()
|
||||
{
|
||||
console.log("Connected to hook 2");
|
||||
|
||||
beanpole.pull('test/hook', function(message)
|
||||
{
|
||||
console.success(message);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
beanpole.push('init');
|
||||
beanpole.push('ready','hook1');
|
||||
|
||||
|
||||
console.log('hook1 is ready');
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
argv = process.argv.concat();
|
||||
|
||||
beanpole.require(['hook.http.mesh','hook.core']);
|
||||
|
||||
beanpole.on({
|
||||
|
||||
'pull -public thru/hook2': function()
|
||||
{
|
||||
console.log("Through hook 2");
|
||||
|
||||
|
||||
setTimeout(function(self)
|
||||
{
|
||||
console.success("done!")
|
||||
self.next();
|
||||
}, 500, this)
|
||||
},
|
||||
|
||||
'push -public hook1/ready': function()
|
||||
{
|
||||
console.log("Connected to hook 1");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
beanpole.push('ready','hook2');
|
||||
|
||||
|
||||
console.log('hook2 is ready');
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
argv = process.argv.concat();
|
||||
|
||||
beanpole.require(['hook.http.mesh','hook.core']);
|
||||
|
||||
beanpole.on({
|
||||
|
||||
'pull -public thru/hook3': function()
|
||||
{
|
||||
console.log('thru hook 3');
|
||||
|
||||
if(!this.next()) return "authenticated"
|
||||
},
|
||||
'push -public hook1/ready': function()
|
||||
{
|
||||
console.log("connected to hook 1");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
beanpole.push('ready','hook2');
|
||||
|
||||
|
||||
console.log('hook2 is ready');
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
var beanpole = require('../../lib/node').router(),
|
||||
express = require('express'),
|
||||
Url = require('url');
|
||||
|
||||
beanpole.require('middleware.core');
|
||||
|
||||
beanpole.on({
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -public basic/auth/root/pass -> basic/auth': function()
|
||||
{
|
||||
if(!this.next()) return 'authorized!';
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -public basic/auth -> auth/text': function()
|
||||
{
|
||||
return "authorized: " + this.user.name;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -public session -> test/session': function()
|
||||
{
|
||||
var sess = this.session.data;
|
||||
|
||||
if(!sess.numVisits) sess.numVisits = 0;
|
||||
|
||||
sess.numVisits++;
|
||||
|
||||
return 'Num Visits: '+sess.numVisits;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push init': function(init)
|
||||
{
|
||||
var srv = express.createServer(),
|
||||
channels = beanpole.channels();
|
||||
|
||||
|
||||
function initPath(path, expr)
|
||||
{
|
||||
srv.get('/' + path, function(req, res)
|
||||
{
|
||||
beanpole.pull(Url.parse(req.url).pathname, null, { meta: { stream: 1 }, req: req }, function(writer)
|
||||
{
|
||||
writer.on({
|
||||
response: function(headers)
|
||||
{
|
||||
if(headers.session)
|
||||
{
|
||||
res.setHeader('Set-Cookie', headers.session.http)
|
||||
}
|
||||
|
||||
if(headers.authorization)
|
||||
{
|
||||
res.statusCode = 401;
|
||||
res.setHeader('WWW-Authenticate', headers.authorization.http);
|
||||
}
|
||||
},
|
||||
write: function(data)
|
||||
{
|
||||
res.write(typeof data == 'object' ? JSON.stringify(data) : data);
|
||||
},
|
||||
end: function()
|
||||
{
|
||||
res.end();
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
for(var channel in channels)
|
||||
{
|
||||
var expr = channels[channel];
|
||||
|
||||
if(expr.type == 'pull' && expr.meta.public)
|
||||
{
|
||||
initPath(channel, expr);
|
||||
}
|
||||
}
|
||||
|
||||
srv.listen(8032);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function meta1(pull)
|
||||
{
|
||||
pull.end('metadata 1');
|
||||
}
|
||||
|
||||
function meta2(pull)
|
||||
{
|
||||
pull.end('metadata 2');
|
||||
}
|
||||
|
||||
function meta3(pull)
|
||||
{
|
||||
pull.end('metadata 3');
|
||||
}
|
||||
|
||||
function filterMeta(pull)
|
||||
{
|
||||
mediator.pull('meta', null, { meta: { group: pull.data.group } }, function(data)
|
||||
{
|
||||
pull.end(data || '');
|
||||
});
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'pull -public -rotate -group=1 meta': meta1,
|
||||
'pull -public -rotate -group=2 meta': meta2,
|
||||
'pull -public -rotate -group=3 meta': meta3,
|
||||
'pull -public meta/:group': filterMeta
|
||||
});
|
||||
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
var express = require('express');
|
||||
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function init(pull)
|
||||
{
|
||||
var srv = express.createServer();
|
||||
|
||||
mediator.pull('hook', function(data)
|
||||
{
|
||||
data.channels.forEach(function(channel)
|
||||
{
|
||||
srv.get('/'+channel.name, function(req, res)
|
||||
{
|
||||
var name = channel.name;
|
||||
|
||||
for(var param in req.params)
|
||||
{
|
||||
name = name.replace(':'+param,req.params[param])
|
||||
}
|
||||
|
||||
mediator.pull('-stream ' + name, function(writer)
|
||||
{
|
||||
writer.pipe(res);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
srv.listen(8032);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
console.log('Server running on port ' + 8032+'. try http://localhost:8032/meta/[1,2,3], or omit the number and watch them rotate.');
|
||||
|
||||
|
||||
mediator.on({
|
||||
'push init': init
|
||||
});
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
beanpole.require(['hook.core','hook.http.mesh']).require(__dirname + '/beans').push('init');
|
||||
Generated
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
function init()
|
||||
{
|
||||
var i = 0;
|
||||
|
||||
//default
|
||||
mediator.pull('load/site', { site: 'http://www.google.com/' }, function(chunk)
|
||||
{
|
||||
console.log('http://www.google.com chunk #%d', i++);
|
||||
});
|
||||
|
||||
//letting brazilnut handle the combining of buffers
|
||||
mediator.pull('-batch load/site', { site: 'http://www.engadget.com/' }, function(buffer)
|
||||
{
|
||||
console.log('done reading http://engadget.com with %d chunks.', buffer.length);
|
||||
});
|
||||
|
||||
|
||||
//streaming data
|
||||
mediator.pull('-stream load/site', { site: 'http://www.google.com/' }, function(reader)
|
||||
{
|
||||
var buffer = [];
|
||||
|
||||
reader.on({
|
||||
write: function(chunk)
|
||||
{
|
||||
buffer.push(chunk)
|
||||
},
|
||||
end: function()
|
||||
{
|
||||
console.log('done reading http://google.com with %d chunks.', buffer.length);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
mediator.on({
|
||||
'push init': init
|
||||
});
|
||||
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
var brazilnut = require('../../lib/node');
|
||||
|
||||
brazilnut.require(__dirname + '/beans').push('init');
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
var beanpole = require('../../lib/node').router(),
|
||||
Structr = require('structr');
|
||||
|
||||
|
||||
|
||||
function hello()
|
||||
{
|
||||
return "hello!.";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
beanpole.on({
|
||||
'pull hello/silly/world': hello
|
||||
})
|
||||
|
||||
var start = new Date();
|
||||
|
||||
for(var i = 10000; i--;)
|
||||
{
|
||||
beanpole.pull('hello/silly/world', function (res)
|
||||
{
|
||||
// console.log(res)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
console.log(new Date().getTime() - start.getTime());
|
||||
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
function all()
|
||||
{
|
||||
console.log('all');
|
||||
|
||||
if(!this.next())
|
||||
{
|
||||
console.log("DONE!")
|
||||
}
|
||||
}
|
||||
|
||||
function all2()
|
||||
{
|
||||
console.log("ROTATE")
|
||||
}
|
||||
|
||||
function thru()
|
||||
{
|
||||
console.log('thru');
|
||||
|
||||
if(!this.next())
|
||||
{
|
||||
console.log("CANNOT CONTINUE!")
|
||||
}
|
||||
}
|
||||
|
||||
function thru2()
|
||||
{
|
||||
console.log("THRU 2");
|
||||
this.next();
|
||||
}
|
||||
|
||||
function sayHi(message)
|
||||
{
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'dispatch /*': all,
|
||||
// 'dispatch -d /*': all2,
|
||||
'dispatch thru2': thru2,
|
||||
'dispatch thru2 -> thru': thru,
|
||||
'dispatch thru2 -> thru -> thru -> hello': sayHi
|
||||
});
|
||||
|
||||
// beanpole.dispatch('hello','world!');
|
||||
// beanpole.dispatch('hello','world!');
|
||||
beanpole.dispatch('hello','world!');
|
||||
Generated
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
exports.plugin = function(mediator)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
Generated
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
function hello1(pull)
|
||||
{
|
||||
return "hello 1!";
|
||||
}
|
||||
|
||||
function hello2(pull)
|
||||
{
|
||||
return "hello 2!";
|
||||
}
|
||||
|
||||
function hello3(pull)
|
||||
{
|
||||
return "hello 3!";
|
||||
}
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
//hello 3!
|
||||
beanpole.pull('say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 1!
|
||||
beanpole.pull('say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 2!
|
||||
beanpole.pull('say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 2!
|
||||
beanpole.pull('-name=group1 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 3!
|
||||
beanpole.pull('-name=group1 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 1!
|
||||
beanpole.pull('-name=group2 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello 1!
|
||||
beanpole.pull('-name=group2 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
|
||||
//NOTE: rotate=N is provided just so the properties aren't overridden
|
||||
'pull -name=group2 -rotate=3 say/hello': hello1,
|
||||
'pull -name=group1 -rotate=2 say/hello': hello2,
|
||||
'pull -name=group1 -rotate=1 say/hello': hello3
|
||||
});
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
function groupHello1(pull)
|
||||
{
|
||||
return "hello!";
|
||||
}
|
||||
|
||||
function groupHello2(pull)
|
||||
{
|
||||
return "hello again!";
|
||||
}
|
||||
|
||||
function groupHello3(pull)
|
||||
{
|
||||
return "hello for a third time!";
|
||||
}
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
//hello!
|
||||
//hello again!
|
||||
//hello for a third time!
|
||||
beanpole.pull('-multi say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello!
|
||||
//hello again!
|
||||
beanpole.pull('-multi -name=group1 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
|
||||
//hello for a third time!
|
||||
beanpole.pull('-multi -name=group2 say/hello', function(msg)
|
||||
{
|
||||
console.log(msg)
|
||||
});
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
|
||||
//-multi=N is set so props aren't overridden
|
||||
'pull -name=group2 -multi=3 say/hello': groupHello3,
|
||||
'pull -name=group1 -multi=2 say/hello': groupHello2,
|
||||
'pull -name=group1 -multi=1 say/hello': groupHello1
|
||||
});
|
||||
|
||||
beanpole.push('init')
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8080
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'push -public spice.io/theurld/ready': function()
|
||||
{
|
||||
console.log("READY");
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['http.server', 'http.gateway','hook.http','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
|
||||
router.push('hook/add','http://theurld.spice.io');
|
||||
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8081
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'pull -http hello': function()
|
||||
{
|
||||
return "Hello world!";
|
||||
},
|
||||
|
||||
'push -public head/ready': function()
|
||||
{
|
||||
console.log("READ READY");
|
||||
},
|
||||
|
||||
'push -public hook/ready': function()
|
||||
{
|
||||
console.log("LOL HOOKKS");
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['http.server', 'http.gateway','hook.http.mesh2','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
router.push('ready','hook');
|
||||
|
||||
router.pull('hooks/add', 'http://localhost:8080', function(){});
|
||||
|
||||
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8082
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'pull -http hello': function()
|
||||
{
|
||||
return "Hello world!";
|
||||
},
|
||||
|
||||
'push -public head/ready': function()
|
||||
{
|
||||
console.log("READ READY");
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['http.server', 'http.gateway','hook.http.mesh2','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
router.push('ready','hook');
|
||||
|
||||
router.pull('hooks/add', 'http://localhost:8080', function(){});
|
||||
|
||||
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8083
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'pull -http hello': function()
|
||||
{
|
||||
return "Hello world!";
|
||||
},
|
||||
|
||||
'push -public head/ready': function()
|
||||
{
|
||||
console.log("READ READY");
|
||||
},
|
||||
|
||||
'push -public hook/ready': function()
|
||||
{
|
||||
console.log("LOL HOOKKS");
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['hook.http.mesh','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
router.push('ready','hook');
|
||||
|
||||
router.pull('hooks/add', 'http://localhost:8080', function(){});
|
||||
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8083
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var id = Date.now();
|
||||
|
||||
console.log(id);
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'pull -http hello': function()
|
||||
{
|
||||
return "Hello world!";
|
||||
},
|
||||
|
||||
'push -public sibling/ready': function(id)
|
||||
{
|
||||
console.log("SIBLING READY: " + id);
|
||||
},
|
||||
|
||||
'push -public hook/ready': function()
|
||||
{
|
||||
if(this.from == router) return;
|
||||
|
||||
this.from.push('sibling/ready', id);
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['hook.http.mesh','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
router.push('ready','hook');
|
||||
|
||||
|
||||
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
router.params({
|
||||
'http.gateway': {
|
||||
http:{
|
||||
port: 8080
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
'pull -http hello': function()
|
||||
{
|
||||
return "Hello world!";
|
||||
},
|
||||
|
||||
'push -public hook/ready': function()
|
||||
{
|
||||
console.log("READY");
|
||||
},
|
||||
|
||||
'push -public duck': function()
|
||||
{
|
||||
console.log("DUCK!");
|
||||
}
|
||||
});
|
||||
|
||||
router.require(['http.server', 'http.gateway','hook.http.mesh2','hook.core']);
|
||||
|
||||
|
||||
router.push('init');
|
||||
router.push('ready','head');
|
||||
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
function intercept(pull)
|
||||
{
|
||||
//change the data
|
||||
pull.data.sport = 'soccer';
|
||||
|
||||
pull.next();
|
||||
}
|
||||
|
||||
function test(pull)
|
||||
{
|
||||
pull.end(pull.data.sport)
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
beanpole.pull('test', { sport: 'football' }, function(result)
|
||||
{
|
||||
console.log(result)
|
||||
});
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
'pull -intercept=sport te`st/interception': intercept,
|
||||
'pull test': test
|
||||
})
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
var beanpole = require('../../lib/node'),
|
||||
argv = process.argv.concat();
|
||||
|
||||
var router = beanpole.router(),
|
||||
router2 = beanpole.router();
|
||||
|
||||
|
||||
|
||||
var listen = {
|
||||
'push hello': function()
|
||||
{
|
||||
console.log('hello!')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
router.on(listen).dispose();
|
||||
router2.on(listen);
|
||||
|
||||
router.push('hello')
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
function delay()
|
||||
{
|
||||
setTimeout(function (self){ self.next(); }, this.data.seconds * 1000, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
beanpole.on({
|
||||
'push -filter=BOMB (say/hello or say/hello/world) or blah': function()
|
||||
{
|
||||
console.log("hello world!")
|
||||
},
|
||||
'push -filter=GOLD blah': function()
|
||||
{
|
||||
console.log("GO")
|
||||
},
|
||||
|
||||
'pull /*': function()
|
||||
{
|
||||
console.log("G")
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
beanpole.push('say/hello');
|
||||
beanpole.push('say/hello/world');
|
||||
beanpole.push('-filter=GOLD blah');
|
||||
beanpole.push('-filter=BOMB blah');
|
||||
beanpole.push('/');
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
|
||||
beanpole.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -overridable say/hello': function()
|
||||
{
|
||||
return "hello";
|
||||
},
|
||||
|
||||
|
||||
'pull say/hello': function()
|
||||
{
|
||||
return "hello world!"
|
||||
}
|
||||
});
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
|
||||
function sayHi()
|
||||
{
|
||||
console.log(this.data)
|
||||
console.log('hi')
|
||||
// this.next();
|
||||
if(!this.next()) return "don't pass " + this.data.name+ " "+this.data.last;
|
||||
}
|
||||
|
||||
function sayHi2()
|
||||
{
|
||||
console.log('pass!');
|
||||
|
||||
if(!this.next())
|
||||
{
|
||||
this.end("GO")
|
||||
}
|
||||
}
|
||||
|
||||
function sayHiCraig()
|
||||
{
|
||||
if(!this.next()) return "GO"
|
||||
}
|
||||
|
||||
function sayHi3()
|
||||
{
|
||||
if(!this.next()) return "hello";
|
||||
}
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
beanpole.pull('hello2/craig', function(result)
|
||||
{
|
||||
console.log(result)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function test2()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
'pull /*': function()
|
||||
{
|
||||
console.log("PSSS") ;
|
||||
this.next();
|
||||
},
|
||||
'pull hellotest': sayHi2,
|
||||
'pull hellotest -> hellotest -> hello2/:name': sayHi3
|
||||
});
|
||||
|
||||
// console.log(beanpole.routeMiddleware._routers.pull._collection._routes)
|
||||
|
||||
beanpole.push('init');
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
|
||||
beanpole.on({
|
||||
'pull name': function()
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
beanpole.push('name', function()
|
||||
{
|
||||
return "SLAYERS!";
|
||||
});
|
||||
|
||||
beanpole.push('name', 'PUSH');
|
||||
// beanpole.push('name', 'PUSH');
|
||||
// beanpole.push('name', 'PUSH');
|
||||
// beanpole.push('name', 'PUSH');
|
||||
// beanpole.push('name', 'PUSH');
|
||||
}, 100);
|
||||
|
||||
return 'PULL';
|
||||
},
|
||||
'push /*': function()
|
||||
{
|
||||
console.log("PUSH INITIALIZED!");
|
||||
this.next();
|
||||
},
|
||||
'push through': function(data)
|
||||
{
|
||||
console.log("delay!")
|
||||
setTimeout(function(self){ self.next(); }, 500, this)
|
||||
},
|
||||
'push -pull name': function(name)
|
||||
{
|
||||
console.log(name)
|
||||
},
|
||||
'push -pull name': function(name)
|
||||
{
|
||||
console.log(name)
|
||||
},
|
||||
/*'push name': function(name)
|
||||
{
|
||||
console.log(name +' PUSH')
|
||||
}*/
|
||||
});
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
|
||||
function sayHi2()
|
||||
{
|
||||
console.log('pass!');
|
||||
|
||||
// return 'ga'
|
||||
if(!this.next())
|
||||
{
|
||||
console.log("FAIL")
|
||||
}
|
||||
}
|
||||
|
||||
function sayHi3()
|
||||
{
|
||||
console.log(this.data)
|
||||
}
|
||||
|
||||
|
||||
function init()
|
||||
{
|
||||
beanpole.push('hello3', 'craig!');
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
'push hello2 -> hello2 -> hello2 -> hello2 -> hello2 -> hello2 -> hello': sayHi2,
|
||||
'push hello2': sayHi2,
|
||||
'push hello -> hello2 -> hello3': sayHi3
|
||||
})
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
function delay()
|
||||
{
|
||||
setTimeout(function (self){ self.next(); }, this.data.seconds * 1000, this);
|
||||
}
|
||||
|
||||
function sayHi()
|
||||
{
|
||||
return "I.";
|
||||
}
|
||||
|
||||
function sayHi2()
|
||||
{
|
||||
return "Love.";
|
||||
}
|
||||
|
||||
function sayHi3()
|
||||
{
|
||||
return "Coffee.";
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
for(var i = 3; i--;)
|
||||
{
|
||||
beanpole.pull('say/hi', function (res)
|
||||
{
|
||||
console.log(res)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
beanpole.on({
|
||||
'push init': init,
|
||||
'pull delay/:seconds': delay,
|
||||
'pull -rotate delay/1 -> say/hi': sayHi,
|
||||
'pull -rotate delay/2 -> say/hi': sayHi2,
|
||||
'pull -rotate delay/3 -> say/hi': sayHi3
|
||||
})
|
||||
|
||||
|
||||
beanpole.push('init');
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
var beanpole = require('../../lib/node');
|
||||
|
||||
var router = beanpole.router();
|
||||
|
||||
|
||||
|
||||
router.on({
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull /*': function()
|
||||
{
|
||||
console.log("THRU");
|
||||
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -two /*': function()
|
||||
{
|
||||
console.log("THRU MOO");
|
||||
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -two /hello/*': function()
|
||||
{
|
||||
console.log("THRU hoo");
|
||||
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull /hello/param/*': function()
|
||||
{
|
||||
console.log("THRU AGAIN");
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -t /hello/param/*': function()
|
||||
{
|
||||
console.log("THRU AGAIN");
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -t2 /hello/param/*': function()
|
||||
{
|
||||
console.log("THRU AGAIN");
|
||||
this.next();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -t3 /hello/param/*': function()
|
||||
{
|
||||
console.log("THRU AGAIN");
|
||||
this.next();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull hello/param': function()
|
||||
{
|
||||
console.log("HELLO!");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.pull('hello/param', function()
|
||||
{
|
||||
});
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title> Socket Test </title>
|
||||
<script src="http://localhost:6032/socket.io/socket.io.js" type="text/javascript"></script>
|
||||
<script src="index.js" type="text/javascript"> </script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
+2139
File diff suppressed because it is too large
Load Diff
+9
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title> Socket Test </title>
|
||||
<script src="http://localhost:6032/socket.io/socket.io.js" type="text/javascript"></script>
|
||||
<script src="index.js" type="text/javascript"> </script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
var beanpole = require('../../../../lib/core').router();
|
||||
|
||||
|
||||
|
||||
function pluginExample(router)
|
||||
{
|
||||
|
||||
var name = prompt("What's your name?", 'craig');
|
||||
var time = Number(prompt("When do you want an alert? (in seconds)", 1));
|
||||
|
||||
|
||||
function appendBody(message)
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = message;
|
||||
document.body.appendChild(div);
|
||||
}
|
||||
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull -public some/random/callback': function(request)
|
||||
{
|
||||
appendBody(request.data.message);
|
||||
|
||||
this.from.push('notify/clients', request.data);
|
||||
|
||||
request.end();
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push send/message': function(data)
|
||||
{
|
||||
beanpole.push('call/later', { channel: 'some/random/callback', data: { _id: new Date().getTime(), message: data.message }, sendAt: new Date().getTime() + data.delay})
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push -public notify/clients': function(data)
|
||||
{
|
||||
appendBody('notified from another client: '+ data.message);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
beanpole.on({
|
||||
'push -public -one spice.io/ready': function()
|
||||
{
|
||||
beanpole.push('send/message', { message: "hello " + name +"!", name: name, delay: time * 1000});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
require('../../../../lib/core/beans/hook.core').plugin(beanpole);
|
||||
require('../../../../lib/web/beans/hook.socket.io.client').plugin(beanpole);
|
||||
pluginExample(beanpole);
|
||||
|
||||
beanpole.push('ready','client');
|
||||
beanpole.push('init');
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
beanpole.require(['hook.core','hook.http.mesh']);
|
||||
|
||||
beanpole.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push init': function()
|
||||
{
|
||||
beanpole.push('ready', 'spice.io');
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'push -public call/later': function(data)
|
||||
{
|
||||
console.log('calling later');
|
||||
|
||||
var self = this;
|
||||
|
||||
setTimeout(function()
|
||||
{
|
||||
self.from.pull(data.channel, data.data, { inner: self.inner }, function(result)
|
||||
{
|
||||
console.log(result)
|
||||
})
|
||||
},Math.max(0, data.sendAt - new Date().getTime()));
|
||||
// setTimeout()
|
||||
}
|
||||
});
|
||||
|
||||
beanpole.push('init');
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
var beanpole = require('../../lib/node').router();
|
||||
|
||||
|
||||
beanpole.require(['hook.core','hook.socket.io.server','hook.http.mesh']);
|
||||
|
||||
beanpole.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push init': function()
|
||||
{
|
||||
beanpole.push('ready', 'spice.io');
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'pull -public say/hello': function()
|
||||
{
|
||||
return "hello MADRE!";
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'push -public client/ready': function()
|
||||
{
|
||||
console.log("CLIENT READY");
|
||||
this.from.pull('get/name', function(name)
|
||||
{
|
||||
console.log(name)
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
beanpole.push('init');
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
var Structr = require('structr'),
|
||||
Parser = require('./parser'),
|
||||
utils = require('./utils'),
|
||||
Request = require('./request'),
|
||||
Janitor = require('sk/core/garbage').Janitor;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* collection for routes
|
||||
*/
|
||||
|
||||
/**
|
||||
* IMPORTANT notes regarding this class
|
||||
* 1. you can have multiple explicit middleware (/path/*)
|
||||
*/
|
||||
|
||||
|
||||
var Collection = Structr({
|
||||
|
||||
/**
|
||||
* Constructor. What else do you think it is?
|
||||
*/
|
||||
|
||||
'__construct': function(ops)
|
||||
{
|
||||
|
||||
//the options for the router
|
||||
this._ops = ops || {};
|
||||
|
||||
//these are the channels parsed into a traversable route
|
||||
this._routes = this._newRoute();
|
||||
|
||||
//these get executed whenever there's a new "on"
|
||||
this._middleware = this._newRoute();
|
||||
|
||||
//the current route index. increments on every route!
|
||||
this._routeIndex = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'has': function(expr)
|
||||
{
|
||||
var routes = this.routes(expr);
|
||||
|
||||
for(var i = routes.length; i--;)
|
||||
{
|
||||
if(routes[i].target) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'route': function(channel)
|
||||
{
|
||||
return this._route(channel.paths);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'routes': function(expr)
|
||||
{
|
||||
var channels = expr.channels,
|
||||
routes = [];
|
||||
|
||||
for(var i = channels.length; i--;)
|
||||
{
|
||||
routes.push(this.route(channels[i]));
|
||||
}
|
||||
|
||||
return routes;
|
||||
},
|
||||
|
||||
/**
|
||||
* listens to the given expression for any chandage
|
||||
*/
|
||||
|
||||
'add': function(expr, callback)
|
||||
{
|
||||
var janitor = new Janitor();
|
||||
|
||||
for(var i = expr.channels.length; i--;)
|
||||
{
|
||||
janitor.addDisposable(this._add(expr.channels[i], expr.meta, callback));
|
||||
}
|
||||
|
||||
|
||||
|
||||
return janitor;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_add': function(channel, meta, callback)
|
||||
{
|
||||
var paths = channel.paths,
|
||||
isMiddleware = channel.isMiddleware,
|
||||
middleware = channel.thru,
|
||||
|
||||
//middleware isn't used explicitly. Rather, it's *injected* into the routes which ARE used. Remember that.
|
||||
//explicit middleware looks like some/path/*
|
||||
currentRoute = this._start(paths, isMiddleware ? this._middleware : this._routes, true);
|
||||
|
||||
//some explicit middleware might already be defined, so we need to get the *one* to pass through.
|
||||
var before = this._before(paths, currentRoute);
|
||||
|
||||
|
||||
if(middleware) this._endMiddleware(middleware).thru = before;
|
||||
|
||||
|
||||
//the final callback for the route
|
||||
var listener = {
|
||||
callback: callback,
|
||||
|
||||
//metadata for the expression
|
||||
meta: meta,
|
||||
|
||||
//keeps tabs for later use (in request)
|
||||
id: 'r'+(this._routeIndex++),
|
||||
|
||||
//this is a queue where the first item is executed first, then on until we reach the last item
|
||||
thru: middleware || before,
|
||||
|
||||
isMiddleware: channel.isMiddleware,
|
||||
|
||||
path: paths,
|
||||
|
||||
dispose: function()
|
||||
{
|
||||
var i = currentRoute.listeners.indexOf(listener);
|
||||
if(i > -1) currentRoute.listeners.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
currentRoute.meta = Structr.copy(meta, currentRoute.meta);
|
||||
|
||||
//at this point we can inject the listener into the current route IF it's middleware.
|
||||
if(isMiddleware) this._injectMiddleware(listener, paths);
|
||||
|
||||
|
||||
//now that we're in the clear, need to add the listener!
|
||||
if(!currentRoute.listeners) currentRoute.listeners = [];
|
||||
|
||||
|
||||
//now to add it. Please take remember, for MOST CASES, "_listeners" will only have one, especially for http / requests
|
||||
currentRoute.listeners.push(listener);
|
||||
|
||||
|
||||
|
||||
//the return statement allows for the item to be disposed of
|
||||
return listener;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_endMiddleware': function(target)
|
||||
{
|
||||
var current = target || {};
|
||||
|
||||
while(current.thru)
|
||||
{
|
||||
current = current.thru;
|
||||
}
|
||||
|
||||
return current;
|
||||
},
|
||||
|
||||
/**
|
||||
* injects explicit middleware (/path/*) in all the routes which go through its path
|
||||
*/
|
||||
|
||||
'_injectMiddleware': function(listener, paths)
|
||||
{
|
||||
//level is only important for
|
||||
listener.level = paths.length;
|
||||
|
||||
//need to go through *all* routes ~ even middleware, because middleware also have
|
||||
//routes to pass through ~ Inception.
|
||||
var afterListeners = this._after(paths, this._routes).concat(this._after(paths, this._middleware));
|
||||
|
||||
//go through ALL items to put before this route, but make sure the item we're replacing isn't higher
|
||||
//in the middleware chain, because higher methods will already *have* reference to this pass-thru
|
||||
for(var i = afterListeners.length; i--;)
|
||||
{
|
||||
var currentListener = afterListeners[i];
|
||||
|
||||
var currentMiddleware = currentListener.thru,
|
||||
previousMiddleware = currentListener;
|
||||
|
||||
while(currentMiddleware)
|
||||
{
|
||||
if(currentMiddleware.level != undefined)
|
||||
{
|
||||
if(currentMiddleware.level < listener.level)
|
||||
{
|
||||
previousMiddleware.thru = listener;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
previousMiddleware = currentMiddleware;
|
||||
currentMiddleware = currentMiddleware.thru;
|
||||
}
|
||||
|
||||
if(!currentMiddleware) previousMiddleware.thru = listener;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* reveals routes which must come *before* a middleware
|
||||
* after beats circular references
|
||||
* TODO: following code is __ugly as fuck__.
|
||||
*/
|
||||
|
||||
'_before': function(paths, after)
|
||||
{
|
||||
var current = this._middleware,
|
||||
listeners = [];
|
||||
|
||||
for(var i = 0, n = paths.length; i < n; i++)
|
||||
{
|
||||
|
||||
//this makes sure we don't get to the end for pass thrus
|
||||
if(current.listeners) listeners = current.listeners;
|
||||
|
||||
|
||||
var path = paths[i],
|
||||
|
||||
newCurrent = path.param ? current._route._param : current._route[path.name];
|
||||
|
||||
|
||||
if(current == after || !newCurrent) break;
|
||||
|
||||
current = newCurrent;
|
||||
}
|
||||
|
||||
|
||||
// if(current != after)
|
||||
//this is a check against pass thrus to beat circular references. It *also* allows this: hello/* -> hello
|
||||
if(current != after && current.listeners) listeners = current.listeners;
|
||||
|
||||
return listeners[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* reveals everyhing that comes *after* a route (for pass-thru's)
|
||||
*/
|
||||
|
||||
'_after': function(paths, routes)
|
||||
{
|
||||
return this._flatten(this._start(paths, routes));
|
||||
},
|
||||
|
||||
/**
|
||||
* returns the starting point of a route
|
||||
*/
|
||||
|
||||
'_route': function(paths, routes, create, retControl)
|
||||
{
|
||||
var control = (routes || this._routes),
|
||||
current = control._route;
|
||||
|
||||
for(var i = 0, n = paths.length; i < n; i++)
|
||||
{
|
||||
var path = paths[i],
|
||||
name = path.param ? '_param' : path.name;
|
||||
|
||||
if(!current[name] && create)
|
||||
{
|
||||
current[name] = this._newRoute(i);
|
||||
}
|
||||
|
||||
if(current[name])
|
||||
{
|
||||
current = current[name];
|
||||
}
|
||||
else
|
||||
{
|
||||
current = current._param;
|
||||
}
|
||||
|
||||
|
||||
if(!current) return {};
|
||||
|
||||
control = current;
|
||||
current = current._route;
|
||||
}
|
||||
|
||||
|
||||
return control;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_start': function(paths, routes)
|
||||
{
|
||||
return this._route(paths, routes, true);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_newRoute': function(level)
|
||||
{
|
||||
return { _route: { }, _level: level || 0 };
|
||||
},
|
||||
|
||||
/**
|
||||
* flattens all routes into a single array
|
||||
*/
|
||||
|
||||
'_flatten': function(route)
|
||||
{
|
||||
var listeners = route.listeners ? route.listeners.concat() : [];
|
||||
|
||||
|
||||
for(var path in route._route)
|
||||
{
|
||||
listeners = listeners.concat(this._flatten(route[path] || {}));
|
||||
}
|
||||
|
||||
return listeners;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = Collection;
|
||||
+595
@@ -0,0 +1,595 @@
|
||||
|
||||
var Structr = require('structr');
|
||||
|
||||
/**
|
||||
* parses syntactic sugar.
|
||||
|
||||
Why the hell are you using a parser for something so simple? Because I wanted to. Yeah, I could have done it in Regexp, but fuck that >.>... This
|
||||
Is much more fun.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
//follow the pattern below when adding tokens plz.
|
||||
|
||||
var Token = {
|
||||
|
||||
// A-Z
|
||||
WORD: 1,
|
||||
|
||||
// -metadata
|
||||
METADATA: 1 << 1,
|
||||
|
||||
|
||||
// =
|
||||
PATH: 1 << 2,
|
||||
|
||||
|
||||
// :param
|
||||
PARAM: 1 << 3,
|
||||
|
||||
// ->
|
||||
TO: 1 << 4,
|
||||
|
||||
// for routing
|
||||
BACKSLASH: 1 << 5,
|
||||
|
||||
// .
|
||||
DOT: 1 << 6,
|
||||
|
||||
// * - this is an auto-middleware
|
||||
STAR: 1 << 7,
|
||||
|
||||
// "or"
|
||||
OR: 1 << 8,
|
||||
|
||||
// (
|
||||
LP: 1 << 9,
|
||||
|
||||
// )
|
||||
RP: 1 << 10,
|
||||
|
||||
// =
|
||||
EQ: 1 << 11,
|
||||
|
||||
|
||||
//whitespace
|
||||
WHITESPACE: 1 << 12
|
||||
};
|
||||
|
||||
|
||||
//reserved keywords
|
||||
var Reversed = {
|
||||
or: Token.OR
|
||||
}
|
||||
|
||||
|
||||
var Tokenizer = function()
|
||||
{
|
||||
|
||||
//source of the string to tokenize
|
||||
var source = '',
|
||||
|
||||
//the position of the parser
|
||||
pos = 0,
|
||||
|
||||
//the current token
|
||||
currentToken,
|
||||
|
||||
self = this;
|
||||
|
||||
|
||||
/**
|
||||
* getter / setter for the source
|
||||
*/
|
||||
|
||||
this.source = function(value)
|
||||
{
|
||||
if(value)
|
||||
{
|
||||
source = value+' '; //padding
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* next token
|
||||
*/
|
||||
|
||||
this.next = function(keepWhite)
|
||||
{
|
||||
return currentToken = nextToken(keepWhite);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
this.peekChars = function(n)
|
||||
{
|
||||
return source.substr(pos, n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
this.current = function(keepWhite)
|
||||
{
|
||||
return currentToken || self.next(keepWhite);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
this.position = function()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var nextToken = function(keepWhite, ignoreError)
|
||||
{
|
||||
if(!keepWhite) skipWhite();
|
||||
|
||||
if(eof()) return null;
|
||||
|
||||
var c = currentChar(), ccode = c.charCodeAt(0);
|
||||
|
||||
if(isWhite(ccode))
|
||||
{
|
||||
|
||||
skipWhite();
|
||||
return token(' ',Token.WHITESPACE);
|
||||
}
|
||||
|
||||
//a-z0-9
|
||||
if(isAlpha(ccode))
|
||||
{
|
||||
var w = nextPath();
|
||||
|
||||
return token(w, Reversed[w.toLowerCase()] || Token.WORD);
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch(c)
|
||||
{
|
||||
|
||||
//for middleware
|
||||
case '-':
|
||||
if(nextChar() == '>') return token('->', Token.TO, true);
|
||||
if(isAlpha(currentCharCode())) return token(nextPath(), Token.METADATA);
|
||||
|
||||
error();
|
||||
|
||||
//parameters for routes
|
||||
case ':':
|
||||
if(isAlpha(nextCharCode())) return token(nextPath(), Token.PARAM);
|
||||
|
||||
error();
|
||||
|
||||
case '/': return token('/', Token.BACKSLASH, true);
|
||||
case '.': return token('.', Token.DOT, true);
|
||||
case '*': return token('*', Token.STAR, true);
|
||||
case '(': return token('(', Token.LP, true);
|
||||
case ')': return token(')', Token.RP, true);
|
||||
case '=': return token('=', Token.EQ, true);
|
||||
|
||||
//path part
|
||||
default: return token(nextPath(), Token.PATH);
|
||||
}
|
||||
|
||||
//eof
|
||||
return null;
|
||||
}
|
||||
|
||||
var error = function()
|
||||
{
|
||||
throw new Error('Unexpected character "'+currentChar()+'" at position '+pos+' in "'+source+'"');
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var token = function(value, type, skipOne)
|
||||
{
|
||||
if(skipOne) nextChar();
|
||||
|
||||
|
||||
return { value: value, type: type };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var nextChar = this.nextChar = function()
|
||||
{
|
||||
return source[++pos];
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var currentChar = this.currentChar = function()
|
||||
{
|
||||
return source[pos];
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var isAlpha = this.isAlpha = function(c)
|
||||
{
|
||||
return (c > 96 && c < 123) || (c > 64 && c < 91) || isNumber(c) || c == 95;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var isWhite = this.isWhite = function(c)
|
||||
{
|
||||
return c == 32 || c == 9 || c == 10;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var isNumber = this.isNumber = function(c)
|
||||
{
|
||||
return c > 47 && c < 58;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var nextCharCode = function()
|
||||
{
|
||||
return nextChar().charCodeAt(0);
|
||||
}
|
||||
/**
|
||||
*/
|
||||
|
||||
var currentCharCode = function()
|
||||
{
|
||||
return currentChar().charCodeAt(0);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var rewind = function(steps)
|
||||
{
|
||||
pos -= (steps || 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var skipWhite = function()
|
||||
{
|
||||
var end = false;
|
||||
|
||||
while(!(end = eof()))
|
||||
{
|
||||
if(!isWhite(currentCharCode())) break;
|
||||
|
||||
nextChar();
|
||||
}
|
||||
return !end;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var nextNumber = function()
|
||||
{
|
||||
var buffer = currentChar();
|
||||
|
||||
while(!eof())
|
||||
{
|
||||
if(isNumber(nextCharCode()))
|
||||
{
|
||||
buffer += currentChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var nextPath = function()
|
||||
{
|
||||
var buffer = currentChar();
|
||||
|
||||
while(!eof())
|
||||
{
|
||||
if(!isWhite(nextCharCode()) && !currentChar().match(/[\/=()]/g))
|
||||
// if(isAlpha(nextCharCode()) || isNumber(currentCharCode()))
|
||||
{
|
||||
buffer += currentChar();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* end of file
|
||||
*/
|
||||
|
||||
var eof = function()
|
||||
{
|
||||
return pos > source.length-2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var ChannelParser = function()
|
||||
{
|
||||
var tokenizer = new Tokenizer(),
|
||||
cache = {};
|
||||
|
||||
/**
|
||||
* parses a string into a handleable expression
|
||||
*/
|
||||
|
||||
this.parse = function(source)
|
||||
{
|
||||
if(!source) throw new Error('Source is not defined');
|
||||
|
||||
//stuff might have happened to the expression, so we need to clone it. it DEFINITELY changes
|
||||
//when pull requests are made...
|
||||
if(cache[source]) return Structr.copy(cache[source]);
|
||||
|
||||
tokenizer.source(source);
|
||||
|
||||
return Structr.copy(cache[source] = rootExpr());
|
||||
}
|
||||
|
||||
|
||||
var rootExpr = function()
|
||||
{
|
||||
var expr = tokenizer.current(),
|
||||
type,
|
||||
meta = {};
|
||||
//type is not defined, but that's okay!
|
||||
|
||||
if(expr.type == Token.WORD && tokenizer.isWhite(tokenizer.peekChars(1).charCodeAt(0)) && tokenizer.position() < tokenizer.source().length-1)
|
||||
{
|
||||
type = expr.value;
|
||||
tokenizer.next();
|
||||
}
|
||||
|
||||
var token, channels = [];
|
||||
|
||||
while(token = tokenizer.current())
|
||||
{
|
||||
switch(token.type)
|
||||
{
|
||||
|
||||
//-metadata=test
|
||||
case Token.METADATA:
|
||||
meta[token.value] = metadataValue();
|
||||
break;
|
||||
|
||||
case Token.BACKSLASH:
|
||||
case Token.WORD:
|
||||
case Token.STAR:
|
||||
channels = channels.concat(channelsExpr());
|
||||
break;
|
||||
case Token.OR:
|
||||
tokenizer.next();
|
||||
break;
|
||||
default:
|
||||
tokenizer.next();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return { type: type, meta: meta, channels: channels };
|
||||
}
|
||||
|
||||
var metadataValue = function()
|
||||
{
|
||||
if(tokenizer.currentChar() == '=')
|
||||
{
|
||||
tokenizer.next();
|
||||
var v = tokenizer.next().value;
|
||||
tokenizer.next();
|
||||
return v;
|
||||
}
|
||||
|
||||
tokenizer.next();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
var channelsExpr = function()
|
||||
{
|
||||
var channels = [],
|
||||
to;
|
||||
|
||||
|
||||
while(hasNext())
|
||||
{
|
||||
|
||||
if(currentTypeIs(Token.LP))
|
||||
{
|
||||
tokenizer.next();
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(currentTypeIs(Token.WORD | Token.PARAM | Token.STAR | Token.BACKSLASH))
|
||||
{
|
||||
channels.push([channelPathsExpr()]);
|
||||
|
||||
while(currentTypeIs(Token.OR))
|
||||
{
|
||||
tokenizer.next();
|
||||
channels[channels.length-1].push(channelPathsExpr());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(currentTypeIs(Token.RP))
|
||||
{
|
||||
tokenizer.next();
|
||||
}
|
||||
|
||||
if(currentTypeIs(Token.TO))
|
||||
{
|
||||
tokenizer.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var _orChannels = splitChannelExpr(channels.concat(), []),
|
||||
channelsThru = [];
|
||||
|
||||
for(var i = _orChannels.length; i--;)
|
||||
{
|
||||
var chain = Structr.copy(_orChannels[i]),
|
||||
current = channel = chain[chain.length-1];
|
||||
|
||||
for(var j = chain.length-1; j--;)
|
||||
{
|
||||
current = current.thru = chain[j];
|
||||
}
|
||||
|
||||
|
||||
channelsThru.push(channel);
|
||||
}
|
||||
|
||||
return channelsThru;
|
||||
}
|
||||
|
||||
var splitChannelExpr = function(orChannels, stack)
|
||||
{
|
||||
if(!orChannels.length) return [stack];
|
||||
|
||||
var current = orChannels.shift();
|
||||
|
||||
if(current.length == 1)
|
||||
{
|
||||
stack.push(current[0]);
|
||||
|
||||
return splitChannelExpr(orChannels, stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
var split = [];
|
||||
|
||||
for(var i = current.length; i--;)
|
||||
{
|
||||
var stack2 = stack.concat();
|
||||
|
||||
stack2.push(current[i]);
|
||||
|
||||
split = split.concat(splitChannelExpr(orChannels.concat(), stack2));
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var channelPathsExpr = function(type)
|
||||
{
|
||||
var paths = [],
|
||||
token,
|
||||
isMiddleware = false,
|
||||
cont = true;
|
||||
|
||||
while(cont && (token = tokenizer.current()))
|
||||
{
|
||||
|
||||
switch(token.type)
|
||||
{
|
||||
case Token.WORD:
|
||||
case Token.PARAM:
|
||||
case Token.PATH:
|
||||
paths.push({ name: token.value, param: token.type == Token.PARAM });
|
||||
break;
|
||||
case Token.BACKSLASH:
|
||||
break;
|
||||
default:
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(cont) tokenizer.next();
|
||||
}
|
||||
|
||||
if(currentTypeIs(Token.STAR))
|
||||
{
|
||||
isMiddleware = true;
|
||||
tokenizer.next();
|
||||
}
|
||||
|
||||
|
||||
return { paths: paths, isMiddleware: isMiddleware };
|
||||
}
|
||||
|
||||
|
||||
var currentToken = function(type, igError)
|
||||
{
|
||||
return checkToken(tokenizer.current(), type, igError);
|
||||
}
|
||||
|
||||
var nextToken = function(type, igError, keepWhite)
|
||||
{
|
||||
return checkToken(tokenizer.next(keepWhite), type, igError);
|
||||
}
|
||||
|
||||
var checkToken = function(token, type, igError)
|
||||
{
|
||||
if(!token || !(type & token.type))
|
||||
{
|
||||
if(!igError) throw new Error('Unexpected token "'+(token || {}).value+'" at position '+tokenizer.position()+' in '+tokenizer.source());
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
var currentTypeIs = function(type)
|
||||
{
|
||||
var current = tokenizer.current();
|
||||
|
||||
return current && !!(type & current.type);
|
||||
}
|
||||
|
||||
var hasNext = function()
|
||||
{
|
||||
return !!tokenizer.current();
|
||||
}
|
||||
}
|
||||
|
||||
exports.parse = new ChannelParser().parse;
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
var Structr = require('structr'),
|
||||
Parser = require('./parser'),
|
||||
utils = require('./utils');
|
||||
|
||||
|
||||
var Request = Structr({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'__construct': function(listener, batch)
|
||||
{
|
||||
//data necessary for the request
|
||||
this.data = batch.data;
|
||||
|
||||
//inner data which is invisible to the request, but contains data which needs to get passed along
|
||||
this.inner = batch.inner;
|
||||
|
||||
//the end callback
|
||||
this.callback = batch.callback;
|
||||
|
||||
this._used = {};
|
||||
this._queue = [];
|
||||
|
||||
//yes, and I know what you're thinking: why the hell are you copying data?
|
||||
//Well, we work backwards, and we don't know if parameters might override data passed to the current URI - we need to be prepared for that. SO
|
||||
//as we're working our way back up, data will be set, and the original data will be mapped the way it should be for the given URI
|
||||
this._add(listener, Structr.copy(this.data, true), batch.paths);
|
||||
|
||||
|
||||
if(batch._next)
|
||||
{
|
||||
this.add(batch._next);
|
||||
}
|
||||
|
||||
this.last = this._queue[0].target;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'init': function()
|
||||
{
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'hasNext': function()
|
||||
{
|
||||
return !!this._queue.length;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'next': function()
|
||||
{
|
||||
if(this._queue.length)
|
||||
{
|
||||
var thru = this._queue.pop(),
|
||||
target = thru.target;
|
||||
|
||||
this.current = target;
|
||||
|
||||
if(target.paths)
|
||||
{
|
||||
var route = this.origin.getRoute({ channel: target });
|
||||
|
||||
this._addListeners(route.listeners, route.data, target.paths);
|
||||
return this.next();
|
||||
}
|
||||
|
||||
|
||||
//heavier...
|
||||
/*var route = this.expandRoute(this._queue.length-1);
|
||||
|
||||
if(!route) return this.next();
|
||||
|
||||
target = route.target,
|
||||
thru = route.thru;
|
||||
this._queue.pop();*/
|
||||
|
||||
|
||||
this.current = target;
|
||||
|
||||
|
||||
if(target.isMiddleware && this._used[target.id]) return this.next();
|
||||
|
||||
//keep tabs of what's used so there's no overlap. this will happen when we get back to the router
|
||||
//for middleware specified in path -> to -> route
|
||||
this._used[target.id] = thru;
|
||||
|
||||
this._prepare(target, thru.data, thru.hasParams, thru.paths);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* expands all the routes (middleware even). See leche for example
|
||||
*/
|
||||
|
||||
/*'expandThru': function()
|
||||
{
|
||||
|
||||
var i = 0;
|
||||
|
||||
while(i < this._queue.length)
|
||||
{
|
||||
if(this.expandRoute(i))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
},*/
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
/*'expandRoute': function(index)
|
||||
{
|
||||
var thru = this._queue[index],
|
||||
target = thru.target;
|
||||
|
||||
if(target.paths)
|
||||
{
|
||||
this._queue.splice(index, 1);
|
||||
var route = this.origin.getRoute({ channel: target }), n = this._queue.length;
|
||||
|
||||
|
||||
this._addListeners(route.listeners, route.data, target.paths);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return { target: target, thru: thru };
|
||||
},*/
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'forward': function(channel, callback)
|
||||
{
|
||||
return this.origin.dispatch(Parser.parse(channel), this.data, { inner: this.inner, req: this.req }, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'thru': function(channel, ops)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if(ops) Structr.copy(ops, this, true);
|
||||
|
||||
|
||||
this._queue.push({ target: Parser.parse('-stream ' + channel).channels[0] });
|
||||
|
||||
this.next();
|
||||
|
||||
/*this.origin.dispatch(Parser.parse('-stream' + channel), this.data, Structr.copy({ inner: this.inner, req: this.req, _next: callback }, ops, true), function(request)
|
||||
{
|
||||
request.pipe(self);
|
||||
})*/
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_addListeners': function(listeners, data, paths)
|
||||
{
|
||||
if(listeners instanceof Array)
|
||||
{
|
||||
for(var i = listeners.length; i--;)
|
||||
{
|
||||
this._add(listeners[i], data, paths);
|
||||
}
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* adds middleware to the END of the call stack
|
||||
*/
|
||||
|
||||
'add': function(callback)
|
||||
{
|
||||
this._queue.unshift(this._func(callback));
|
||||
},
|
||||
|
||||
/**
|
||||
* adds middleware to the beginning of the call stack
|
||||
*/
|
||||
|
||||
'unshift': function(callback)
|
||||
{
|
||||
this._queue.push(this._func(callback));
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_func': function(callback)
|
||||
{
|
||||
return { target: { callback: callback }, data: {} };
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_add': function(route, data, paths)
|
||||
{
|
||||
var current = route, _queue = this._queue,
|
||||
hasParams = false;
|
||||
|
||||
if(!data) data = {};
|
||||
|
||||
while(current)
|
||||
{
|
||||
for(var i = paths.length; i--;)
|
||||
{
|
||||
var opath = paths[i],
|
||||
cpath = route.path[i],
|
||||
param,
|
||||
value;
|
||||
|
||||
|
||||
if(cpath.param && !opath.param)
|
||||
{
|
||||
param = cpath.name;
|
||||
value = opath.name;
|
||||
}
|
||||
else
|
||||
if(cpath.param && opath.param)
|
||||
{
|
||||
param = cpath.name;
|
||||
value = this.data[opath.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hasParams = true;
|
||||
|
||||
|
||||
this.data[param] = data[param] = value;
|
||||
|
||||
|
||||
// if(!this.data[param]) this.data[param] = value;
|
||||
}
|
||||
|
||||
//make sure not to use the same route twice. this will happen especially with middleware specified as /middleware/*
|
||||
_queue.push({ target: current, data: data, hasParams: hasParams, paths: paths });
|
||||
|
||||
current = current.thru;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_prepare': function(target, data, hasParams, paths)
|
||||
{
|
||||
//call once, then dispose
|
||||
if(target.meta && target.meta.one)
|
||||
{
|
||||
target.dispose();
|
||||
}
|
||||
|
||||
if(hasParams)
|
||||
{
|
||||
Structr.copy(data, this.data,true);
|
||||
}
|
||||
|
||||
|
||||
if(target.path) this.currentChannel = utils.pathToString(target.path, this.data);
|
||||
|
||||
this._callback(target, data);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'channelPath': function(index)
|
||||
{
|
||||
return utils.pathToString(this._queue[index].target.path || [], this.data);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_callback': function(target, data)
|
||||
{
|
||||
return target.callback.call(this, this);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Request;
|
||||
+282
@@ -0,0 +1,282 @@
|
||||
var Structr = require('structr'),
|
||||
Parser = require('./parser'),
|
||||
utils = require('./utils'),
|
||||
middleware = require('../middleware/meta'),
|
||||
Request = require('./request'),
|
||||
Collection = require('./collection');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Glorious.
|
||||
*/
|
||||
|
||||
var Router = Structr({
|
||||
|
||||
/**
|
||||
* Constructor. What else do you think it is?
|
||||
*/
|
||||
|
||||
'__construct': function(ops)
|
||||
{
|
||||
if(!ops) ops = {};
|
||||
|
||||
this.RequestClass = ops.RequestClass || Request;
|
||||
this._collection = new Collection(ops);
|
||||
this._allowMultiple = !!ops.multi;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* listens to the given expression for any change
|
||||
*/
|
||||
|
||||
'on': function(expr, ops, callback)
|
||||
{
|
||||
if(!callback)
|
||||
{
|
||||
callback = ops;
|
||||
ops = null;
|
||||
}
|
||||
|
||||
for(var i = expr.channels.length; i--;)
|
||||
{
|
||||
var single = utils.channel(expr, i),
|
||||
existingRoute = this.getRoute(single);
|
||||
|
||||
if(existingRoute.listeners.length && !this._allowMultiple && !this._middleware().allowMultiple(single))
|
||||
{
|
||||
var epath = existingRoute.listeners[0].path;
|
||||
|
||||
//use-case: server crashes, and reboots. Needs to override current registered path (which is trash)
|
||||
if(existingRoute.listeners[0].meta.overridable)
|
||||
{
|
||||
existingRoute.listeners[0].dispose();
|
||||
}
|
||||
else
|
||||
|
||||
//if both are params, then there's a collission.
|
||||
if(single.channel.paths[single.channel.paths.length-1].param == epath[epath.length-1].param)
|
||||
{
|
||||
throw new Error('Path "'+utils.pathToString(single.channel.paths)+'" already exists');
|
||||
}
|
||||
};
|
||||
|
||||
this._middleware().setRoute(channel);
|
||||
}
|
||||
|
||||
|
||||
return this._collection.add(expr, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_middleware': function()
|
||||
{
|
||||
return this.controller.metaMiddleware;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'hasRoute': function(channel, data)
|
||||
{
|
||||
return !!this.getRoute(channel, data).listeners.length;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'hasRoutes': function(expr, data)
|
||||
{
|
||||
for(var i = expr.channels.length; i--;)
|
||||
{
|
||||
if(this.hasRoute(utils.channel(expr, i), data)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'getRoute': function(single, data)
|
||||
{
|
||||
var route = this._collection.route(single.channel);
|
||||
|
||||
var r = this._middleware().getRoute({
|
||||
expr: single,
|
||||
router: this,
|
||||
route: route,
|
||||
data: data,
|
||||
listeners: this._filterRoute(single, route)
|
||||
});
|
||||
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
//this chunk is experimental. Moreso to test its usefulness over anything. The initial
|
||||
//thought is enable the ability for routes with *different* metadata to share the same channel. This is great
|
||||
//If say, you have web-workers which use the same channels, but different cluster IDs, so a master server knows
|
||||
//what data to send to what web-worker. This COULD be specified in the URI structure, but that feels a bit messy. We'll see if this works first. It's nice and clean.
|
||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
if(!this._middleware().allowMultiple(route) && !this._allowMultiple && r.listeners.length)
|
||||
{
|
||||
r.listeners = [r.listeners[0]];
|
||||
}
|
||||
|
||||
return r;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'dispatch': function(expr, data, ops, callback)
|
||||
{
|
||||
//only one for now. may change later on.
|
||||
for(var i = expr.channels.length; i--;)
|
||||
{
|
||||
if(this._dispatch(utils.channel(expr, i), data, ops, callback)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_dispatch': function(expr, data, ops, callback)
|
||||
{
|
||||
if(data instanceof Function)
|
||||
{
|
||||
callback = data;
|
||||
data = undefined;
|
||||
ops = undefined;
|
||||
}
|
||||
|
||||
if(ops instanceof Function)
|
||||
{
|
||||
callback = ops;
|
||||
ops = undefined;
|
||||
}
|
||||
|
||||
if(!ops) ops = {};
|
||||
if(!data) data = {};
|
||||
|
||||
channel = utils.pathToString(expr.channel.paths);
|
||||
|
||||
var inf = this.getRoute(expr, data);
|
||||
|
||||
//warnings are good incase this shouldn't happen
|
||||
if(!inf.listeners.length)
|
||||
{
|
||||
if(!ops.ignoreWarning && !expr.meta.passive)
|
||||
{
|
||||
console.warn('The %s route "%s" does not exist', expr.type, channel);
|
||||
}
|
||||
|
||||
//some callbacks are passive, meaning the dispatched request is *optional* ~ like a plugin
|
||||
if(expr.meta.passive && callback)
|
||||
{
|
||||
callback(null, 'Route Exists');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var newOps = {
|
||||
|
||||
//router is set to controller because router() is used in loader. keeps things consistent, and using "this.controller.pull" is vague
|
||||
router: this.controller,
|
||||
|
||||
//where the route lives
|
||||
origin: this,
|
||||
|
||||
//data attached, duh.
|
||||
data: inf.data,
|
||||
|
||||
//inner data
|
||||
inner: ops.inner || {},
|
||||
|
||||
channel: channel,
|
||||
|
||||
paths: inf.expr.channel.paths,
|
||||
|
||||
//the metadata attached to the expression. Tells all about how it should be handled
|
||||
meta: expr.meta,
|
||||
|
||||
//where is the dispatch coming from? Useful for hooks
|
||||
from: ops.from || this.controller,
|
||||
|
||||
//the listeners to dispatch
|
||||
listeners: inf.listeners,
|
||||
|
||||
//the final callback after everything's done ;)
|
||||
callback: callback
|
||||
};
|
||||
|
||||
Structr.copy(newOps, ops, true);
|
||||
|
||||
this._callListeners(ops);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_callListeners': function(newOps)
|
||||
{
|
||||
for(var i = newOps.listeners.length; i--;)
|
||||
{
|
||||
Structr.copy(newOps, new this.RequestClass(newOps.listeners[i], newOps), true).init().next();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* filters routes based on metadata
|
||||
*/
|
||||
|
||||
'_filterRoute': function(expr, route)
|
||||
{
|
||||
if(!route) return [ ];
|
||||
|
||||
var listeners = (route.listeners || []).concat();
|
||||
|
||||
|
||||
//Useful if there are groups of listeners with the same channel, but should not communicate
|
||||
//with each other. E.g: two apps with slaves, sending queues to thyme. Thyme would need to know exactly where the slaves are
|
||||
for(var name in expr.meta)
|
||||
{
|
||||
//the value of the metadata to search
|
||||
var value = expr.meta[name];
|
||||
|
||||
//make sure that it's not *just* defined. This is important
|
||||
//for metadata such as streams
|
||||
if(value === 1) continue;
|
||||
|
||||
//loop through the listeners and start filtering
|
||||
for(var i = listeners.length; i--;)
|
||||
{
|
||||
var listener = listeners[i];
|
||||
|
||||
if(listener.meta.unfilterable) break;
|
||||
|
||||
var metaV = listener.meta[name];
|
||||
|
||||
//if value == 1, then the tag just needs to exist
|
||||
if(metaV != value && metaV != '*')
|
||||
{
|
||||
listeners.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return listeners;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.exports = Router;
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
|
||||
/**
|
||||
* replaces params of the given expression
|
||||
*/
|
||||
|
||||
|
||||
exports.replaceParams = function(expr, params)
|
||||
{
|
||||
|
||||
var path;
|
||||
|
||||
for(var i = expr.channel.paths.length; i--;)
|
||||
{
|
||||
path = expr.channel.paths[i];
|
||||
|
||||
if(path.param)
|
||||
{
|
||||
|
||||
path.param = false;
|
||||
path.name = params[path.name];
|
||||
|
||||
//no name? IT MUST EXIST. DELETE!
|
||||
if(!path.name) expr.channel.paths.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
exports.channel = function(expr, index)
|
||||
{
|
||||
return { type: expr.type, channel: expr.channels[index], meta: expr.meta || {} };
|
||||
}
|
||||
|
||||
|
||||
exports.pathToString = function(path, data)
|
||||
{
|
||||
var paths = [];
|
||||
|
||||
if(!data) data = {};
|
||||
|
||||
for(var i = 0, n = path.length; i < n; i++)
|
||||
{
|
||||
var pt = path[i],
|
||||
part;
|
||||
|
||||
if(pt.param && data[pt.name])
|
||||
{
|
||||
part = data[pt.name];
|
||||
}
|
||||
else
|
||||
{
|
||||
part = pt.param ? ':' + pt.name : pt.name;
|
||||
}
|
||||
|
||||
paths.push(part);
|
||||
}
|
||||
|
||||
return paths.join('/');
|
||||
}
|
||||
|
||||
//old
|
||||
/*exports.channelToStr = function(channel, omit)
|
||||
{
|
||||
var buffer = [];
|
||||
|
||||
if(!omit) omit = [];
|
||||
|
||||
if(expr.type && !omit.type) buffer.push(expr.type);
|
||||
|
||||
if(!omit.meta)
|
||||
for(var key in channel.meta)
|
||||
{
|
||||
buffer.push('-'+key+'='+expr.meta[key]);
|
||||
}
|
||||
|
||||
var current = expr.channel;
|
||||
|
||||
var middleware = [];
|
||||
|
||||
while(current)
|
||||
{
|
||||
var paths = [];
|
||||
|
||||
for(var i = 0, n = current.paths.length; i < n; i++)
|
||||
{
|
||||
var path = current.paths[i];
|
||||
|
||||
paths.push((path.param ? ':' : '')+ path.name);
|
||||
}
|
||||
|
||||
middleware.unshift(paths.join('/'));
|
||||
|
||||
current = current.thru;
|
||||
}
|
||||
|
||||
buffer.push(middleware.join(' -> '));
|
||||
|
||||
return buffer.join(' ');
|
||||
}*/
|
||||
|
||||
exports.passThrusToArray = function(channel)
|
||||
{
|
||||
var cpt = channel.thru,
|
||||
thru = [];
|
||||
|
||||
while(cpt)
|
||||
{
|
||||
thru.push(this._pathToString(cpt.paths));
|
||||
cpt = cpt.thru;
|
||||
}
|
||||
|
||||
return thru;
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
var Structr = require('structr'),
|
||||
routeMiddleware = require('./middleware/route'),
|
||||
metaMiddleware = require('./middleware/meta'),
|
||||
Parser = require('./concrete/parser'),
|
||||
Janitor = require('sk/core/garbage').Janitor,
|
||||
utils = require('./concrete/utils');
|
||||
|
||||
var AbstractController = Structr({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'__construct': function(target)
|
||||
{
|
||||
this.metaMiddleware = metaMiddleware(this);
|
||||
this.routeMiddleware = routeMiddleware(this);
|
||||
|
||||
this.metaMiddleware.init();
|
||||
this.routeMiddleware.init();
|
||||
|
||||
this._channels = {};
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'has': function(type, ops)
|
||||
{
|
||||
var expr = this._parse(type, ops);
|
||||
return this._router(expr).hasRoutes(expr);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'getRoute': function(type, ops)
|
||||
{
|
||||
var expr = this._parse(type, ops);
|
||||
return this._router(expr).getRoute(utils.channel(expr, 0));
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'on': function(target)
|
||||
{
|
||||
var ja = new Janitor();
|
||||
|
||||
for(var type in target)
|
||||
{
|
||||
ja.addDisposable(this.on(type, {}, target[type]));
|
||||
}
|
||||
|
||||
return ja;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'second on': function(type, callback)
|
||||
{
|
||||
return this.on(type, {}, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'third on': function(type, ops, callback)
|
||||
{
|
||||
var expr = this._parse(type, ops),
|
||||
router = this.routeMiddleware.router(expr);
|
||||
|
||||
for(var i = expr.channels.length; i--;)
|
||||
{
|
||||
var pathStr = utils.pathToString(expr.channels[i].paths);
|
||||
|
||||
if(!this._channels[pathStr])
|
||||
{
|
||||
this.addChannel(pathStr, Structr.copy(utils.channel(expr, i)));
|
||||
}
|
||||
}
|
||||
|
||||
return router.on(expr, ops, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'channels': function()
|
||||
{
|
||||
return this._channels;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'addChannel': function(path, singleChannel)
|
||||
{
|
||||
for(var prop in singleChannel.meta)
|
||||
{
|
||||
singleChannel.meta[prop] = '*';
|
||||
}
|
||||
|
||||
this._channels[path] = singleChannel;
|
||||
},
|
||||
|
||||
/**
|
||||
* flavor picker for operations. In the string, or in the ops ;)
|
||||
*/
|
||||
|
||||
'_parse': function(type, ops)
|
||||
{
|
||||
var expr = typeof type != 'object' ? Parser.parse(type) : Structr.copy(type);
|
||||
|
||||
if(ops)
|
||||
{
|
||||
if(ops.meta) Structr.copy(ops.meta, expr.meta);
|
||||
if(ops.type) expr.type = ops.type;
|
||||
}
|
||||
|
||||
return expr;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_router': function(expr)
|
||||
{
|
||||
return this.routeMiddleware.router(expr);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_createTypeMethod': function(method)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
var func = this[ method ] = function(channel, data, ops, callback)
|
||||
{
|
||||
if(!ops) ops = {};
|
||||
ops.type = method;
|
||||
|
||||
var expr = this._parse(channel, ops);
|
||||
|
||||
return self._router(expr).dispatch(expr, data, ops, callback);
|
||||
}
|
||||
|
||||
|
||||
var router = self._router( { type: method });
|
||||
|
||||
|
||||
Structr.copy(router, func, true);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var ConcreteController = AbstractController.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override __construct': function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
var self = this;
|
||||
|
||||
//make channels data-bindable
|
||||
this.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pull channels': function()
|
||||
{
|
||||
return self.channels();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override addChannel': function(path, singleChannel)
|
||||
{
|
||||
this._super(path, singleChannel);
|
||||
|
||||
//keep the same format as the channels so the end-point is handled exactly the same
|
||||
var toPush = {};
|
||||
|
||||
toPush[path] = singleChannel;
|
||||
|
||||
this.push('channels', toPush, { ignoreWarning: true });
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = ConcreteController;
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
var Loader = require('./loader');
|
||||
|
||||
|
||||
//or a new, sandboxed router
|
||||
exports.router = function()
|
||||
{
|
||||
return new Loader();
|
||||
}
|
||||
|
||||
//singleton to boot
|
||||
exports.router().copyTo(module.exports, true);
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
var Structr = require('structr'),
|
||||
Controller = require('./controller');
|
||||
|
||||
try
|
||||
{
|
||||
require.paths.unshift(__dirname + '/beans');
|
||||
}catch(e)
|
||||
{
|
||||
//break the web.
|
||||
}
|
||||
|
||||
var Loader = Controller.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'override __construct': function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
this._params = {};
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'params': function(params)
|
||||
{
|
||||
if(typeof params == 'string') return this._params[params];
|
||||
|
||||
Structr.copy(params || {}, this._params);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'require': function()
|
||||
{
|
||||
for(var i = arguments.length; i--;)
|
||||
{
|
||||
this._require(arguments[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_require': function(source)
|
||||
{
|
||||
if(source instanceof Array)
|
||||
{
|
||||
for(var i = source.length; i--;)
|
||||
{
|
||||
this._require(source[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(typeof src == 'object' && typeof src.bean == 'function')
|
||||
{
|
||||
source.plugin(this._controller, source.params || this._params[ source.name ] || {});
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = Loader;
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
var Structr = require('structr');
|
||||
|
||||
module.exports = function()
|
||||
{
|
||||
var mw = new exports.Middleware();
|
||||
|
||||
mw.init = function()
|
||||
{
|
||||
//needs to be useable online = manual
|
||||
mw.add(require('./rotate'));
|
||||
}
|
||||
|
||||
return mw;
|
||||
}
|
||||
|
||||
exports.Middleware = Structr({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'__construct': function()
|
||||
{
|
||||
|
||||
//middleware specific to metadata
|
||||
this._toMetadata = {};
|
||||
|
||||
//middleware which handles everything
|
||||
this._universal = {};
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'add': function(module)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if(module.all)
|
||||
{
|
||||
module.all.forEach(function(type)
|
||||
{
|
||||
if(!self._universal[type]) self._universal[type] = [];
|
||||
|
||||
self._universal[type].push(module);
|
||||
});
|
||||
}
|
||||
|
||||
module.meta.forEach(function(name)
|
||||
{
|
||||
self._toMetadata[name] = module;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'getRoute': function(ops)
|
||||
{
|
||||
//parse metadata TO, and FROM
|
||||
var mw = this._getMW(ops.route ? ops.route.meta : {}, 'getRoute').concat(this._getMW(ops.expr.meta));
|
||||
|
||||
return this._eachMW(ops, mw, function(cur, ops)
|
||||
{
|
||||
return cur.getRoute(ops);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'setRoute': function(ops)
|
||||
{
|
||||
var mw = this._getMW(ops.meta, 'setRoute');
|
||||
|
||||
return this._eachMW(ops, mw, function(cur, ops)
|
||||
{
|
||||
return cur.setRoute(ops);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'allowMultiple': function(expr)
|
||||
{
|
||||
var mw = this._getMW(expr.meta);
|
||||
|
||||
for(var i = mw.length; i--;)
|
||||
{
|
||||
if(mw[i].allowMultiple) return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_getMW': function(meta, uni)
|
||||
{
|
||||
var mw = (this._universal[uni] || []).concat();
|
||||
|
||||
for(var name in meta)
|
||||
{
|
||||
if(meta[name] == undefined) continue;
|
||||
|
||||
var handler = this._toMetadata[name];
|
||||
|
||||
if(handler && mw.indexOf(handler) == -1) mw.push(handler);
|
||||
}
|
||||
|
||||
return mw;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_eachMW': function(ops, mw, each)
|
||||
{
|
||||
var cops = ops,
|
||||
newOps;
|
||||
|
||||
|
||||
for(var i = mw.length; i--;)
|
||||
{
|
||||
if(newOps = each(mw[i], cops))
|
||||
{
|
||||
cops = newOps;
|
||||
}
|
||||
}
|
||||
|
||||
return cops;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
|
||||
|
||||
|
||||
exports.rotator = function(target, meta)
|
||||
{
|
||||
|
||||
if(!target) target = {};
|
||||
|
||||
target.meta = [meta];
|
||||
target.allowMultiple = true;
|
||||
|
||||
target.getRoute = function(ops)
|
||||
{
|
||||
var route = ops.route,
|
||||
listeners = ops.listeners;
|
||||
|
||||
|
||||
//if rotate is specified, then we need to rotate it (round-robin). There's a catch though...
|
||||
//because the above *might* have filtered down to metadata values, we need to only rotate what's left, AND
|
||||
//the rotate index must be stuck with the routes rotate metadata.
|
||||
//Also, if the router can have multiple, then we cannot do round-robin. FUcKs ShiT Up.
|
||||
if(!ops.router._allowMultiple && route && route.meta && route.meta[meta] != undefined && listeners.length)
|
||||
{
|
||||
route.meta[meta] = (++route.meta[meta]) % listeners.length;
|
||||
|
||||
//only ONE listener now..
|
||||
ops.listeners = [listeners[route.meta[meta]]];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
target.setRoute = function(ops)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
exports.rotator(exports, 'rotate');
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
exports.meta = ['store'];
|
||||
|
||||
|
||||
|
||||
exports.getRoute = function(){};
|
||||
exports.setRoute = function(ops)
|
||||
{
|
||||
};
|
||||
Generated
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
var Router = require('../../../concrete/router');
|
||||
|
||||
exports.types = ['dispatch'];
|
||||
|
||||
exports.test = function(expr)
|
||||
{
|
||||
return !expr.type || expr.type == 'dispatch' ? 'dispatch' : null;
|
||||
}
|
||||
|
||||
exports.newRouter = function()
|
||||
{
|
||||
return new Router({multi:true});
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
var Structr = require('structr');
|
||||
|
||||
|
||||
module.exports = function(controller)
|
||||
{
|
||||
var mw = new exports.Middleware(controller);
|
||||
|
||||
mw.init = function()
|
||||
{
|
||||
//needs to be useable online = manual
|
||||
mw.add(require('./pushPull/push'));
|
||||
mw.add(require('./pushPull/pull'));
|
||||
mw.add(require('./default'));
|
||||
}
|
||||
|
||||
return mw;
|
||||
}
|
||||
|
||||
exports.Middleware = Structr({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'__construct': function(controller)
|
||||
{
|
||||
this._middleware = [];
|
||||
|
||||
this._controller = controller;
|
||||
|
||||
//instantiated routers
|
||||
this._routers = {};
|
||||
|
||||
//types of routers
|
||||
this.types = [];
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'add': function(module)
|
||||
{
|
||||
this._middleware.push(module);
|
||||
|
||||
this.types = module.types.concat(this.types);
|
||||
|
||||
for(var i = module.types.length; i--;)
|
||||
{
|
||||
this._controller._createTypeMethod(module.types[i]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'router': function(expr)
|
||||
{
|
||||
for(var i = this._middleware.length; i--;)
|
||||
{
|
||||
//get the factory name. some middleware may return different routers depending on the expression metadata, such as pull -multi
|
||||
var mw = this._middleware[i], name = mw.test(expr);
|
||||
|
||||
if(name) return this._router(mw, name);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_router': function(tester, name)
|
||||
{
|
||||
return this._routers[ name ] || this._newRouter(tester, name);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_newRouter': function(tester, name)
|
||||
{
|
||||
var router = tester.newRouter(name);
|
||||
|
||||
router.type = name;
|
||||
router.controller = this._controller;
|
||||
|
||||
this._routers[ name ] = router;
|
||||
|
||||
return router;
|
||||
}
|
||||
});
|
||||
|
||||
Generated
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
var Router = require('../../../../concrete/router'),
|
||||
Request = require('./request');
|
||||
|
||||
exports.types = ['pull','pullMulti'];
|
||||
|
||||
exports.test = function(expr)
|
||||
{
|
||||
if(expr.type == 'pullMulti') return 'pullMulti';
|
||||
return expr.type == 'pull' ? (expr.meta && expr.meta.multi ? 'pullMulti' : 'pull') : null;
|
||||
}
|
||||
|
||||
exports.newRouter = function(type)
|
||||
{
|
||||
var ops = { RequestClass: Request };
|
||||
|
||||
if(type == 'pullMulti') ops.multi = true;
|
||||
|
||||
return new Router(ops);
|
||||
}
|
||||
Generated
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
var Request = require('../request'),
|
||||
Structr = require('structr');
|
||||
|
||||
|
||||
var PullRequest = Request.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override init': function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
this._listen(this.callback, this.meta);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override _callback': function()
|
||||
{
|
||||
var ret = this._super.apply(this, arguments);
|
||||
|
||||
if(ret != undefined)
|
||||
{
|
||||
if(ret == true)
|
||||
{
|
||||
}
|
||||
|
||||
if(ret.send)
|
||||
{
|
||||
ret.send(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.end(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = PullRequest;
|
||||
Generated
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
var Router = require('./router'),
|
||||
PushRequest = require('./request');
|
||||
|
||||
exports.types = ['push'];
|
||||
|
||||
exports.test = function(expr)
|
||||
{
|
||||
return expr.type == 'push' ? 'push' : null;
|
||||
}
|
||||
|
||||
exports.newRouter = function()
|
||||
{
|
||||
return new Router({ multi: true, RequestClass: PushRequest });
|
||||
}
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
var Stream = require('../stream'),
|
||||
PushPullRequest = require('../request');
|
||||
|
||||
|
||||
var PushRequest = PushPullRequest.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override init': function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
this.cache();
|
||||
this.stream.pipe(this);
|
||||
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override _callback': function(route, data)
|
||||
{
|
||||
this._listen(route.callback, route.meta || {});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = PushRequest;
|
||||
Generated
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
var Router = require('../../../../concrete/router'),
|
||||
Stream = require('../stream'),
|
||||
utils = require('../../../../concrete/utils'),
|
||||
Structr = require('structr');
|
||||
|
||||
|
||||
var PushRouter = Router.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override on': function(expr, ops, callback)
|
||||
{
|
||||
if(!callback)
|
||||
{
|
||||
callback = ops;
|
||||
ops = {};
|
||||
}
|
||||
|
||||
var ret = this._super(expr, ops, callback);
|
||||
|
||||
|
||||
if(expr.meta.pull)
|
||||
{
|
||||
this.controller.pull(expr, Structr.copy(ops.data), { ignoreWarning: true }, callback);
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override _callListeners': function(ops)
|
||||
{
|
||||
|
||||
//the stream for pushing content. must be cached incase there's latency.
|
||||
var stream = new Stream(true),
|
||||
|
||||
//no callback? then data's just being pushed, which is okay
|
||||
callback = ops.callback || function(stream)
|
||||
{
|
||||
return ops.data;
|
||||
}
|
||||
|
||||
//of there's a callback, it can return a value which is pushed to the stream
|
||||
var ret = callback(stream);
|
||||
|
||||
//IF there's a value, then we're done
|
||||
if(ret != undefined)
|
||||
{
|
||||
stream.end(ret);
|
||||
}
|
||||
|
||||
//make the stream visible to all listeners
|
||||
ops.stream = stream;
|
||||
|
||||
//SHIBLAM. call the listeners ;)
|
||||
this._super.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = PushRouter;
|
||||
Generated
Vendored
+88
@@ -0,0 +1,88 @@
|
||||
var Request = require('../../../concrete/request'),
|
||||
Stream = require('./stream'),
|
||||
Structr = require('structr');
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var PushPullRequest = Request.extend(Structr.copy(Stream.proto, {
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'init': function()
|
||||
{
|
||||
this._init();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_listen': function(listener, meta)
|
||||
{
|
||||
//because the framework needs to be easy to use, streams are turned off by default. This
|
||||
//would be a huge pain in the pass if every time they're required, but they're SUPER important
|
||||
//if we're trying to stream a large amount of data. What about HTTP? So if it's false, we need to
|
||||
//add a stream handler.
|
||||
if(!meta.stream)
|
||||
{
|
||||
//the buffer for the streams
|
||||
var buffer = [], self = this;
|
||||
|
||||
function end(err)
|
||||
{
|
||||
if(err) return;
|
||||
|
||||
//again, it would be a pain in the ass if everytimg we have to do: var value = response[0]. So
|
||||
//a "batch" must be specified if we're expecting an array, because 99% of the time for in-app route handling,
|
||||
//only ONE value will be returned.
|
||||
if(meta.batch)
|
||||
{
|
||||
listener.call(self, buffer, err, self);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!buffer.length)
|
||||
{
|
||||
listener();
|
||||
}
|
||||
else
|
||||
//so again, by default callback the listener as many times as there are batch values
|
||||
for(var i = 0, n = buffer.length; i < n; i++)
|
||||
{
|
||||
listener.call(self, buffer[i], err, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.pipe({
|
||||
|
||||
|
||||
//on write, throw the data into the buffer
|
||||
write: function(data)
|
||||
{
|
||||
buffer.push(data);
|
||||
},
|
||||
|
||||
error: end,
|
||||
|
||||
//on end, callback the listener
|
||||
end: end
|
||||
});
|
||||
}
|
||||
|
||||
//is the listener expecting a stream? Okay, then pass on the writer to the listener. Only use this for files, http requests, and the
|
||||
//likes plz, omg you're code would look like shit otherwise >.>
|
||||
else
|
||||
{
|
||||
//more flavor picking. Use this, or the passed obj
|
||||
listener.call(this, this);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
module.exports = PushPullRequest;
|
||||
Generated
Vendored
+209
@@ -0,0 +1,209 @@
|
||||
var Structr = require('structr'),
|
||||
EventEmitter = require('sk/core/events').EventEmitter;
|
||||
|
||||
/**
|
||||
the bridge between the listener, and responder. Yeah, Yeah. the listener
|
||||
94 */
|
||||
|
||||
var proto = {
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_init': function(ttl)
|
||||
{
|
||||
this._em = new EventEmitter();
|
||||
|
||||
this.response = {};
|
||||
|
||||
if(ttl)
|
||||
{
|
||||
this.cache(ttl);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'cache': function(ttl)
|
||||
{
|
||||
if(this._caching) return;
|
||||
this._caching = true;
|
||||
|
||||
|
||||
//store the buffer incase data comes a little quicker than we can handle it.
|
||||
var buffer = this._buffer = [], self = this;
|
||||
|
||||
this.on({
|
||||
write: function(chunk)
|
||||
{
|
||||
buffer.push(chunk)
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'on': function(listeners)
|
||||
{
|
||||
for(var type in listeners)
|
||||
{
|
||||
this._em.addListener(type, listeners[type]);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'second on': function(type, callback)
|
||||
{
|
||||
this._em.addListener(type, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'respond': function(data)
|
||||
{
|
||||
this.responded = true;
|
||||
|
||||
Structr.copy(data, this.response, true);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'error': function(data)
|
||||
{
|
||||
if(!data) return this._error;
|
||||
this._error = data;
|
||||
this._em.emit('error', data);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_sendResponse': function()
|
||||
{
|
||||
if(!this._sentResponse)
|
||||
{
|
||||
this._sentResponse = true;
|
||||
|
||||
//WHOOAAHH, what are you doing!? Okay, I know it looks stupid, it is. BUT, consider this scenario:
|
||||
//via HTTP, the session object is *saved* to the database once toJSON is called, which is ONLY called when *this* happens. We do not want
|
||||
//the session to save before we're done writing to it, or handling it.
|
||||
this.response = JSON.parse(JSON.stringify(this.response));
|
||||
|
||||
this._em.emit('response', this.response);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'write': function(data)
|
||||
{
|
||||
this._sendResponse();
|
||||
|
||||
this._em.emit('write', data);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'end': function(data)
|
||||
{
|
||||
//SUPER NOTE: end can be called *once*. After that, all the listeners are disposed of
|
||||
if(data) this.write(data);
|
||||
|
||||
this._sendResponse();
|
||||
|
||||
this.finished = true;
|
||||
|
||||
this._em.emit('end', data);
|
||||
|
||||
//remove the event listeners to avoid mem leaks
|
||||
this._em.dispose();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'pipe': function(stream)
|
||||
{
|
||||
|
||||
//IF there is a buffer, that means it came faster than we can handle it. This sort of thing
|
||||
//occurrs when there are pass-thru routes which hold up the final callback. e.g: authenticating a user against
|
||||
//a database
|
||||
// if(stream.response) stream.response = this.response;
|
||||
|
||||
if(stream.respond && this.responded) stream.respond(this.response);
|
||||
|
||||
if(this._buffer && this._buffer.length)
|
||||
{
|
||||
for(var i = 0, n = this._buffer.length; i < n; i++)
|
||||
{
|
||||
stream.write(this._buffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//already finished? return
|
||||
if(this.finished)
|
||||
{
|
||||
return stream.end();
|
||||
}
|
||||
|
||||
//looks like the bridge is still handling data, so listen for the rest
|
||||
this.on({
|
||||
write: function(data)
|
||||
{
|
||||
if(stream.write) stream.write(data);
|
||||
},
|
||||
end: function()
|
||||
{
|
||||
if(stream.end) stream.end();
|
||||
},
|
||||
error: function(e)
|
||||
{
|
||||
if(stream.error) stream.error(e);
|
||||
},
|
||||
response: function(data)
|
||||
{
|
||||
if(stream.respond) stream.respond(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var Stream = Structr(Structr.copy(proto, {
|
||||
|
||||
/**
|
||||
* @param the current request
|
||||
* @param ttl time to keep cached version in memory before dumping it
|
||||
*/
|
||||
|
||||
'__construct': function(ttl)
|
||||
{
|
||||
this._init(ttl);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
Stream.proto = proto;
|
||||
|
||||
|
||||
module.exports = Stream;
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
exports.plugin = function(router)
|
||||
{
|
||||
|
||||
router.on({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'push init': function()
|
||||
{
|
||||
exec('hostname', function(err, hostname)
|
||||
{
|
||||
router.on('pull hostname', function()
|
||||
{
|
||||
return hostname;
|
||||
});
|
||||
|
||||
router.push('hostname', hostname.replace('\n',''));
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
require('sk/node/log');
|
||||
|
||||
//need this for global beanpole ~ not cached with NPM.
|
||||
if(global.beanpole)
|
||||
{
|
||||
module.exports = global.beanpole;
|
||||
}
|
||||
else
|
||||
{
|
||||
var Loader = require('./loader');
|
||||
|
||||
exports.router = function()
|
||||
{
|
||||
return new Loader();
|
||||
}
|
||||
|
||||
|
||||
exports.router().copyTo(module.exports, true);
|
||||
|
||||
global.beanpole = module.exports;
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
var Structr = require('structr'),
|
||||
Loader = require('../core/loader'),
|
||||
fs = require('fs'),
|
||||
pt = require('path');
|
||||
|
||||
//let coffeescript inject require hooks
|
||||
require('coffee-script');
|
||||
|
||||
function unableToLoad(bean)
|
||||
{
|
||||
console.error('Unable to load bean "%s"', bean);
|
||||
}
|
||||
|
||||
|
||||
//replaces relative paths, with abs paths for beans. Primarily used for the package.json
|
||||
//config
|
||||
function replaceRelWithAbsPath(config, cwd)
|
||||
{
|
||||
for(var property in config)
|
||||
{
|
||||
var value = config[property];
|
||||
|
||||
if(typeof value == 'string' && value.substr(0,2) == './')
|
||||
{
|
||||
config[property] = fs.realpathSync(cwd+value.substr(1));
|
||||
}
|
||||
else
|
||||
if(value instanceof Object)
|
||||
{
|
||||
replaceRelWithAbsPath(value, cwd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
//quick, temporary fix for node > 5.x. breaks
|
||||
try
|
||||
{
|
||||
require.paths.unshift(__dirname + '/beans');
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
|
||||
}
|
||||
var NodeLoader = Loader.extend({
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
|
||||
'override __construct': function()
|
||||
{
|
||||
this._super();
|
||||
|
||||
this._loaded = [];
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'override _require': function(source)
|
||||
{
|
||||
if(!this._super(source))
|
||||
{
|
||||
if(typeof source == 'object')
|
||||
{
|
||||
for(var bean in source)
|
||||
{
|
||||
this._require2(bean).plugin(this, source[bean]);
|
||||
}
|
||||
}
|
||||
else
|
||||
if(typeof source == 'string')
|
||||
{
|
||||
var bean, self = this, basename = pt.basename(source);
|
||||
|
||||
|
||||
if(basename == 'package.json')
|
||||
{
|
||||
var pkg = JSON.parse(fs.readFileSync(source, 'utf8'));
|
||||
|
||||
for(var bean in pkg.beans)
|
||||
{
|
||||
var params = pkg.beans[bean],
|
||||
plugin = self._require2(bean);
|
||||
|
||||
|
||||
if(!plugin)
|
||||
{
|
||||
unableToLoad(bean);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
plugin.plugin(self, replaceRelWithAbsPath(typeof params != 'boolean' ? params : self._params[bean] || {}, pt.dirname(source)));
|
||||
}
|
||||
}
|
||||
else
|
||||
if(!(bean = this._require2(source)))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
//NOT a bean, but a directory for the beans.
|
||||
fs.readdirSync(source).forEach(function(name)
|
||||
{
|
||||
//hidden file
|
||||
if(name.substr(0,1) == '.') return;
|
||||
|
||||
self._require2(source + '/' + name).plugin(self, self._params[name] || {});
|
||||
});
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
console.log(e.stack)
|
||||
console.warn('Unable to load beans from directory %s', source);
|
||||
unableToLoad(source);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bean.plugin(this, self._params[source.split('/').pop()] || {});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
//this gets hit if old require is true
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
'_require2': function(bean)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = require.resolve(bean);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = require(bean),
|
||||
name = pt.dirname(path).split('/').pop();
|
||||
|
||||
|
||||
if(this._loaded.indexOf(path) > -1)
|
||||
{
|
||||
console.notice('Cannot reload bean "%s"', bean);
|
||||
|
||||
return { plugin: function() {} };
|
||||
}
|
||||
|
||||
this._loaded.push(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = NodeLoader;
|
||||
+1
@@ -0,0 +1 @@
|
||||
module.exports = require('../core')
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "beanpole",
|
||||
"description": "Routing on Steroids",
|
||||
"version": "0.1.16",
|
||||
"author": "Craig Condon",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/crcn/beanpole.git"
|
||||
},
|
||||
"directories" : { "lib" : "./lib" },
|
||||
"dependencies": {
|
||||
"sk":"*",
|
||||
"vine":"*",
|
||||
"mime":"*",
|
||||
"gumbo":"*",
|
||||
"cashew":"*",
|
||||
"structr":"*",
|
||||
"coffee-script":"*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ebnf-diagram":"*"
|
||||
},
|
||||
|
||||
"main": "./lib/node/index.js"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"folders":
|
||||
[
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"build_systems":
|
||||
[
|
||||
{
|
||||
"name":"cbd make",
|
||||
"cmd":["cbd","make","beanpole"]
|
||||
},
|
||||
{
|
||||
"name":"cbd start",
|
||||
"cmd":["cbd","start","beanpole"]
|
||||
},
|
||||
{
|
||||
"name":"cbd make+start",
|
||||
"cmd":["cbd","make+start","beanpole"]
|
||||
}
|
||||
]
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>currentDocument</key>
|
||||
<string>lib/core/concrete/router.js</string>
|
||||
<key>documents</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>expanded</key>
|
||||
<true/>
|
||||
<key>name</key>
|
||||
<string>project</string>
|
||||
<key>regexFolderFilter</key>
|
||||
<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
||||
<key>sourceDirectory</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>fileHierarchyDrawerWidth</key>
|
||||
<integer>200</integer>
|
||||
<key>metaData</key>
|
||||
<dict>
|
||||
<key>MIT-LICENSE.txt</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>61</integer>
|
||||
<key>line</key>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>docs/beans/README.md</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>8</integer>
|
||||
<key>line</key>
|
||||
<integer>43</integer>
|
||||
</dict>
|
||||
<key>columnSelection</key>
|
||||
<false/>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
<key>selectFrom</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>2</integer>
|
||||
<key>line</key>
|
||||
<integer>43</integer>
|
||||
</dict>
|
||||
<key>selectTo</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>8</integer>
|
||||
<key>line</key>
|
||||
<integer>43</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>examples/ws/client/release/index.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>0</integer>
|
||||
<key>line</key>
|
||||
<integer>1232</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>1216</integer>
|
||||
</dict>
|
||||
<key>lib/core/concrete/router.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>7</integer>
|
||||
<key>line</key>
|
||||
<integer>266</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>234</integer>
|
||||
</dict>
|
||||
<key>lib/core/controller.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>4</integer>
|
||||
<key>line</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/index.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>0</integer>
|
||||
<key>line</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/loader.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>1</integer>
|
||||
<key>line</key>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>lib/core/middleware/route/pushPull/push/router.js</key>
|
||||
<dict>
|
||||
<key>caret</key>
|
||||
<dict>
|
||||
<key>column</key>
|
||||
<integer>4</integer>
|
||||
<key>line</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>firstVisibleColumn</key>
|
||||
<integer>0</integer>
|
||||
<key>firstVisibleLine</key>
|
||||
<integer>17</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>openDocuments</key>
|
||||
<array>
|
||||
<string>MIT-LICENSE.txt</string>
|
||||
<string>docs/beans/README.md</string>
|
||||
<string>examples/ws/client/release/index.js</string>
|
||||
<string>lib/core/controller.js</string>
|
||||
<string>lib/core/loader.js</string>
|
||||
<string>lib/core/concrete/router.js</string>
|
||||
<string>lib/core/index.js</string>
|
||||
</array>
|
||||
<key>showFileHierarchyDrawer</key>
|
||||
<true/>
|
||||
<key>windowFrame</key>
|
||||
<string>{{210, 4}, {1230, 874}}</string>
|
||||
</dict>
|
||||
</plist>
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2010 Alexis Sellier (cloudhead) , Marak Squires
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
<h1>colors.js - get color and style in your node.js console like what</h1>
|
||||
|
||||
<img src="http://i.imgur.com/goJdO.png" border = "0"/>
|
||||
|
||||
var sys = require('sys');
|
||||
var colors = require('./colors');
|
||||
|
||||
sys.puts('hello'.green); // outputs green text
|
||||
sys.puts('i like cake and pies'.underline.red) // outputs red underlined text
|
||||
sys.puts('inverse the color'.inverse); // inverses the color
|
||||
sys.puts('OMG Rainbows!'.rainbow); // rainbow (ignores spaces)
|
||||
|
||||
<h2>colors and styles!</h2>
|
||||
- bold
|
||||
- italic
|
||||
- underline
|
||||
- inverse
|
||||
- yellow
|
||||
- cyan
|
||||
- white
|
||||
- magenta
|
||||
- green
|
||||
- red
|
||||
- grey
|
||||
- blue
|
||||
|
||||
|
||||
### Authors
|
||||
|
||||
#### Alexis Sellier (cloudhead) , Marak Squires , Justin Campbell, Dustin Diaz (@ded)
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
colors.js
|
||||
|
||||
Copyright (c) 2010 Alexis Sellier (cloudhead) , Marak Squires
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
exports.mode = "console";
|
||||
|
||||
// prototypes the string object to have additional method calls that add terminal colors
|
||||
|
||||
var addProperty = function (color, func) {
|
||||
exports[color] = function(str) {
|
||||
return func.apply(str);
|
||||
};
|
||||
String.prototype.__defineGetter__(color, func);
|
||||
}
|
||||
|
||||
var isHeadless = (typeof module !== 'undefined');
|
||||
['bold', 'underline', 'italic', 'inverse', 'grey', 'black', 'yellow', 'red', 'green', 'blue', 'white', 'cyan', 'magenta'].forEach(function (style) {
|
||||
|
||||
// __defineGetter__ at the least works in more browsers
|
||||
// http://robertnyman.com/javascript/javascript-getters-setters.html
|
||||
// Object.defineProperty only works in Chrome
|
||||
addProperty(style, function () {
|
||||
return isHeadless ?
|
||||
stylize(this, style) : // for those running in node (headless environments)
|
||||
this.replace(/( )/, '$1'); // and for those running in browsers:
|
||||
// re: ^ you'd think 'return this' works (but doesn't) so replace coerces the string to be a real string
|
||||
});
|
||||
});
|
||||
|
||||
// prototypes string with method "rainbow"
|
||||
// rainbow will apply a the color spectrum to a string, changing colors every letter
|
||||
addProperty('rainbow', function () {
|
||||
if (!isHeadless) {
|
||||
return this.replace(/( )/, '$1');
|
||||
}
|
||||
var rainbowcolors = ['red','yellow','green','blue','magenta']; //RoY G BiV
|
||||
var exploded = this.split("");
|
||||
var i=0;
|
||||
exploded = exploded.map(function(letter) {
|
||||
if (letter==" ") {
|
||||
return letter;
|
||||
}
|
||||
else {
|
||||
return stylize(letter,rainbowcolors[i++ % rainbowcolors.length]);
|
||||
}
|
||||
});
|
||||
return exploded.join("");
|
||||
});
|
||||
|
||||
function stylize(str, style) {
|
||||
if (exports.mode == 'console') {
|
||||
var styles = {
|
||||
//styles
|
||||
'bold' : ['\033[1m', '\033[22m'],
|
||||
'italic' : ['\033[3m', '\033[23m'],
|
||||
'underline' : ['\033[4m', '\033[24m'],
|
||||
'inverse' : ['\033[7m', '\033[27m'],
|
||||
//grayscale
|
||||
'white' : ['\033[37m', '\033[39m'],
|
||||
'grey' : ['\033[90m', '\033[39m'],
|
||||
'black' : ['\033[30m', '\033[39m'],
|
||||
//colors
|
||||
'blue' : ['\033[34m', '\033[39m'],
|
||||
'cyan' : ['\033[36m', '\033[39m'],
|
||||
'green' : ['\033[32m', '\033[39m'],
|
||||
'magenta' : ['\033[35m', '\033[39m'],
|
||||
'red' : ['\033[31m', '\033[39m'],
|
||||
'yellow' : ['\033[33m', '\033[39m']
|
||||
};
|
||||
} else if (exports.mode == 'browser') {
|
||||
var styles = {
|
||||
//styles
|
||||
'bold' : ['<b>', '</b>'],
|
||||
'italic' : ['<i>', '</i>'],
|
||||
'underline' : ['<u>', '</u>'],
|
||||
'inverse' : ['<span style="background-color:black;color:white;">', '</span>'],
|
||||
//grayscale
|
||||
'white' : ['<span style="color:white;">', '</span>'],
|
||||
'grey' : ['<span style="color:grey;">', '</span>'],
|
||||
'black' : ['<span style="color:black;">', '</span>'],
|
||||
//colors
|
||||
'blue' : ['<span style="color:blue;">', '</span>'],
|
||||
'cyan' : ['<span style="color:cyan;">', '</span>'],
|
||||
'green' : ['<span style="color:green;">', '</span>'],
|
||||
'magenta' : ['<span style="color:magenta;">', '</span>'],
|
||||
'red' : ['<span style="color:red;">', '</span>'],
|
||||
'yellow' : ['<span style="color:yellow;">', '</span>']
|
||||
};
|
||||
} else if (exports.mode == 'none') {
|
||||
return str;
|
||||
} else {
|
||||
console.log('unsupported mode, try "browser", "console" or "none"');
|
||||
}
|
||||
|
||||
return styles[style][0] + str + styles[style][1];
|
||||
};
|
||||
|
||||
// don't summon zalgo
|
||||
addProperty('zalgo', function () {
|
||||
return zalgo(this);
|
||||
});
|
||||
|
||||
// please no
|
||||
function zalgo(text, options) {
|
||||
var soul = {
|
||||
"up" : [
|
||||
'̍','̎','̄','̅',
|
||||
'̿','̑','̆','̐',
|
||||
'͒','͗','͑','̇',
|
||||
'̈','̊','͂','̓',
|
||||
'̈','͊','͋','͌',
|
||||
'̃','̂','̌','͐',
|
||||
'̀','́','̋','̏',
|
||||
'̒','̓','̔','̽',
|
||||
'̉','ͣ','ͤ','ͥ',
|
||||
'ͦ','ͧ','ͨ','ͩ',
|
||||
'ͪ','ͫ','ͬ','ͭ',
|
||||
'ͮ','ͯ','̾','͛',
|
||||
'͆','̚'
|
||||
],
|
||||
"down" : [
|
||||
'̖','̗','̘','̙',
|
||||
'̜','̝','̞','̟',
|
||||
'̠','̤','̥','̦',
|
||||
'̩','̪','̫','̬',
|
||||
'̭','̮','̯','̰',
|
||||
'̱','̲','̳','̹',
|
||||
'̺','̻','̼','ͅ',
|
||||
'͇','͈','͉','͍',
|
||||
'͎','͓','͔','͕',
|
||||
'͖','͙','͚','̣'
|
||||
],
|
||||
"mid" : [
|
||||
'̕','̛','̀','́',
|
||||
'͘','̡','̢','̧',
|
||||
'̨','̴','̵','̶',
|
||||
'͜','͝','͞',
|
||||
'͟','͠','͢','̸',
|
||||
'̷','͡',' ҉'
|
||||
]
|
||||
},
|
||||
all = [].concat(soul.up, soul.down, soul.mid),
|
||||
zalgo = {};
|
||||
|
||||
function randomNumber(range) {
|
||||
r = Math.floor(Math.random()*range);
|
||||
return r;
|
||||
};
|
||||
|
||||
function is_char(character) {
|
||||
var bool = false;
|
||||
all.filter(function(i){
|
||||
bool = (i == character);
|
||||
});
|
||||
return bool;
|
||||
}
|
||||
|
||||
function heComes(text, options){
|
||||
result = '';
|
||||
options = options || {};
|
||||
options["up"] = options["up"] || true;
|
||||
options["mid"] = options["mid"] || true;
|
||||
options["down"] = options["down"] || true;
|
||||
options["size"] = options["size"] || "maxi";
|
||||
var counts;
|
||||
text = text.split('');
|
||||
for(var l in text){
|
||||
if(is_char(l)) { continue; }
|
||||
result = result + text[l];
|
||||
|
||||
counts = {"up" : 0, "down" : 0, "mid" : 0};
|
||||
|
||||
switch(options.size) {
|
||||
case 'mini':
|
||||
counts.up = randomNumber(8);
|
||||
counts.min= randomNumber(2);
|
||||
counts.down = randomNumber(8);
|
||||
break;
|
||||
case 'maxi':
|
||||
counts.up = randomNumber(16) + 3;
|
||||
counts.min = randomNumber(4) + 1;
|
||||
counts.down = randomNumber(64) + 3;
|
||||
break;
|
||||
default:
|
||||
counts.up = randomNumber(8) + 1;
|
||||
counts.mid = randomNumber(6) / 2;
|
||||
counts.down= randomNumber(8) + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
var arr = ["up", "mid", "down"];
|
||||
for(var d in arr){
|
||||
var index = arr[d];
|
||||
for (var i = 0 ; i <= counts[index]; i++)
|
||||
{
|
||||
if(options[index]) {
|
||||
result = result + soul[index][randomNumber(soul[index].length)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
return heComes(text);
|
||||
}
|
||||
|
||||
addProperty('stripColors', function() {
|
||||
return ("" + this).replace(/\u001b\[\d+m/g,'');
|
||||
});
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>Colors Example</title>
|
||||
<script src="colors.js"></script>
|
||||
<script type="text/javascript">
|
||||
console.log('Rainbows are fun!'.rainbow);
|
||||
console.log('So '.italic + 'are'.underline + ' styles! '.bold + 'inverse'.inverse);
|
||||
console.log('Chains are also cool.'.bold.italic.underline.red);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.write('Rainbows are fun!'.rainbow + '<br>');
|
||||
document.write('So '.italic + 'are'.underline + ' styles! '.bold + 'inverse'.inverse + '<br>');
|
||||
document.write('Chains are also cool.'.bold.italic.underline.red);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
var util = require('util');
|
||||
var colors = require('./colors');
|
||||
|
||||
//colors.mode = "browser";
|
||||
|
||||
var test = colors.red("hopefully colorless output");
|
||||
util.puts('Rainbows are fun!'.rainbow);
|
||||
util.puts('So '.italic + 'are'.underline + ' styles! '.bold + 'inverse'.inverse); // styles not widely supported
|
||||
util.puts('Chains are also cool.'.bold.italic.underline.red); // styles not widely supported
|
||||
//util.puts('zalgo time!'.zalgo);
|
||||
util.puts(test.stripColors);
|
||||
util.puts("a".grey + " b".black);
|
||||
|
||||
util.puts(colors.rainbow('Rainbows are fun!'));
|
||||
util.puts(colors.italic('So ') + colors.underline('are') + colors.bold(' styles! ') + colors.inverse('inverse')); // styles not widely supported
|
||||
util.puts(colors.bold(colors.italic(colors.underline(colors.red('Chains are also cool.'))))); // styles not widely supported
|
||||
//util.puts(colors.zalgo('zalgo time!'));
|
||||
util.puts(colors.stripColors(test));
|
||||
util.puts(colors.grey("a") + colors.black(" b"));
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "colors",
|
||||
"description": "get colors in your node.js console like what",
|
||||
"version": "0.5.1",
|
||||
"author": "Marak Squires",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/Marak/colors.js.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.1.90"
|
||||
},
|
||||
"main": "colors"
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "structr",
|
||||
"description": "Clean OO structure for Javascript.",
|
||||
"version": "0.0.10",
|
||||
"author": "Craig Condon",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/spiceapps/Structr.git"
|
||||
},
|
||||
"main": "./structr.js"
|
||||
}
|
||||
+488
@@ -0,0 +1,488 @@
|
||||
var Structr = function (target, parent)
|
||||
{
|
||||
if (!parent) parent = Structr.fh({});
|
||||
|
||||
var that = Structr.extend.apply(null, [parent].concat(target))
|
||||
|
||||
that.__construct.prototype = that;
|
||||
|
||||
if(!that.__construct.extend)
|
||||
//allow for easy extending.
|
||||
that.__construct.extend = function()
|
||||
{
|
||||
return Structr(Structr.argsToArray(arguments), that);
|
||||
};
|
||||
|
||||
//return the constructor
|
||||
return that.__construct;
|
||||
};
|
||||
|
||||
|
||||
Structr.argsToArray = function(args)
|
||||
{
|
||||
var ar = new Array(args.length);
|
||||
for(var i = args.length; i--;) ar[i] = args[i];
|
||||
return ar;
|
||||
}
|
||||
|
||||
Structr.copy = function (from, to, lite)
|
||||
{
|
||||
if(typeof to == 'boolean')
|
||||
{
|
||||
lite = to;
|
||||
to = undefined;
|
||||
}
|
||||
|
||||
if (!to) to = from instanceof Array ? [] : {};
|
||||
|
||||
var i;
|
||||
|
||||
for(i in from)
|
||||
{
|
||||
var fromValue = from[i],
|
||||
toValue = to[i],
|
||||
newValue;
|
||||
|
||||
//don't copy anything fancy other than objects and arrays. this could really screw classes up, such as dates.... (yuck)
|
||||
if (!lite && typeof fromValue == 'object' && (!fromValue || fromValue.__proto__ == Object.prototype || fromValue.__proto__ == Array.prototype))
|
||||
{
|
||||
|
||||
//if the toValue exists, and the fromValue is the same data type as the TO value, then
|
||||
//merge the FROM value with the TO value, instead of replacing it
|
||||
if (toValue && fromValue instanceof toValue.constructor)
|
||||
{
|
||||
newValue = toValue;
|
||||
}
|
||||
|
||||
//otherwise replace it, because FROM has priority over TO
|
||||
else
|
||||
{
|
||||
newValue = fromValue instanceof Array ? [] : {};
|
||||
}
|
||||
|
||||
Structr.copy(fromValue, newValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = fromValue;
|
||||
}
|
||||
|
||||
to[i] = newValue;
|
||||
}
|
||||
|
||||
return to;
|
||||
};
|
||||
|
||||
|
||||
//returns a method owned by an object
|
||||
Structr.getMethod = function (that, property)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
return that[property].apply(that, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
Structr.wrap = function(that, prop)
|
||||
{
|
||||
if(that._wrapped) return that;
|
||||
|
||||
that._wrapped = true;
|
||||
|
||||
function wrap(target)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
return target.apply(that, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
if(prop)
|
||||
{
|
||||
that[prop] = wrap(target[prop]);
|
||||
return that;
|
||||
}
|
||||
|
||||
for(var property in that)
|
||||
{
|
||||
var target = that[property];
|
||||
|
||||
if(typeof target == 'function')
|
||||
{
|
||||
that[property] = wrap(target);
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
}
|
||||
|
||||
//finds all properties with modifiers
|
||||
Structr.findProperties = function (target, modifier)
|
||||
{
|
||||
var props = [],
|
||||
property;
|
||||
|
||||
for(property in target)
|
||||
{
|
||||
var v = target[property];
|
||||
|
||||
if (v && v[modifier])
|
||||
{
|
||||
props.push(property);
|
||||
}
|
||||
}
|
||||
|
||||
return props;
|
||||
};
|
||||
|
||||
Structr.nArgs = function(func)
|
||||
{
|
||||
var inf = func.toString().replace(/\{[\W\S]+\}/g, '').match(/\w+(?=[,\)])/g);
|
||||
return inf ? inf.length :0;
|
||||
}
|
||||
|
||||
Structr.getFuncsByNArgs = function(that, property)
|
||||
{
|
||||
return that.__private['overload::' + property] || (that.__private['overload::' + property] = {});
|
||||
}
|
||||
|
||||
Structr.getOverloadedMethod = function(that, property, nArgs)
|
||||
{
|
||||
var funcsByNArgs = Structr.getFuncsByNArgs(that, property);
|
||||
|
||||
return funcsByNArgs[nArgs];
|
||||
}
|
||||
|
||||
Structr.setOverloadedMethod = function(that, property, func, nArgs)
|
||||
{
|
||||
var funcsByNArgs = Structr.getFuncsByNArgs(that, property);
|
||||
|
||||
if(func.overloaded) return funcsByNArgs;
|
||||
|
||||
funcsByNArgs[nArgs || Structr.nArgs(func)] = func;
|
||||
|
||||
return funcsByNArgs;
|
||||
}
|
||||
|
||||
//modifies how properties behave in a class
|
||||
Structr.modifiers = {
|
||||
|
||||
/**
|
||||
* overrides given method
|
||||
*/
|
||||
|
||||
m_override: function (that, property, newMethod)
|
||||
{
|
||||
var oldMethod = (that.__private && that.__private[property]) || that[property] || function (){},
|
||||
parentMethod = oldMethod;
|
||||
|
||||
if(oldMethod.overloaded)
|
||||
{
|
||||
var overloadedMethod = oldMethod,
|
||||
nArgs = Structr.nArgs(newMethod);
|
||||
parentMethod = Structr.getOverloadedMethod(that, property, nArgs);
|
||||
}
|
||||
|
||||
//wrap the method so we can access the parent overloaded function
|
||||
var wrappedMethod = function ()
|
||||
{
|
||||
this._super = parentMethod;
|
||||
var ret = newMethod.apply(this, arguments);
|
||||
delete this._super;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(oldMethod.overloaded)
|
||||
{
|
||||
return Structr.modifiers.m_overload(that, property, wrappedMethod, nArgs);
|
||||
}
|
||||
|
||||
return wrappedMethod;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* getter / setter which are physical functions: e.g: test.myName(), and test.myName('craig')
|
||||
*/
|
||||
|
||||
m_explicit: function (that, property, gs)
|
||||
{
|
||||
var pprop = '__'+property;
|
||||
|
||||
//if GS is not defined, then set defaults.
|
||||
if (typeof gs != 'object')
|
||||
{
|
||||
gs = {};
|
||||
}
|
||||
|
||||
if (!gs.get)
|
||||
gs.get = function ()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
if (!gs.set)
|
||||
gs.set = function (value)
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
|
||||
return function (value)
|
||||
{
|
||||
//getter
|
||||
if (!arguments.length)
|
||||
{
|
||||
this._value = this[pprop];
|
||||
var ret = gs.get.apply(this);
|
||||
delete this._value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
//setter
|
||||
else
|
||||
{
|
||||
//don't call the gs if the value isn't the same
|
||||
if (this[pprop] == value )
|
||||
return;
|
||||
|
||||
//set the current value to the setter value
|
||||
this._value = this[pprop];
|
||||
|
||||
//set
|
||||
gs.set.apply(this, [value]);
|
||||
|
||||
//set the new value. this only matters if the setter set it
|
||||
this[pprop] = this._value;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
m_implicit: function (that, property, egs)
|
||||
{
|
||||
//keep the original function available so we can override it
|
||||
that.__private[property] = egs;
|
||||
|
||||
that.__defineGetter__(property, egs);
|
||||
that.__defineSetter__(property, egs);
|
||||
},
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
m_overload: function (that, property, value, nArgs)
|
||||
{
|
||||
var funcsByNArgs = Structr.setOverloadedMethod(that, property, value, nArgs);
|
||||
|
||||
var multiFunc = function()
|
||||
{
|
||||
var func = funcsByNArgs[arguments.length];
|
||||
|
||||
if(func)
|
||||
{
|
||||
return funcsByNArgs[arguments.length].apply(this, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
var expected = [];
|
||||
|
||||
for(var sizes in funcsByNArgs)
|
||||
{
|
||||
expected.push(sizes);
|
||||
}
|
||||
|
||||
throw new Error('Expected '+expected.join(',')+' parameters, got '+arguments.length+'.');
|
||||
}
|
||||
}
|
||||
|
||||
multiFunc.overloaded = true;
|
||||
|
||||
return multiFunc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//extends from one class to another. note: the TO object should be the parent. a copy is returned.
|
||||
Structr.extend = function ()
|
||||
{
|
||||
var from = arguments[0],
|
||||
to = {};
|
||||
|
||||
for(var i = 1, n = arguments.length; i < n; i++)
|
||||
{
|
||||
var obj = arguments[i];
|
||||
|
||||
Structr.copy(obj instanceof Function ? obj() : obj, to);
|
||||
}
|
||||
|
||||
|
||||
var that = {
|
||||
__private: {
|
||||
|
||||
//contains modifiers for all properties of object
|
||||
propertyModifiers: {}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Structr.copy(from, that);
|
||||
|
||||
var usedProperties = {},
|
||||
property;
|
||||
|
||||
for(property in to)
|
||||
{
|
||||
var value = to[property];
|
||||
|
||||
|
||||
var propModifiersAr = property.split(' '), //property is at the end of the modifiers. e.g: override bindable testProperty
|
||||
propertyName = propModifiersAr.pop(),
|
||||
|
||||
modifierList = that.__private.propertyModifiers[propertyName] || (that.__private.propertyModifiers[propertyName] = []);
|
||||
|
||||
|
||||
if (propModifiersAr.length)
|
||||
{
|
||||
var propModifiers = {};
|
||||
for(var i = propModifiersAr.length; i--;)
|
||||
{
|
||||
var modifier = propModifiersAr[i];
|
||||
|
||||
propModifiers['m_' + propModifiersAr[i]] = 1;
|
||||
|
||||
if (modifierList.indexOf(modifier) == -1)
|
||||
{
|
||||
modifierList.push(modifier);
|
||||
}
|
||||
}
|
||||
|
||||
if(propModifiers.m_merge)
|
||||
{
|
||||
value = Structr.copy(from[propertyName], value);
|
||||
}
|
||||
|
||||
//if explicit, or implicit modifiers are set, then we need an explicit modifier first
|
||||
if (propModifiers.m_explicit || propModifiers.m_implicit)
|
||||
{
|
||||
value = Structr.modifiers.m_explicit(that, propertyName, value);
|
||||
}
|
||||
|
||||
if (propModifiers.m_override)
|
||||
{
|
||||
value = Structr.modifiers.m_override(that, propertyName, value);
|
||||
}
|
||||
|
||||
if (propModifiers.m_implicit)
|
||||
{
|
||||
//getter is set, don't continue.
|
||||
Structr.modifiers.m_implicit(that, propertyName, value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for(var j = modifierList.length; j--;)
|
||||
{
|
||||
value[modifierList[j]] = true;
|
||||
}
|
||||
|
||||
if(usedProperties[propertyName])
|
||||
{
|
||||
var oldValue = that[propertyName];
|
||||
|
||||
//first property will NOT be overloaded, so we need to check it here
|
||||
if(!oldValue.overloaded) Structr.modifiers.m_overload(that, propertyName, oldValue, undefined);
|
||||
|
||||
value = Structr.modifiers.m_overload(that, propertyName, value, undefined);
|
||||
}
|
||||
|
||||
usedProperties[propertyName] = 1;
|
||||
|
||||
that.__private[propertyName] = that[propertyName] = value;
|
||||
}
|
||||
|
||||
//if the parent constructor exists, and the child constructor IS the parent constructor, it means
|
||||
//the PARENT constructor was defined, and the CHILD constructor wasn't, so the parent prop was copied over. We need to create a new function, and
|
||||
//call the parent constructor when the child is instantiated, otherwise it'll be the same class essentially (setting proto)
|
||||
if (that.__construct && from.__construct && that.__construct == from.__construct)
|
||||
{
|
||||
that.__construct = Structr.modifiers.m_override(that, '__construct', function()
|
||||
{
|
||||
this._super.apply(this, arguments);
|
||||
});
|
||||
}
|
||||
else
|
||||
if(!that.__construct)
|
||||
{
|
||||
that.__construct = function() {};
|
||||
}
|
||||
|
||||
|
||||
//copy
|
||||
for(var property in from.__construct)
|
||||
{
|
||||
if(from.__construct[property]['static'] && !that[property])
|
||||
{
|
||||
that.__construct[property] = from.__construct[property];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var propertyName;
|
||||
|
||||
//apply the static props
|
||||
for(propertyName in that)
|
||||
{
|
||||
var value = that[propertyName];
|
||||
|
||||
//if the value is static, then tack it onto the constructor
|
||||
if (value && value['static'])
|
||||
{
|
||||
that.__construct[propertyName] = value;
|
||||
delete that[propertyName];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return that;
|
||||
}
|
||||
|
||||
|
||||
//really.. this isn't the greatest idea if a LOT of objects
|
||||
//are being allocated in a short perioud of time. use the closure
|
||||
//method instead. This is great for objects which are instantiated ONCE, or a couple of times :P.
|
||||
Structr.fh = function (that)
|
||||
{
|
||||
that = Structr.extend({}, that);
|
||||
|
||||
//deprecated
|
||||
that.getMethod = function (property)
|
||||
{
|
||||
return Structr.getMethod(this, property);
|
||||
}
|
||||
|
||||
that.extend = function ()
|
||||
{
|
||||
return Structr.extend.apply(null, [this].concat(arguments))
|
||||
}
|
||||
|
||||
//copy to target object
|
||||
that.copyTo = function (target, lite)
|
||||
{
|
||||
Structr.copy(this, target, lite);
|
||||
}
|
||||
|
||||
//wraps the objects methods so this always points to the right place
|
||||
that.wrap = function(property)
|
||||
{
|
||||
return Structr.wrap(this, property);
|
||||
}
|
||||
|
||||
return that;
|
||||
}
|
||||
|
||||
module.exports = Structr;
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
var Structr=function(a,c){c||(c=Structr.fh({}));var b=Structr.extend(c,a);if(!b.__construct)b.__construct=function(){};b.__construct.prototype=b;b.__construct.extend=function(a){return Structr(a,b)};return b.__construct};Structr.copy=function(a,c){c||(c={});for(var b in a){var d=a[b],e=c[b];typeof d=="object"?(e=e&&d instanceof e.constructor?e:d instanceof Array?[]:{},Structr.copy(d,e)):e=d;c[b]=e}return c};Structr.getMethod=function(a,c){return function(){return a[c].apply(a,arguments)}};
|
||||
Structr.findProperties=function(a,c){var b=[],d;for(d in a){var e=a[d];e&&e[c]&&b.push(d)}return b};Structr.getNArgs=function(a){return(a=a.toString().replace(/\{[\W\S]+\}/g,"").match(/\w+(?=[,\)])/g))?a.length:0};Structr.getFuncsByNArgs=function(a,c){return a.__private["overload::"+c]||(a.__private["overload::"+c]={})};Structr.getOverloadedMethod=function(a,c,b){return Structr.getFuncsByNArgs(a,c)[b]};
|
||||
Structr.setOverloadedMethod=function(a,c,b,d){a=Structr.getFuncsByNArgs(a,c);if(b.overloaded)return a;a[d||Structr.getNArgs(b)]=b;return a};
|
||||
Structr.modifiers={m_override:function(a,c,b){var d=a.__private&&a.__private[c]||a[c]||function(){},e=d;if(d.overloaded)var g=Structr.getNArgs(b),e=Structr.getOverloadedMethod(a,c,g);var h=function(){this._super=e;var a=b.apply(this,arguments);delete this._super;return a};if(d.overloaded)return Structr.modifiers.m_overload(a,c,h,g);return h},m_explicit:function(a,c,b){var d="_gs::"+c;typeof b!="object"&&(b={});if(!b.get)b.get=function(){return this._value};if(!b.set)b.set=function(b){this._value=
|
||||
b};return function(a){if(arguments.length){if(this[d]!=a)this._value=this[d],b.set.apply(this,[a]),this[d]=this._value}else{this._value=this[d];var c=b.get.apply(this);delete this._value;return c}}},m_implicit:function(a,c,b){a.__private[c]=b;a.__defineGetter__(c,b);a.__defineSetter__(c,b)},m_overload:function(a,c,b,d){var e=Structr.setOverloadedMethod(a,c,b,d),a=function(){return e[arguments.length].apply(this,arguments)};a.overloaded=!0;return a}};
|
||||
Structr.extend=function(a,c){c||(c={});var b={__private:{propertyModifiers:{}}};c instanceof Function&&(c=c());Structr.copy(a,b);var d={},e;for(e in c){var g=c[e],h=e.split(" "),f=h.pop(),i=b.__private.propertyModifiers[f]||(b.__private.propertyModifiers[f]=[]);if(h.length){for(var j={},k=h.length;k--;){var l=h[k];j["m_"+h[k]]=1;i.indexOf(l)==-1&&i.push(l)}if(j.m_explicit||j.m_implicit)g=Structr.modifiers.m_explicit(b,f,g);j.m_override&&(g=Structr.modifiers.m_override(b,f,g));if(j.m_implicit){Structr.modifiers.m_implicit(b,
|
||||
f,g);continue}}for(h=i.length;h--;)g[i[h]]=!0;d[f]&&(i=b[f],i.overloaded||Structr.modifiers.m_overload(b,f,i,void 0),g=Structr.modifiers.m_overload(b,f,g,void 0));d[f]=1;b.__private[f]=b[f]=g}if(b.__construct&&a.__construct&&b.__construct==a.__construct)b.__construct=Structr.modifiers.m_override(b,"__construct",function(){this._super.apply(this,arguments)});for(f in b)if((g=b[f])&&g["static"])b.__construct[f]=g,delete b[f];return b};
|
||||
Structr.fh=function(a){a=Structr.extend({},a);a.getMethod=function(a){return Structr.getMethod(this,a)};a.extend=function(a){return Structr.extend(this,a)};a.copyTo=function(a){Structr.copy(this,a)};return a};if(this.exports)exports.Structr=Structr;
|
||||
Reference in New Issue
Block a user