Saturday 26 May 2012

observers


node.js + Socket.io + Bash. A collaborative terminal for your browser

https://gist.github.com/947512

Monday 21 May 2012

workng with meteor

Try it yourself In about 3 minutes, you'll make your own copy of Leaderboard and deploy it live on the Internet for you and your friends to use. No programming knowledge required! Pick a name for your new app. I'll call it... .meteor.com new suggestion Install Meteor (if you haven't already). In your Terminal window, run: $ curl install.meteor.com | sh Make a copy of the example. $ meteor create --example leaderboard Get it running on the cloud. $ cd leaderboard $ meteor deploy testing-app.meteor.com Now, open testing-app.meteor.com in a new tab in your web browser. There's your app! http://meteor.com/examples/leaderboard

Push Service


Push Example
=========================================

create new server and client for push/sub notifications
----------------
client: http://stream-channel.herokuapp.com/
server: http://stream-server.herokuapp.com/



code:https://github.com/msroot/push-sub-example-ror

Sunday 20 May 2012

High performance Publish/Subscribe solution for Ruby On Rails or Juggernaut vs. Faye


In this post I want to share some experience in pub/sub for RoR. First, I'll briefly explain what kind of application we have, why we've chosen Faye and then I'll say how to run many instances of Faye without any Load Balancers and without Redis. 

One of RoR apps I've developed is handling more than 30 000 RMP (requests per minute) while i'm writing this post (and it is ready to handle more). About 90% of requests do pushes to Faye. About 6 000 users are connected to Faye right now. Everything is working very stable and smooth. And we are going to grow :)

But before Faye we used Juggernaut. These technologies are pretty same. And both are easy to use and integrate with Rails app. We've choosen Juggernaut because it was... more popular I think. So, we've patched it a little bit for our needs and quickly integrated to our application. Everything was good untill first deployment to production with less than hundred online users. It loaded servers - but we were ready to accepted it. But then we found another issue - it was very unstable. If somebody pushes broken data to it - process dies. Totally dies. So we've added monit to monitor Juggernaut. Not really cool, right? We've been patching it a lot. Still, it was not stable and sometimes it was using so much CPU that we've decided to look on another solution. And here we've found out Faye.

Before describing Faye I want to say that Juggernaut has 1 great benefit which Faye doesn't have - you can push events directly to Redis and Juggernaut will catch it and process. You can't easily do the same with Faye (maybe it will be done in future). Instead of it you have to send a HTTP request, which is slower and loads Faye's server.

So, we've decided to switch to Faye. We've choosen node.js instead of Thin and after first deployment we found the difference - Faye is stable and doesn't load system at all.

And now, finally, about high-performance and scalability.

Both Node.js and Thin are very-very slow if you run it with SSL - check my next post to see how to solve this problem

First of all, you need many instances of Faye to support a lot of concurrent users. Faye supports Redis as a  shared storage (in experimental mode, but it seems to be stable). It gives you a possibility to run many instances on many servers but it's slow - it needs to communicate with Redis. So, we've decided to create our own simple mechanism of sharding instead of using Redis.And we didn't want to use one more Load Balancer for it.

Note: this mechanism is designed to work when user subscribes to his own channel. To push data to global channel you need to perform requests to each shard.

Let's say we have a domain name app.com pointing to Load Balancer for Rails app. All our servers have sub-domains like server1.app.com, server2.app.com etc.

Configuration files:

We've created a YAML config where we listed all our instances. It looks like:
  production:
    shards:
      -
        node_port: 42000
        node_host: server1.app.com
        node_local_host: 10.x.x.1 #local IP of server
        run_on: server1_hostname

      -
        node_port: 42001
        node_host: server1.app.com
        node_local_host: 10.x.x.1
        run_on: server1_hostname
      -
        node_port: 42000
        node_host: server2.app.com
        node_local_host: 10.x.x.2
        run_on: server2_hostname
  .....

run_on option is used by our own Rake task to detect what shard to start on specific server during deployment. 
node_host is a public domain name or IP - we are using it to generate URL for users.
node_local_host is a local IP of server, cause we want to push data through local interfaces.

Sharding:

We assign shard for user by very simple formula:
   shard = @shards[user.id % @shards.size]

If you have 3 shards, users with ids 0, 3, 6 are connected to 1st shard; users with id's 1, 4, 7 - to 2nd...

Client side code:
client = new Faye.Client(<%= raw Faye.shard_for(user).url.inspect %>);
client.subscribe(<%= raw Faye.shard_for(user).channel.inspect %>, function(data){...});

Method .url returns URL like http://server1.app.com:42000/faye

Channel for user is just a "/#{user.id}", eg. '/123'.
So, now we need to push events to the needed shard:
...
  uri = URI.parse(Faye.shard_for(user).local_url)
  http = Net::HTTP.new(uri.host, uri.port)
  req = Net::HTTP::Post.new uri.path
  body = {'channel' => Faye.shard_for(user).channel, 'data' => data.to_json, 'ext' => {:auth_token => FAYE_TOKEN}}
  req.set_form_data('message' => body.to_json)
  http.request req
...

Method .local_url returns http://10.x.x.1:42000/faye.


https://github.com/ntenisOT/Faye-Example-Application
http://rails-alex.blogspot.com.au/2011/10/high-performance-publishsubscribe.html
http://railscasts.com/episodes/316-private-pub

Friday 18 May 2012

Tuesday 15 May 2012

rake stats

Facebook Token Expiry



Token Expiry

Since Facebook deprecated the offline_access permission, this has become more complex. The expiration time of the access token you obtain will depend on which flow you are using. See below for more details.

Client-Side Flow

If you use the client-side flow, Facebook will give you back a short lived access token (~ 2 hours).

Signed and Permanent cookies in Rails 3


Signed and Permanent cookies in Rails 3
Published over 2 years ago
David added a very cool feature to Rails recently – Signed cookies and permanent cookies This lets you set permanent and/or signed cookies very easily.
Before this, you’d have to write :
cookies[:user_preference] = {
  :value => @current_user.preferences,
  :expires => 20.years.from_now.utc
}
Now just becomes :
cookies.permanent[:user_preference] = @current_user.preferences
In case you happen to have seen my Railssummit presentation I had talked about using ActiveSupport::MessageVerifier for implementing “Remember me” functionality. The above commit makes that a whole lot easier.
In your model User.rb :
# User.rb
def self.authenticated_with_token(id, stored_salt)
  u = find_by_id(user_id)
  u && u.salt == stored_salt ? u : nil
end
And when the user checks “Remember me” box, make sure the following gets run :
cookies.permanent.signed[:remember_me] = [current_user.id, current_user.salt]
This will set a permanent and signed cookie using the secret specified inActionController::Base.cookie_verifier_secret. If you don’t have the cookie_verifier_secret defined, you might want to do that in one of the initializers.
Now when you want to login using the cookie :
user = User.authenticated_with_token(*cookies.signed[:remember_me])
In this specific case, it’s very important to use the salt in the cookie value. That makes sure the cookie gets invalidated if the user changes his password.


http://m.onkey.org/signed-and-permanent-cookies-in-rails-3

Thursday 10 May 2012

Gaskit


Gaskit

Gaskit a git-backed issue tracker. It uses a branch in your local git database to store the tickets.
Screenshot of Gaskit

Current Status

Gaskit was created as a proof of concept for using Git as a database for an application. It currently only runs against itself.
There is a lot more work to do before it is really useful. If you'd like to help out, clone the repo and run the app to see what needs done.

Running the app

$ bundle install
$ bundle exec rackup
https://github.com/bkeepers/gaskit

I am the smallest rails app!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
%w(action_controller/railtie coderay).map &method(:require)

run TheSmallestRailsApp ||= Class.new(Rails::Application) {
  config.secret_token = routes.append { root to: 'hello#world' }.inspect
  initialize!
}

class HelloController < ActionController::Base
  def world
    render inline: "
      <!DOCTYPE html>
      <title>The Smallest Rails App</title>
      <h3>I am the smallest rails app!</h3>
      <p>Here is my source code:</p>
      #{CodeRay.scan_file(__FILE__, :ruby).div(line_numbers: :table)}
      <a href='https://github.com/artemave/thesmallestrailsapp.com'>Make me smaller</a>
    "
  end
end


http://thesmallestrailsapp.com/

brew install ack && brew install tmux

tmux From Wikipedia, the free encyclopedia Thi tmux session, with two horizontal and one vertical pane. Developer(s) Nicholas Marriott Initial release 2009-09-20 Stable release 1.6 / January 23, 2012; 3 months ago Written in C Operating system Unix-like Available in English Type Command line interface License BSD Website http://tmux.sourceforge.net/ tmux is a software application that can be used to multiplex several virtual consoles, allowing a user to access multiple separate terminal sessions inside a single terminal window or remote terminal session. It is useful for dealing with multiple programs from a command line interface, and for separating programs from the Unix shell that started the program.[1]

HTML presentation and slideshow

http://lab.hakim.se/reveal-js/?transition=cube#/7



https://github.com/hakimel/reveal.js

zoom.js

http://lab.hakim.se/zoom-js/

stroll.js - CSS3 scroll effects

http://lab.hakim.se/scroll-effects/

screenfull.js


screenfull.js

Simple wrapper for cross-browser usage of the JavaScriptFullscreen API, which lets you bring the page or any element into fullscreen. Smoothens out the browser implementation differences, so you don't have too.


http://sindresorhus.com/screenfull.js/

Sunday 6 May 2012

Sortable List in Ruby on Rails 3 – Unobtrusive jQuery

Sortable List in Ruby on Rails 3 – Unobtrusive jQuery

Step 1 – create app

$ rails new books -d mysql

Step 2 – replace contents in rails.js with following (switch from prototype to jquery)

http://github.com/rails/jquery-ujs/blob/master/src/rails.js

Step 3 – bundler

Go to gemfile
gem "rails"
gem "mysql2"
gem "acts_as_list"

# go to console:
$ bundle install

Step 4 – to be quick will scaffold a resource

$ cd books
$ rails g scaffold books name:string
# make sure your config/database.yml file is filled in correctly
$ rake db:create
$ rake db:migrate
Add acts_as_list to model
# book.rb
class Book < ActiveRecord::Base
  acts_as_list
end

Step 5 – add jquery to view and setup javascript content_for

Go to app/views/layouts/books.html.erb
Change this:
<%= javascript_include_tag :defaults %>
To this:
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js", "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js", "rails.js" %>
Also before /body add:
<%= yield :javascript %>

Step 6 – seed the db

Go to db/seeds.rb
#db/seeds.rb
book = Book.create([{ :name => 'Harry Potter' }, { :name => 'Twilight' }, { :name => 'Bible' }])

# back to console
$ rake db:seed
# doesn't work - need to add the position column to books in database
$ rails g migration add_position_to_books position:integer
$ rake db:migrate
$ rake db:seed

Step 7 – edit index for li – tables don’t work

<h1>Listing books</h1>
<ul id="books"> <% @books.each do |book| %>
  <li id="book_<%= book.id %>"><span class="handle">[drag]</span><%= book.name %></li>
<% end %></ul>
<%= link_to 'New book', new_book_path %>

Step 8 – add javascript in view

# index.html.erb
<% content_for :javascript do %>
<%= javascript_tag do %>
// Sorting the list

$(document).ready(function(){
$('#books').sortable({
axis: 'y',
dropOnEmpty: false,
handle: '.handle',
cursor: 'crosshair',
items: 'li',
opacity: 0.4,
scroll: true,
update: function(){
$.ajax({
type: 'post',
data: $('#books').sortable('serialize'),
dataType: 'script',
complete: function(request){
$('#books').effect('highlight');
},
url: '/books/sort'})
}
});
});
<% end %>
<% end %>

Step 9 – controller

#books_controller.rb
def index
@books = Book.order('books.position ASC')
end

def sort
@books = Book.all
@books.each do |book|
book.position = params['book'].index(book.id.to_s) + 1
book.save
end

render :nothing => true
end

Cursor

#style.css
.handle:hover{cursor: move;}

Final step – routes

root to: "books#index"
resources :books do
post :sort, on: :collection
# ruby 1.8 would go :on => :collection
end
PS: if you want an all-in-one resource to become an expert in ruby on rails 3, I wouldn’t bother with textbooks – just buy this video tutorial series (and if you get it through this link I get some commission): Ruby on Rails Tutorial


http://webtempest.com/sortable-list-in-ruby-on-rails-3-almost-unobtrusive-jquery/