rack-campaign 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.textile CHANGED
@@ -1 +1,137 @@
1
- More to come soon...
1
+ h2. rack-campaign
2
+
3
+ This is a "Rack":http://rack.rubyforge.org/ application (a gem is available by the same name) allowing you to maintain a "YAML":http://www.yaml.org/ file of short URLs that redirect to target URLs with a set of specified Google Analytics variables. It could be used to attach any number of parameters by any name to the query string.
4
+
5
+ h2. What it does:
6
+
7
+ *example promo url*:
8
+
9
+ @http://zetetic.net/c/blog-rack-campaign@
10
+
11
+ When the user visits this link, our web server sees the /c/ location and forwards it to rack-campaign, which looks up 'blog-rack-campaign' in the YAML file, and redirects the user to the full URL, with campaign variables attached.
12
+
13
+ *resulting full url*:
14
+
15
+ @http://www.zetetic.net/blog/2010/06/11/introducing-rack-campaign?utm_campaign=rack-campaign&utm_source=blog&utm_medium=internets&utm_content=example%20link@
16
+
17
+ The former is much better than the latter, especially for newsletters and other promotional links. And with a Rack application and a YAML file you can host it yourself, you don't need to rely on bit.ly or other URL shorteners, and you can "fix" any mistakes after publishing a URL simply by updating the YAML file and reloading Unicorn (taking advantage of zero down-time!) [ _You could use another Rack-server, we like Unicorn._ ]
18
+
19
+ h2. Installation
20
+
21
+ @gem install rack-campaign@
22
+
23
+ The rest depends on how you intend to use it.
24
+
25
+ h2. Example Files
26
+
27
+ In the @/examples@ directory of the source distribution are some sample configuration files. @config.ru@ is a @rackup@ file, initializing the rack-campaign middleware. You don't have to use rack-campaign as a stand-alone Rack application, you could instead use it in a middleware stack (although you might want to modify it's behavior). You probably want to use the map directive in that case to assign rack-campaign to a particular url path (we use /c).
28
+
29
+ h2. Example Configuration
30
+
31
+ This is how we use rack-campaign as a stand-alone Rack application. Nginx is our web-server, and we use Unicorn to serve up rack-campaign for the /c path:
32
+
33
+ */www/campaigns/campaigns.yml*:
34
+
35
+ <pre><code>
36
+ blog-rack-campaign:
37
+ url: http://dev.zetetic.net/blog/2010/06/11/introducing-rack-campaign
38
+ tokens:
39
+ campaign: rack-campaign
40
+ source: blog
41
+ medium: internets
42
+ content: example link
43
+
44
+ blog-getstrip:
45
+ url: http://getstrip.com
46
+ tokens:
47
+ campaign: rack-campaign
48
+ source: blog
49
+ medium: internets
50
+ term: strip rocks!
51
+ content: example link
52
+ </code></pre>
53
+
54
+ */www/campaigns/config.ru*:
55
+
56
+ <pre><code>
57
+ # Rack-up application config
58
+
59
+ require 'rubygems'
60
+ require 'rack/zetetic/rack-campaign'
61
+
62
+ run Rack::Zetetic::CampaignLink.new('/www/campaigns/campaigns.yml')
63
+ </code></pre>
64
+
65
+ *nginx.conf*:
66
+
67
+ <pre><code>
68
+ # define upstream for campaign routing
69
+ upstream campaigns {
70
+ server unix:/www/campaigns/tmp/sockets/unicorn.sock;
71
+ }
72
+
73
+ location /c {
74
+ proxy_redirect off;
75
+ proxy_set_header Host $host;
76
+ proxy_set_header X-Real-IP $remote_addr;
77
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
78
+ proxy_max_temp_file_size 0;
79
+
80
+ # forward everything else to the mongrel cluster
81
+ if (!-f $request_filename) {
82
+ proxy_pass http://campaigns;
83
+ break;
84
+ }
85
+ }
86
+ </code></pre>
87
+
88
+ */etc/init.d/unicorn_rack*:
89
+
90
+ <pre><code>
91
+ #!/bin/bash
92
+ #
93
+ # unicorn_rack Startup script for Unicorn master processes
94
+ #
95
+ # chkconfig: - 85 15
96
+ # description: unicorn is a magical process offering up workers to nginx
97
+ #
98
+
99
+ USER=mongrel
100
+ RETVAL=0
101
+ APPS=( '/www/campaigns' )
102
+
103
+ for APP in "${APPS[@]}"
104
+ do
105
+ case "$1" in
106
+ start)
107
+ echo "Starting up $APP"
108
+ cd $APP
109
+ sudo -u $USER unicorn -c $APP/unicorn.rb -E production -D
110
+ RETVAL=$?
111
+ ;;
112
+ stop)
113
+ echo "Stopping $APP"
114
+ PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
115
+ sudo -u $USER kill -INT $PID
116
+ RETVAL=$?
117
+ ;;
118
+ restart)
119
+ $0 stop
120
+ sleep 2
121
+ $0 start
122
+ ;;
123
+ reload)
124
+ echo "Re-loading $APPS"
125
+ PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
126
+ sudo -u $USER kill -HUP $PID
127
+ RETVAL=$?
128
+ ;;
129
+ *)
130
+ echo "Usage: unicorn_rack {start|stop|restart|reload}"
131
+ exit 1
132
+ ;;
133
+ esac
134
+ done
135
+
136
+ exit $RETVAL
137
+ </code></pre>
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'date'
5
5
  require 'spec/rake/spectask'
6
6
 
7
7
  GEM = "rack-campaign"
8
- GEM_VERSION = "0.0.2"
8
+ GEM_VERSION = "0.0.3"
9
9
  AUTHOR = "Billy Gray"
10
10
  EMAIL = "wgray@zetetic.net"
11
11
  HOMEPAGE = "http://github.com/billymeltdown/rack-campaign"
@@ -25,7 +25,7 @@ spec = Gem::Specification.new do |s|
25
25
  s.homepage = HOMEPAGE
26
26
  s.add_dependency "rack"
27
27
  s.require_path = 'lib'
28
- s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib}/**/*")
28
+ s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib}/**/*") + Dir.glob("examples/**/*")
29
29
  end
30
30
 
31
31
  task :default => :spec
@@ -0,0 +1,16 @@
1
+ blog-rack-campaign:
2
+ url: http://dev.zetetic.net/blog/2010/06/11/introducing-rack-campaign
3
+ tokens:
4
+ campaign: rack-campaign
5
+ source: blog
6
+ medium: internets
7
+ content: example link
8
+
9
+ blog-getstrip:
10
+ url: http://getstrip.com
11
+ tokens:
12
+ campaign: rack-campaign
13
+ source: blog
14
+ medium: internets
15
+ term: strip rocks!
16
+ content: example link
@@ -0,0 +1,6 @@
1
+ # Rack application
2
+
3
+ require 'rubygems'
4
+ require 'rack/zetetic/rack-campaign'
5
+
6
+ run Rack::Zetetic::CampaignLink.new('/path/to/your/campaigns.yml')
@@ -0,0 +1,47 @@
1
+ #!/bin/bash
2
+ #
3
+ # unicorn_rack Startup script for Unicorn master processes
4
+ #
5
+ # chkconfig: - 85 15
6
+ # description: unicorn is a magical process offering up workers to nginx
7
+ #
8
+
9
+ USER=mongrel
10
+ RETVAL=0
11
+ APPS=( '/www/campaigns' )
12
+
13
+ for APP in "${APPS[@]}"
14
+ do
15
+ case "$1" in
16
+ start)
17
+ echo "Starting up $APP"
18
+ cd $APP
19
+ sudo -u $USER unicorn -c $APP/unicorn.rb -E production -D
20
+ RETVAL=$?
21
+ ;;
22
+ stop)
23
+ echo "Stopping $APP"
24
+ PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
25
+ sudo -u $USER kill -INT $PID
26
+ RETVAL=$?
27
+ ;;
28
+ restart)
29
+ $0 stop
30
+ sleep 2
31
+ $0 start
32
+ ;;
33
+ reload)
34
+ echo "Re-loading $APPS"
35
+ PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
36
+ sudo -u $USER kill -HUP $PID
37
+ RETVAL=$?
38
+ ;;
39
+ *)
40
+ echo "Usage: unicorn_rack {start|stop|restart|reload}"
41
+ exit 1
42
+ ;;
43
+ esac
44
+ done
45
+
46
+ exit $RETVAL
47
+
@@ -0,0 +1,69 @@
1
+ # unicorn -c /path/to/unicorn.rb -e production -D
2
+ # Unicorn-specific config
3
+ # Largely borrowed from the Github crew
4
+
5
+ app_dir = '/www/campaign_link'
6
+ worker_processes (ENV['RACK_ENV'] == 'production' ? 6 : 2)
7
+
8
+ # Restart any workers that haven't responded in 30 seconds
9
+ timeout 30
10
+
11
+ # Load the Rack app into the master before forking workers
12
+ # for super-fast worker spawn times
13
+ preload_app true
14
+
15
+ # Listen on a Unix data socket
16
+ listen 'unix:' + app_dir + '/tmp/sockets/unicorn.sock', :backlog => 2048
17
+
18
+ ##
19
+ # REE
20
+ # http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
21
+ if GC.respond_to?(:copy_on_write_friendly=)
22
+ GC.copy_on_write_friendly = true
23
+ end
24
+
25
+ before_fork do |server, worker|
26
+ ##
27
+ # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
28
+ # immediately start loading up a new version of itself (loaded with a new
29
+ # version of our app). When this new Unicorn is completely loaded
30
+ # it will begin spawning workers. The first worker spawned will check to
31
+ # see if an .oldbin pidfile exists. If so, this means we've just booted up
32
+ # a new Unicorn and need to tell the old one that it can now die. To do so
33
+ # we send it a QUIT.
34
+ #
35
+ # Using this method we get 0 downtime deploys.
36
+
37
+ old_pid = app_dir + '/tmp/pids/unicorn.pid.oldbin'
38
+ if File.exists?(old_pid) && server.pid != old_pid
39
+ begin
40
+ Process.kill("QUIT", File.read(old_pid).to_i)
41
+ rescue Errno::ENOENT, Errno::ESRCH
42
+ # someone else did our job for us
43
+ end
44
+ end
45
+ end
46
+
47
+ after_fork do |server, worker|
48
+ ##
49
+ # Unicorn master is started as root, which is fine, but let's
50
+ # drop the workers to mongrel:mongrel (or whatever you like...)
51
+ begin
52
+ uid, gid = Process.euid, Process.egid
53
+ user, group = 'mongrel', 'mongrel'
54
+ target_uid = Etc.getpwnam(user).uid
55
+ target_gid = Etc.getgrnam(group).gid
56
+ worker.tmp.chown(target_uid, target_gid)
57
+ if uid != target_uid || gid != target_gid
58
+ Process.initgroups(user, target_gid)
59
+ Process::GID.change_privilege(target_gid)
60
+ Process::UID.change_privilege(target_uid)
61
+ end
62
+ rescue => e
63
+ if ENV['RACK_ENV'] == 'development'
64
+ STDERR.puts "couldn't change user, oh well"
65
+ else
66
+ raise e
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Billy Gray
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-10 00:00:00 -04:00
17
+ date: 2010-06-14 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -43,6 +43,10 @@ files:
43
43
  - README.textile
44
44
  - Rakefile
45
45
  - lib/rack/zetetic/campaign_link.rb
46
+ - examples/campaigns.yml
47
+ - examples/config.ru
48
+ - examples/initscript
49
+ - examples/unicorn.rb
46
50
  has_rdoc: true
47
51
  homepage: http://github.com/billymeltdown/rack-campaign
48
52
  licenses: []