oversip-mod-mysql 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1,5 @@
1
+ MAIN AUTHOR
2
+ ===========
3
+
4
+ - Iñaki Baz Castillo <ibc@aliax.net> (Github @ibc)
5
+
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Name: oversip-mod-mysql
2
+ Maintainer: Iñaki Baz Castillo <ibc@aliax.net>
3
+ Copyright (c) 2012 Iñaki Baz Castillo <ibc@aliax.net>
4
+
5
+
6
+ License: The MIT License
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining
9
+ a copy of this software and associated documentation files (the
10
+ "Software"), to deal in the Software without restriction, including
11
+ without limitation the rights to use, copy, modify, merge, publish,
12
+ distribute, sublicense, and/or sell copies of the Software, and to
13
+ permit persons to whom the Software is furnished to do so, subject to
14
+ the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be
17
+ included in all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,176 @@
1
+ # oversip-mod-mysql
2
+
3
+ `oversip-mod-mysql` provides an easy to use MySQL connector for [OverSIP](http://www.oversip.net) proxy based on [mysql2](https://github.com/brianmario/mysql2) driver. The library allows both pure async style (via callbacks) or serial style (by using [em-synchrony](https://github.com/igrigorik/em-synchrony/) Gem).
4
+
5
+ Check the [mysql2 documentation](https://github.com/brianmario/mysql2/blob/master/README.md) for the exact syntax and usage of the MySQL queries.
6
+
7
+
8
+ ## API
9
+
10
+
11
+ ### Method `OverSIP:M:Mysql.add_pool(options, db_data)`
12
+
13
+ Creates a MySQL connection pool. Parameters:
14
+
15
+ * `options`: A mandatory `Hash` with the following fields:
16
+ * `:name`: Mandatory field. Must be a `Symbol` with the name for this pool.
17
+ * `:pool_size`: The number of parallel MySQL connections to perform. By default 10.
18
+ * `:synchrony`: Whether to use [em-synchrony](https://github.com/igrigorik/em-synchrony/) or not. By default `false`.
19
+
20
+ * `db_data`: A mandatory `Hash` that will be passed to [`Mysql2::EM::Client.new`](https://github.com/brianmario/mysql2#connection-options).
21
+
22
+ *NOTE:* There is no need to pass the option `:async => true` in `db_data`. That is automatically done by the library.
23
+
24
+
25
+ ### Method `OverSIP:M:Mysql.pool(name)`
26
+
27
+ Retrieves a previously created pool with the given name. Raises an `ArgumentError` if the given name does not exist in the list of created pools.
28
+
29
+
30
+
31
+
32
+ ## Pure async style usage
33
+
34
+ When creating a pool with `options[:synchrony] => false` (default behaviour) the obtained pool is a [`EventMachine::Pool`](https://github.com/ibc/EventMachine-LE/blob/master/lib/em/pool.rb) instance and thus, it requires the following usage:
35
+
36
+
37
+ ### Example
38
+
39
+ On top of `/etc/oversip/server.rb`:
40
+
41
+ ```
42
+ require "oversip-mod-mysql"
43
+
44
+ def (OverSIP::SystemEvents).on_initialize
45
+ OverSIP::M::Mysql.add_pool(
46
+ {
47
+ :name => :my_async_db,
48
+ :pool_size => 5,
49
+ :synchrony => false
50
+ },
51
+ {
52
+ :host => "localhost",
53
+ :username => "oversip",
54
+ :password => "xxxxxx",
55
+ :database => "oversip",
56
+ :cast_booleans => true,
57
+ :symbolize_keys => true
58
+ }
59
+ )
60
+ end
61
+ ```
62
+
63
+ Somewhere within the `OverSIP::SipEvents.on_request()` method in `/etc/oversip/server.rb`:
64
+
65
+ ```
66
+ pool = OverSIP::M::Mysql.pool(:my_async_db)
67
+
68
+ begin
69
+ pool.perform do |db_conn|
70
+ query = db_conn.aquery "SELECT * FROM users WHERE user = \'#{request.from.user}\'"
71
+
72
+ query.callback do |result|
73
+ log_info "DB async query result: #{result.to_a.inspect}"
74
+ if result.any?
75
+ # Add a X-Header with value the 'custom_header' field of the table row:
76
+ request.set_header "X-Header", result.first["custom_header"]
77
+ proxy = ::OverSIP::SIP::Proxy.new
78
+ proxy.route request
79
+ else
80
+ request.reply 404, "User not found in DB"
81
+ end
82
+ end
83
+
84
+ query.errback do |error|
85
+ log_error "DB async query error: #{error.inspect}"
86
+ request.reply 500, "DB async query error"
87
+ end
88
+ end
89
+
90
+ rescue ::Mysql2::Error => e
91
+ log_error "DB async query error:"
92
+ log_error e
93
+ request.reply 500, "DB async query error"
94
+ end
95
+ ```
96
+
97
+
98
+ ## Sync style usage with `em-synchrony`
99
+
100
+ When creating a pool with `options[:synchrony] => true` the obtained pool is a [`EventMachine::Synchrony::ConnectionPool`](https://github.com/igrigorik/em-synchrony/blob/master/lib/em-synchrony/connection_pool.rb) instance.
101
+
102
+ Please ensure you properly understand how [em-synchrony](https://github.com/igrigorik/em-synchrony/) works. Specially take into account that just the code within the `EM.synchrony do [...] end` block is executed serially. Code placed after that block is executed immediately, this is, *before* the serial code is executed. So if you want to use serial style coding write all your logic code within a `EM.synchrony do [...] end` block.
103
+
104
+ * For more information about `em-synchrony` usage check [Untangling Evented Code with Ruby Fibers](http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/).
105
+
106
+
107
+ ### Example
108
+
109
+ On top of `/etc/oversip/server.rb`:
110
+
111
+ ```
112
+ require "oversip-mod-mysql"
113
+
114
+ def (OverSIP::SystemEvents).on_initialize
115
+ OverSIP::M::Mysql.add_pool(
116
+ {
117
+ :name => :my_sync_db,
118
+ :pool_size => 5,
119
+ :synchrony => true
120
+ },
121
+ {
122
+ :host => "localhost",
123
+ :username => "oversip",
124
+ :password => "xxxxxx",
125
+ :database => "oversip",
126
+ :cast_booleans => true,
127
+ :symbolize_keys => true
128
+ }
129
+ )
130
+ end
131
+ ```
132
+
133
+ Somewhere within the `OverSIP::SipEvents.on_request()` method in `/etc/oversip/server.rb`:
134
+
135
+ ```
136
+ EM.synchrony do
137
+ pool = OverSIP::M::Mysql.pool(:my_sync_db)
138
+
139
+ begin
140
+ result = pool.query "SELECT * FROM users WHERE user = \'#{request.from.user}\'"
141
+ log_info "DB sync query result: #{result.to_a.inspect}"
142
+ if result.any?
143
+ # Add a X-Header with value the 'custom_header' field of the table row:
144
+ request.set_header "X-Header", result.first["custom_header"]
145
+ proxy = ::OverSIP::SIP::Proxy.new :proxy_out
146
+ proxy.route request
147
+ else
148
+ request.reply 404, "User not found in DB"
149
+ end
150
+
151
+ rescue ::Mysql2::Error => e
152
+ log_error "DB sync query error:"
153
+ log_error e
154
+ request.reply 500, "DB sync query error"
155
+ end
156
+ end
157
+ ```
158
+
159
+
160
+ ## Using sync and async styles together
161
+
162
+ A pool created with `OverSIP:M:Mysql.add_pool()` method must be sync or async. However the user can set two pools, the first one sync and the second one sync.
163
+
164
+ When a sync pool is created, the library loads `em-synchrony/mysql2` which overrides the `Mysql2::EM::Client#query()` method. So if *at least* one of your pools uses sync style then you must use the `Mysql2::EM::Client#aquery()` method for the async pool (which is an alias of the original `query()` method).
165
+
166
+
167
+ ## Installation
168
+
169
+ ```
170
+ ~$ gem install oversip-mod-mysql
171
+ ```
172
+
173
+
174
+ ## Author
175
+
176
+ Iñaki Baz Castillo <ibc@aliax.net> (Github [@ibc](https://github.com/ibc)).
@@ -0,0 +1,71 @@
1
+ require "mysql2/em"
2
+
3
+ require "oversip-mod-mysql/version.rb"
4
+ require "oversip-mod-mysql/mysql2_em_client.rb"
5
+
6
+
7
+ module OverSIP
8
+ module Modules
9
+
10
+ module Mysql
11
+
12
+ extend ::OverSIP::Logger
13
+
14
+ DEFAULT_POOL_SIZE = 10
15
+ DEFAULT_SYNCHRONY = false
16
+
17
+ @log_id = "Mysql module"
18
+ @pools = {}
19
+
20
+ def self.add_pool options, db_data
21
+ raise ::ArgumentError, "`options' must be a Hash" unless options.is_a? ::Hash
22
+ raise ::ArgumentError, "`db_data' must be a Hash" unless db_data.is_a? ::Hash
23
+
24
+ name, pool_size, synchrony = options.values_at(:name, :pool_size, :synchrony)
25
+ pool_size ||= DEFAULT_POOL_SIZE
26
+ synchrony ||= DEFAULT_SYNCHRONY
27
+
28
+ raise ::ArgumentError, "`options[:name]' must be a Symbol" unless name.is_a? ::Symbol
29
+ raise ::ArgumentError, "`options[:pool_size]' must be a positive Fixnum" unless pool_size.is_a? ::Fixnum and pool_size > 0
30
+
31
+ # Forcing DB autoreconnect.
32
+ db_data[:reconnect] = true
33
+
34
+ # Use em-synchrony for serial coding.
35
+ if synchrony
36
+ begin
37
+ require "em-synchrony"
38
+ require "em-synchrony/mysql2"
39
+ rescue ::LoadError
40
+ OverSIP::Launcher.fatal "em-synchrony not installed: gem install em-synchrony"
41
+ end
42
+
43
+ OverSIP::SystemCallbacks.on_started do
44
+ log_system_info "Adding a sync pool with name #{name.inspect}..."
45
+ @pools[name] = ::EM::Synchrony::ConnectionPool.new(size: pool_size) do
46
+ ::Mysql2::EM::Client.new(db_data)
47
+ end
48
+ end
49
+
50
+ # Don't use em-synchrony but pure callbacks.
51
+ else
52
+ OverSIP::SystemCallbacks.on_started do
53
+ log_system_info "Adding an async pool with name #{name.inspect}..."
54
+ pool = @pools[name] = ::EM::Pool.new
55
+ pool_size.times do
56
+ pool.add ::Mysql2::EM::Client.new(db_data)
57
+ end
58
+ end
59
+ end
60
+ end # def self.add_pool
61
+
62
+ def self.pool name
63
+ pool = @pools[name]
64
+ raise ::ArgumentError, "no pool with `name' #{name.inspect}" unless pool
65
+ pool
66
+ end
67
+
68
+ end # module Mysql
69
+
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ module Mysql2
2
+ module EM
3
+ class Client
4
+ # Allow the aquery() method even if 'em-synchrony' is not loaded.
5
+ alias :aquery :query
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module OverSIP
2
+ module Modules
3
+
4
+ module Mysql
5
+ module Version
6
+ MAJOR = 0
7
+ MINOR = 0
8
+ TINY = 1
9
+ DEVEL = nil # Set to nil for stable releases.
10
+ end
11
+
12
+ VERSION = [Version::MAJOR, Version::MINOR, Version::TINY].join(".")
13
+ VERSION << ".#{Version::DEVEL}" if Version::DEVEL
14
+ end
15
+
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oversip-mod-mysql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Inaki Baz Castillo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: oversip
16
+ requirement: &16825480 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *16825480
25
+ - !ruby/object:Gem::Dependency
26
+ name: mysql2
27
+ requirement: &17963820 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.3.11
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *17963820
36
+ description: ! 'oversip-mod-mysql provides an easy to use MySQL connector for OverSIP
37
+ proxy. The library allows both pure async style (via callbacks) or serial style
38
+ (by using ''em-synchrony'' Gem).
39
+
40
+ '
41
+ email:
42
+ - ibc@aliax.net
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - lib/oversip-mod-mysql.rb
48
+ - lib/oversip-mod-mysql/version.rb
49
+ - lib/oversip-mod-mysql/mysql2_em_client.rb
50
+ - README.md
51
+ - AUTHORS
52
+ - LICENSE
53
+ homepage: https://github.com/versatica/oversip-mod-mysql
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: 1.9.2
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.11
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: MySQL connector module for OverSIP
77
+ test_files: []
78
+ has_rdoc: false