ige_isb_api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,284 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ module IGE_ISB_API
5
+ class Constants
6
+ API_VERSION = '2.1'
7
+
8
+ LICENSEE_ID = ENV['ISB_LICENSEE_ID'].to_i # issued by ISB
9
+ CASINO = ENV['ISB_CASINO_ID'] # issued by ISB
10
+ SECRET_KEY = ENV['ISB_SECRET_KEY'] # issued by ISB
11
+ BONUS_API_KEY = ENV['ISB_BONUS_API_KEY'] # issued by ISB
12
+ BONUS_SECRET_KEY = ENV['ISB_BONUS_SECRET_KEY'] # issued by ISB
13
+ CALLBACK_ID = ENV['ISB_CALLBACK_ID'].to_i # issued by ISB
14
+ API_SERVER = ENV['ISB_API_SERVER'] # issued by ISB
15
+ BONUS_API_SERVER = ENV['ISB_BONUS_API_SERVER'] # issued by ISB
16
+ SERVER = {fun: ENV['ISB_FUN_URL'], real: ENV['ISB_REAL_URL']} # issued by ISB
17
+
18
+ DEFAULT_ENCODING = 'utf-8'
19
+ ALLOWED_CURRENCIES = %w(EUR GBP USD)
20
+ ALLOWED_MODES = %w(window gpu opaque transparent direct)
21
+ ALLOWED_GAME_TYPES = %w(flash html5)
22
+ ALLOWED_LIMITATIONS = %w(bet loss time exclusion deposit_extra deposit) # all must be lower case, despite what the docs say
23
+ ALLOWED_FREQUENCIES = %w(daily weekly monthly) # all must be lower case, despite what the docs say
24
+ ALLOWED_BONUS_TYPES = ['before-wager redeemable', 'before-wager non-redeemable', 'after-wager', 'cash']
25
+ ALLOWED_BONUS_STATUSES = [ 'pending', 'accepted', 'active', 'completed',
26
+ 'cancelled', 'declined', 'expired',
27
+ 'completed non-redeemable', 'queue']
28
+ LANGUAGES = {en: 0, fr: 1, es: 2, it: 3, de: 5} # de is documented as being 4, but it's actually 5. The doc is a misprint.
29
+ DEFAULT_CURRENCY_CODE = 'USD'
30
+ DEFAULT_LANGUAGE = 'en'
31
+
32
+ MALE = 0
33
+ FEMALE = 1
34
+ REAL = 0
35
+ FUN = 1
36
+ TEST = 2
37
+ USER_INACTIVE = 0
38
+ USER_ACTIVE = 1
39
+ USER_BANNED = 2
40
+
41
+ ALLOWED_COUNTRY_CODES = {
42
+ af: 'Afghanistan',
43
+ al: 'Albania',
44
+ dz: 'Algeria',
45
+ as: 'American Samoa',
46
+ ad: 'Andorra',
47
+ ao: 'Angola',
48
+ ai: 'Anguilla',
49
+ aq: 'Antarctica',
50
+ ag: 'Antigua and Barbuda',
51
+ ar: 'Argentina',
52
+ am: 'Armenia',
53
+ aw: 'Aruba',
54
+ au: 'Australia',
55
+ at: 'Austria',
56
+ az: 'Azerbaijan',
57
+ bs: 'Bahamas, The',
58
+ bh: 'Bahrain',
59
+ bd: 'Bangladesh',
60
+ bb: 'Barbados',
61
+ by: 'Belarus',
62
+ be: 'Belgium',
63
+ bz: 'Belize',
64
+ bj: 'Benin',
65
+ bm: 'Bermuda',
66
+ bt: 'Bhutan',
67
+ bo: 'Bolivia',
68
+ ba: 'Bosnia and Herzegovina',
69
+ bw: 'Botswana',
70
+ bv: 'Bouvet Island',
71
+ br: 'Brazil',
72
+ io: 'British Indian Ocean Territory',
73
+ vg: 'British Virgin Islands',
74
+ bn: 'Brunei',
75
+ bg: 'Bulgaria',
76
+ bf: 'Burkina Faso',
77
+ mm: 'Burma',
78
+ bi: 'Burundi',
79
+ kh: 'Cambodia',
80
+ cm: 'Cameroon',
81
+ ca: 'Canada',
82
+ cv: 'Cape Verde',
83
+ ky: 'Cayman Islands',
84
+ cf: 'Central African Republic',
85
+ td: 'Chad',
86
+ cl: 'Chile',
87
+ cn: 'China',
88
+ cx: 'Christmas Island',
89
+ cc: 'Cocos (Keeling) Islands',
90
+ co: 'Colombia',
91
+ cd: 'Congo, Democratic Republic of the',
92
+ cg: 'Congo, Republic of the',
93
+ ck: 'Cook Islands',
94
+ cr: 'Costa Rica',
95
+ ci: "Cote d'Ivoire",
96
+ hr: 'Croatia',
97
+ cu: 'Cuba',
98
+ cy: 'Cyprus',
99
+ cz: 'Czech Republic',
100
+ dk: 'Denmark',
101
+ dj: 'Djibouti',
102
+ dm: 'Dominica',
103
+ do: 'Dominican Republic',
104
+ ec: 'Ecuador',
105
+ eg: 'Egypt',
106
+ sv: 'El Salvador',
107
+ gq: 'Equatorial Guinea',
108
+ er: 'Eritrea',
109
+ ee: 'Estonia',
110
+ et: 'Ethiopia',
111
+ fk: 'Falkland Islands (Islas Malvinas)',
112
+ fo: 'Faroe Islands',
113
+ fj: 'Fiji',
114
+ fi: 'Finland',
115
+ fr: 'France',
116
+ gf: 'French Guiana',
117
+ pf: 'French Polynesia',
118
+ tf: 'French Southern and Antarctic Lands',
119
+ ga: 'Gabon',
120
+ gm: 'Gambia, The',
121
+ ge: 'Georgia',
122
+ de: 'Germany',
123
+ gh: 'Ghana',
124
+ gi: 'Gibraltar',
125
+ gr: 'Greece',
126
+ gl: 'Greenland',
127
+ gd: 'Grenada',
128
+ gp: 'Guadeloupe',
129
+ gu: 'Guam',
130
+ gt: 'Guatemala',
131
+ gg: 'Guernsey',
132
+ gn: 'Guinea',
133
+ gw: 'Guinea-Bissau',
134
+ gy: 'Guyana',
135
+ ht: 'Haiti',
136
+ hm: 'Heard Island and McDonald Islands',
137
+ va: 'Holy See (Vatican City)',
138
+ hn: 'Honduras',
139
+ hk: 'Hong Kong',
140
+ hu: 'Hungary',
141
+ is: 'Iceland',
142
+ in: 'India',
143
+ id: 'Indonesia',
144
+ ir: 'Iran',
145
+ iq: 'Iraq',
146
+ ie: 'Ireland',
147
+ im: 'Isle of Man',
148
+ il: 'Israel',
149
+ it: 'Italy',
150
+ jm: 'Jamaica',
151
+ jp: 'Japan',
152
+ je: 'Jersey',
153
+ jo: 'Jordan',
154
+ kz: 'Kazakhstan',
155
+ ke: 'Kenya',
156
+ ki: 'Kiribati',
157
+ kp: 'Korea, North',
158
+ kr: 'Korea, South',
159
+ kw: 'Kuwait',
160
+ kg: 'Kyrgyzstan',
161
+ la: 'Laos',
162
+ lv: 'Latvia',
163
+ lb: 'Lebanon',
164
+ ls: 'Lesotho',
165
+ lr: 'Liberia',
166
+ ly: 'Libya',
167
+ li: 'Liechtenstein',
168
+ lt: 'Lithuania',
169
+ lu: 'Luxembourg',
170
+ mo: 'Macau',
171
+ mk: 'Macedonia',
172
+ mg: 'Madagascar',
173
+ mw: 'Malawi',
174
+ my: 'Malaysia',
175
+ mv: 'Maldives',
176
+ ml: 'Mali',
177
+ mt: 'Malta',
178
+ mh: 'Marshall Islands',
179
+ mq: 'Martinique',
180
+ mr: 'Mauritania',
181
+ mu: 'Mauritius',
182
+ yt: 'Mayotte',
183
+ mx: 'Mexico',
184
+ fm: 'Micronesia, Federated States of',
185
+ md: 'Moldova',
186
+ mc: 'Monaco',
187
+ mn: 'Mongolia',
188
+ ms: 'Montserrat',
189
+ ma: 'Morocco',
190
+ mz: 'Mozambique',
191
+ na: 'Namibia',
192
+ nr: 'Nauru',
193
+ np: 'Nepal',
194
+ nl: 'Netherlands',
195
+ an: 'Netherlands Antilles',
196
+ nc: 'New Caledonia',
197
+ nz: 'New Zealand',
198
+ ni: 'Nicaragua',
199
+ ne: 'Niger',
200
+ ng: 'Nigeria',
201
+ nu: 'Niue',
202
+ nf: 'Norfolk Island',
203
+ mp: 'Northern Mariana Islands',
204
+ no: 'Norway',
205
+ om: 'Oman',
206
+ pk: 'Pakistan',
207
+ pw: 'Palau',
208
+ pa: 'Panama',
209
+ pg: 'Papua New Guinea',
210
+ py: 'Paraguay',
211
+ pe: 'Peru',
212
+ ph: 'Philippines',
213
+ pn: 'Pitcairn Islands',
214
+ pl: 'Poland',
215
+ pt: 'Portugal',
216
+ pr: 'Puerto Rico',
217
+ qa: 'Qatar',
218
+ re: 'Reunion',
219
+ ro: 'Romania',
220
+ ru: 'Russia',
221
+ rw: 'Rwanda',
222
+ sh: 'Saint Helena',
223
+ kn: 'Saint Kitts and Nevis',
224
+ lc: 'Saint Lucia',
225
+ pm: 'Saint Pierre and Miquelon',
226
+ vc: 'Saint Vincent and the Grenadines',
227
+ ws: 'Samoa',
228
+ sm: 'San Marino',
229
+ st: 'Sao Tome and Principe',
230
+ sa: 'Saudi Arabia',
231
+ sn: 'Senegal',
232
+ cs: 'Serbia and Montenegro',
233
+ sc: 'Seychelles',
234
+ sl: 'Sierra Leone',
235
+ sg: 'Singapore',
236
+ sk: 'Slovakia',
237
+ si: 'Slovenia',
238
+ sb: 'Solomon Islands',
239
+ so: 'Somalia',
240
+ za: 'South Africa',
241
+ gs: 'South Georgia and the South Sandwich Islands',
242
+ es: 'Spain',
243
+ lk: 'Sri Lanka',
244
+ sd: 'Sudan',
245
+ sr: 'Suriname',
246
+ sj: 'Svalbard',
247
+ sz: 'Swaziland',
248
+ se: 'Sweden',
249
+ ch: 'Switzerland',
250
+ sy: 'Syria',
251
+ tw: 'Taiwan',
252
+ tj: 'Tajikistan',
253
+ tz: 'Tanzania',
254
+ th: 'Thailand',
255
+ tp: 'Timor-Leste',
256
+ tg: 'Togo',
257
+ tk: 'Tokelau',
258
+ to: 'Tonga',
259
+ tt: 'Trinidad and Tobago',
260
+ tn: 'Tunisia',
261
+ tr: 'Turkey',
262
+ tm: 'Turkmenistan',
263
+ tc: 'Turks and Caicos Islands',
264
+ tv: 'Tuvalu',
265
+ ug: 'Uganda',
266
+ ua: 'Ukraine',
267
+ ae: 'United Arab Emirates',
268
+ gb: 'United Kingdom',
269
+ us: 'United States',
270
+ uy: 'Uruguay',
271
+ uz: 'Uzbekistan',
272
+ vu: 'Vanuatu',
273
+ ve: 'Venezuela',
274
+ vn: 'Vietnam',
275
+ vi: 'Virgin Islands',
276
+ wf: 'Wallis and Futuna',
277
+ ps: 'West Bank',
278
+ eh: 'Western Sahara',
279
+ ye: 'Yemen',
280
+ zm: 'Zambia',
281
+ zw: 'Zimbabwe'
282
+ }
283
+ end
284
+ end
@@ -0,0 +1,433 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "ige_isb_api"
5
+ require "ige_isb_api/constants"
6
+ require 'nokogiri'
7
+
8
+ # Email from iSB on 2 Sept 2013 says
9
+ # please use the following parameters:
10
+ # Loginc = XX,player_ID (Where XX is your licensee ID)
11
+ # Passc = random string
12
+ # also can ignore the 'file' tag in the games_info.xml file.
13
+ # and confirmed that :swf_revision will always be an integer.
14
+ # ignore language code
15
+ # ignore <fun> tag in game info.
16
+
17
+ # email from ISB on 2 Oct 2013
18
+ # We will use a new parameter within pass strings something called “hostID”.
19
+ # However being a string, we need to agree over an internal naming convention to know which URL corresponds to the string used.
20
+ # For example: if hostID is “1”, the url for end of session json return is https://api.luckygoldfish.com/isb/end-session.
21
+ # The url for returning the json doesn’t needs to point to a domain whitelisted in these case as the initiation is made from our side (have to double check it though)
22
+ # By these, we needed to change the structure for login and pass while calling our games in real mode.
23
+ # Please use the following:
24
+ #
25
+ # Flash:
26
+ # loginc: 54,playerID
27
+ # passc: requestID,token,hostID
28
+ #
29
+ # html5
30
+ # name: 54,playerID
31
+ # password: requestID,token,hostID
32
+ #
33
+ # where:
34
+ # playerID - unique player identification
35
+ # requestID - has to be unique for every new game session
36
+ # token - SHA256 digest of our 'SECRETKEY' + 'IDREQUEST' which we will use to authenticate the incoming info.
37
+ # hostID - the host id (configured as INT) assigned to the real URL on our site (url to IGE api will be changeable and will be depend on the hostID parameter).
38
+ # see https://github.com/Interactive-Gaming-Entertainment/ISBAPI/issues/5
39
+ # this has changed now as follows:
40
+ # Flash:
41
+ # loginc: 54,player_login
42
+ # passc: requestID,token,hostID
43
+ #
44
+ # html5
45
+ # name: 54,player_login
46
+ # password: requestID,token,hostID
47
+
48
+ module IGE_ISB_API
49
+ class GameInfo
50
+ attr_accessor :mode, # :fun or :real
51
+ :url, :swf_revision, :host, :use_custom_loader, :custom_loader,
52
+ :preloader # all the rest of the info is the same or ignored
53
+
54
+ def initialize(mode = :fun)
55
+ raise ArgumentError, "Invalid mode #{mode}, should be :fun or :real" unless mode == :fun || mode == :real
56
+ @mode = mode
57
+ end
58
+
59
+ def use_custom_loader?
60
+ return @use_custom_loader if (defined? @use_custom_loader && !@use_custom_loader.nil?)
61
+ return false
62
+ end
63
+
64
+ end
65
+
66
+ class Game
67
+ attr_accessor :id, :name, :description, :images, :is_fun_active, :is_real_active,
68
+ :coin_values, :identifier, :category, :main_category, :skin,
69
+ :coin, :coin_min, :coin_max, :wmode, :casino, :use_preloader, # use preloader is the same for both fun and real modes.
70
+ :game_type, :restricted_countries, :custom_backgrounds,
71
+ :info, :translated, :language
72
+
73
+ # 'tra', 'tfa', and 'ta' are deprecated fields and should be ignored.
74
+
75
+ def initialize()
76
+ @info = {}
77
+ end
78
+
79
+ def has_info?(mode)
80
+ return !self.info[mode].nil?
81
+ end
82
+
83
+ def get_info(mode)
84
+ the_info = self.info[mode]
85
+ raise ArgumentError, "No Info associated with mode #{mode}" unless self.has_info?(mode)
86
+ return the_info
87
+ end
88
+
89
+ def use_preloader?
90
+ return @use_preloader if (defined? @use_preloader && !@use_preloader.nil?)
91
+ return false
92
+ end
93
+
94
+ def game_html5_url(mode)
95
+ the_info = self.get_info(mode)
96
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}html/#{self.identifier}/#{self.identifier}_r#{the_info.swf_revision}/#{self.identifier}.html"
97
+ end
98
+
99
+ def game_swf_url(mode)
100
+ check_mode!(mode)
101
+ the_info = self.get_info(mode)
102
+ if the_info.use_custom_loader?
103
+ raise RuntimeError, "Custom Loader not specified" if the_info.custom_loader.nil? || the_info.custom_loader.empty?
104
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}#{self.main_category}/#{the_info.custom_loader}"
105
+ end
106
+ if self.use_preloader?
107
+ raise RuntimeError, "Preloader not specified" if the_info.preloader.nil? || the_info.preloader.empty?
108
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}#{self.main_category}/#{the_info.preloader}"
109
+ end
110
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}#{self.main_category}/#{game_swf_path(mode)}"
111
+ end
112
+
113
+ # must not start with a '/'
114
+ # With custom loader, you load the custom loader swf, and the gameurl flash var has to be absolute url
115
+ # With preloader, you load the preloader swf, and the gameurl flash var has to be absolute url
116
+ # Without custom loader or preloader, you have to load the main game swf, and the gameurl remains relative url
117
+ def game_swf_path(mode)
118
+ check_mode!(mode)
119
+ raise RuntimeError, "Game Identifier Unknown" if self.identifier.nil? || self.identifier.empty?
120
+ raise RuntimeError, "Game Server Unknown" if IGE_ISB_API::Constants::SERVER[mode].nil? || IGE_ISB_API::Constants::SERVER[mode].empty?
121
+ the_info = self.get_info(mode)
122
+ raise RuntimeError, "SWF Revision not specified" if the_info.swf_revision.nil?
123
+ if the_info.use_custom_loader? || self.use_preloader?
124
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}#{self.main_category}/swf_files/#{self.identifier}_r#{the_info.swf_revision}.swf"
125
+ end
126
+ return "swf_files/#{self.identifier}_r#{the_info.swf_revision}.swf"
127
+ end
128
+
129
+ def game_info_url(mode)
130
+ check_mode!(mode)
131
+ raise RuntimeError, "Game Indentifier Unknown" if self.identifier.nil? || self.identifier.empty?
132
+ raise RuntimeError, "Game Server Unknown" if IGE_ISB_API::Constants::SERVER[mode].nil? || IGE_ISB_API::Constants::SERVER[mode].empty?
133
+ return "#{IGE_ISB_API::Constants::SERVER[mode]}xml_game_info/#{self.identifier}_info.xml"
134
+ end
135
+
136
+ def load_info(some_xml)
137
+ doc = Nokogiri::XML(some_xml)
138
+ gn = doc.xpath("//game").first
139
+ @skin = gn.xpath('skin_id').first.text.to_i
140
+ @coin = gn.xpath('coin').first.text.to_f
141
+ @coin_min = gn.xpath('coin_min').first.text.to_f
142
+ @coin_max = gn.xpath('coin_max').first.text.to_f
143
+ @casino = gn.xpath('casino').first.text
144
+ @game_type = gn.xpath('type').first.text
145
+ @wmode = gn.xpath('wmode').first.text
146
+ # mode specific info
147
+ fun = gn.xpath('fun').first.text == '1'
148
+ mode = fun ? :fun : :real
149
+ the_info = self.has_info?(mode) ? self.get_info(mode) : GameInfo.new(mode)
150
+ the_info.url = gn.xpath('url').first.text
151
+ the_info.swf_revision = gn.xpath('swf_revision').first.text.to_i
152
+ the_info.host = gn.xpath('host').first.text
153
+ the_info.use_custom_loader = (gn.xpath('use_custom_loader').first.text == '1')
154
+ the_info.custom_loader = gn.xpath('custom_loader').first.text
155
+ the_info.preloader = gn.xpath('prelfile').first.text if self.use_preloader?
156
+ self.info[mode] = the_info
157
+ return [] unless ((self.fun? && self.has_info?(:fun)) && (self.real? && self.has_info?(:real)))
158
+ return any_errors?
159
+ end
160
+
161
+ def fun?
162
+ return @is_fun_active
163
+ end
164
+
165
+ def real?
166
+ return @is_real_active
167
+ end
168
+
169
+ def translated?
170
+ return @translated
171
+ end
172
+
173
+ # Image Sizes
174
+ # simg – preview of the game, the size of the preview is 160px – 60px
175
+ # limg – preview of the game, the size of the preview is 197px - 88px
176
+ # html_img – preview of the game, the size of the preview is 120px -158px
177
+ # img_v2 – preview of the game, the size of the preview is 240px – 135px
178
+ def main_image
179
+ images = self.images
180
+ image = ''
181
+ image = images[:v2] unless images[:v2].nil? || images[:v2].empty?
182
+ image = images[:l] if image.empty? && !(images[:l].nil? || images[:l].empty?)
183
+ image = images[:html] if image.empty? && !(images[:html].nil? || images[:html].empty?)
184
+ return image
185
+ end
186
+
187
+ def thumb_image
188
+ images = self.images
189
+ thumb = ''
190
+ thumb = images[:s] unless images[:s].nil? || images[:s].empty?
191
+ thumb = main_image if thumb.empty?
192
+ return thumb
193
+ end
194
+
195
+ def warnings
196
+ warnings = []
197
+ warnings << {game: self, message: "Missing description, defaulting to ''."} if self.description.nil? || self.description.empty?
198
+ images = self.images
199
+ warnings << {game: self, message: "Missing ':l' image in #{images.inspect}"} if images[:l].nil? || images[:l].empty?
200
+ warnings << {game: self, message: "Missing ':s' image in #{images.inspect}"} if images[:s].nil? || images[:s].empty?
201
+ warnings << {game: self, message: "Missing ':html' image in #{images.inspect}"} if images[:html].nil? || images[:html].empty?
202
+ # => almost all games are missing the :v2 image completely so only warn if empty, not nil.
203
+ warnings << {game: self, message: "Missing :v2 image in #{images.inspect}"} if !images[:v2].nil? && images[:v2].empty?
204
+ return warnings
205
+ end
206
+
207
+ def self.from_node(node, cat, lang)
208
+ g = Game.new
209
+ g.category = cat
210
+ g.id = node['id'].to_i
211
+ g.name = node['n']
212
+ g.images = {
213
+ s: node['simg'], # preview of the game, the size of the preview is 160px – 60px. Sometimes missing.
214
+ l: node['limg'], # preview of the game, the size of the preview is 197px - 88px.
215
+ html: node['html_img'], # preview of the game, the size of the preview is 120px -158px.
216
+ v2: node['img_v2'] # preview of the game, the size of the preview is 240px – 135px. This is typically nil
217
+ }
218
+ g.is_fun_active = (node['fa'] == '1')
219
+ g.is_real_active = (node['ra'] == '1')
220
+ g.use_preloader = (node['p'] == '1')
221
+ g.coin_values = node['c'].split('; ').map {|s| s.to_f}
222
+ g.restricted_countries = node['rc'].split(', ')
223
+ g.identifier = node['i']
224
+ g.description = node.xpath('d').first.text
225
+ mcn = node.xpath('main_cat').first
226
+ g.main_category = mcn.text unless mcn.nil?
227
+ g.translated = (node['translated'] == '1')
228
+ g.language = g.translated? ? lang : IGE_ISB_API::Constants::DEFAULT_LANGUAGE
229
+ return g
230
+ end
231
+
232
+ # request_id must be unique for each request
233
+ def self.encode_password(idrequest)
234
+ raise ArgumentError, "You must supply a unique :idrequest" if idrequest.nil?
235
+ # password: idrequest,token,hostID
236
+ # token - SHA256 digest of our 'SECRETKEY' + 'idrequest' which we will use to authenticate the incoming info.
237
+ token = (Digest::SHA256.new << "#{IGE_ISB_API::Constants::SECRET_KEY}#{idrequest}").to_s
238
+ return "#{idrequest},#{token},#{IGE_ISB_API::Constants::CALLBACK_ID}"
239
+ end
240
+
241
+ def self.encode_login(player_login)
242
+ raise ArgumentError, "You must supply a valid :player_login" if player_login.nil?
243
+ return "#{IGE_ISB_API::Constants::LICENSEE_ID},#{player_login}"
244
+ end
245
+
246
+ def self.game_launcher_url(opts = {})
247
+ options = {
248
+ currency: IGE_ISB_API::Constants::DEFAULT_CURRENCY_CODE
249
+ }.merge(opts)
250
+ password = options[:fun] ? 'fun' : Game.encode_password(options[:idrequest])
251
+ name = options[:fun] ? 'fun' : Game.encode_login(options[:player_login])
252
+ vars = [
253
+ "name=#{name}",
254
+ "password=#{password}",
255
+ "lang=#{options[:language]}",
256
+ "currency=#{options[:currency]}",
257
+ "funmode=#{options[:fun].to_s}"
258
+ ].join('&')
259
+ return "#{options[:game_html5_url]}?#{vars}"
260
+ end
261
+
262
+ # Flash:
263
+ # loginc: 54,playerID
264
+ # passc: requestID,token,hostID
265
+ def self.embed_swfobject(opts = {})
266
+ options = {
267
+ width: '100%',
268
+ height: '100%',
269
+ container: 'game',
270
+ currency: IGE_ISB_API::Constants::DEFAULT_CURRENCY_CODE,
271
+ gm_api: 1 # see https://github.com/Interactive-Gaming-Entertainment/ISBAPI/issues/10
272
+
273
+ }.merge(opts)
274
+ mode = options[:fun] ? :fun : :real
275
+ password = options[:fun] ? 'fun' : Game.encode_password(options[:idrequest])
276
+ name = options[:fun] ? 'fun' : Game.encode_login(options[:player_login])
277
+ vars = [
278
+ "gamename: '#{options[:name]}'",
279
+ "gameurl: '#{options[:game_swf_path]}'",
280
+ "gameid: '#{options[:identifier]}'",
281
+ "skin_id: '#{options[:skin]}'",
282
+ "hostname: '#{options[:host]}'",
283
+ "loginc: '#{name}'",
284
+ "passc: '#{password}'",
285
+ "cur: '#{options[:currency]}'",
286
+ "forfun: #{options[:fun] ? 1 : 0}",
287
+ "langue: #{IGE_ISB_API::Constants::LANGUAGES[options[:language].to_sym]}",
288
+ "casino: '#{options[:casino]}'",
289
+ "coinval: '#{options[:coin_min]}'",
290
+ "table: 0",
291
+ "tokenuse: 0",
292
+ "realc: 60",
293
+ "gmAPI: #{options[:gm_api]}",
294
+ "settingsXMLProvider: '#{IGE_ISB_API::Constants::SERVER[mode]}#{options[:main_category]}/xml/#{options[:language]}/#{options[:identifier]}_settings_#{mode.to_s}.xml'",
295
+ "translationXMLProvider: '#{IGE_ISB_API::Constants::SERVER[mode]}#{options[:main_category]}/xml/#{options[:language]}/#{options[:identifier]}_translations.xml'"
296
+ ].join(', ')
297
+ pars = [
298
+ "align: 'middle'",
299
+ "allowScriptAccess: 'always'",
300
+ "allowFullScreen: 'true'",
301
+ "quality: 'high'",
302
+ "bgcolor: '#{options[:colour]}'",
303
+ "wmode: '#{options[:wmode]}'"
304
+ ].join(', ')
305
+ result = "<script>var vars = {#{vars}}, params = {#{pars}}, swfUrl = '#{options[:game_swf_url]}'; "
306
+ result << "swfobject.embedSWF(swfUrl, '#{options[:container]}', '#{options[:width]}', '#{options[:height]}', '11.0.0', null, vars, params);</script>"
307
+ return result
308
+ end
309
+
310
+ # settingsXMLProvider - the location of the game's settings xml file (/[main_cat]/xml/[language identifier]/[game identifier]_settings_[fun/real].xml)
311
+ def self.embed_game_html(opts = {})
312
+ options = {
313
+ width: '100%',
314
+ height: '100%',
315
+ currency: IGE_ISB_API::Constants::DEFAULT_CURRENCY_CODE,
316
+ gm_api: 1 # see https://github.com/Interactive-Gaming-Entertainment/ISBAPI/issues/10
317
+ }.merge(opts)
318
+ mode = options[:fun] ? :fun : :real
319
+ password = options[:fun] ? 'fun' : Game.encode_password(options[:idrequest])
320
+ name = options[:fun] ? 'fun' : Game.encode_login(options[:player_login])
321
+ flashvars = [
322
+ "gamename=#{options[:name]}",
323
+ "gameurl=#{options[:game_swf_path]}",
324
+ "gameid=#{options[:identifier]}",
325
+ "skin_id=#{options[:skin]}",
326
+ "hostname=#{options[:host]}",
327
+ "loginc=#{name}",
328
+ "passc=#{password}",
329
+ "cur=#{options[:currency]}",
330
+ "forfun=#{options[:fun] ? 1 : 0}",
331
+ "langue=#{IGE_ISB_API::Constants::LANGUAGES[options[:language].to_sym]}",
332
+ "casino=#{options[:casino]}",
333
+ "coinval=#{options[:coin_min]}",
334
+ "table=0",
335
+ "tokenuse=0",
336
+ "realc=60",
337
+ "gmAPI=#{options[:gm_api]}",
338
+ "settingsXMLProvider=#{IGE_ISB_API::Constants::SERVER[mode]}#{options[:main_category]}/xml/#{options[:language]}/#{options[:identifier]}_settings_#{mode.to_s}.xml",
339
+ "translationXMLProvider=#{IGE_ISB_API::Constants::SERVER[mode]}#{options[:main_category]}/xml/#{options[:language]}/#{options[:identifier]}_translations.xml"
340
+ ].join('&')
341
+ result = "<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' codebase='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0' width='#{options[:width]}' height='#{options[:height]}' id='#{options[:identifier]}'>"
342
+ result << "<object type='application/x-shockwave-flash' data='#{options[:game_swf_url]}' width='#{options[:width]}' height='#{options[:height]}'>"
343
+ result << "<param name='movie' value='#{options[:game_swf_url]}' />"
344
+ result << "<param name='flashvars' value='#{flashvars}' />"
345
+ result << "<param name='align' value='middle' />"
346
+ result << "<param name='allowFullScreen' value='true' />"
347
+ result << "<param name='allowScriptAccess' value='always' />"
348
+ result << "<param name='quality' value='high' />"
349
+ result << "<param name='bgcolor' value='#{options[:colour]}' />"
350
+ result << "<param name='wmode' value='#{options[:wmode]}' />"
351
+ result << "<param name='base' value='.' />"
352
+ result << "</object></object>"
353
+ return result
354
+ end
355
+
356
+ private
357
+
358
+ def check_mode!(mode)
359
+ raise ArgumentError, "Invalid mode #{mode}, should be :fun or :real" unless mode == :fun || mode == :real
360
+ raise ArgumentError, "Invalid mode #{mode}, :fun not allowed for this game." if mode == :fun && !self.fun?
361
+ raise ArgumentError, "Invalid mode #{mode}, :real not allowed for this game." if mode == :real && !self.real?
362
+ end
363
+
364
+ def any_errors?
365
+ errors = []
366
+ errors << {game: self, message: "Missing casino"} if self.casino.nil? || self.casino.empty?
367
+ errors << {game: self, message: "Missing identifier"} if self.identifier.nil? || self.identifier.empty?
368
+ errors << {game: self, message: "Missing game_swf_path(:fun)"} if self.fun? && (self.game_swf_path(:fun).nil? || self.game_swf_path(:fun).empty?)
369
+ errors << {game: self, message: "Missing game_swf_url(:fun)"} if self.fun? && (self.game_swf_url(:fun).nil? || self.game_swf_url(:fun).empty?)
370
+ errors << {game: self, message: "Missing game_swf_path(:real)"} if self.real? && (self.game_swf_path(:real).nil? || self.game_swf_path(:real).empty?)
371
+ errors << {game: self, message: "Missing game_swf_url(:real)"} if self.real? && (self.game_swf_url(:real).nil? || self.game_swf_url(:real).empty?)
372
+ errors << {game: self, message: "Missing main_category"} if self.game_type === 'flash' && (self.main_category.nil? || self.main_category.empty?)
373
+ errors << {game: self, message: "Missing wmode"} if self.wmode.nil? || self.wmode.empty?
374
+ errors << {game: self, message: "Missing type"} if self.game_type.nil? || self.game_type.empty?
375
+ errors << {game: self, message: "Invalid game type"} unless IGE_ISB_API::Constants::ALLOWED_GAME_TYPES.include?(self.game_type)
376
+ errors << {game: self, message: "Missing coin_min: coin_values are #{self.coin_values.inspect} coin: #{self.coin} max: #{self.coin_max}"} if self.coin_min.nil? || self.coin_min <= 0.0
377
+ errors << {game: self, message: "Unable to determine main image"} if self.main_image.empty?
378
+ errors << {game: self, message: "Unable to determine thumbnail image"} if self.thumb_image.empty?
379
+ errors << {game: self, message: "Invalid wmode"} unless IGE_ISB_API::Constants::ALLOWED_MODES.include?(self.wmode)
380
+ errors << {game: self, message: "Neither fun, nor real"} if !(self.fun? || self.real?)
381
+ errors << {game: self, message: "Missing fun game info"} if (self.fun? && !self.has_info?(:fun))
382
+ errors << {game: self, message: "Missing real game info"} if (self.real? && !self.has_info?(:real))
383
+ return errors
384
+ end
385
+ end
386
+
387
+ class Category
388
+ attr_accessor :parent, :children, :id, :name, :description, :games, :icon, :language
389
+
390
+ def initialize()
391
+ @children = []
392
+ @games = []
393
+ @language = IGE_ISB_API::Constants::DEFAULT_LANGUAGE
394
+ end
395
+
396
+ def self.from_node(node, opts = {})
397
+ c = Category.new
398
+ c.id = node['id'].to_i
399
+ c.icon = node['i']
400
+ c.name = node['n']
401
+ @language = opts[:language] unless opts[:language].nil?
402
+ c.description = node['d']
403
+ node.xpath("c").each do |subcat|
404
+ # puts "found subcat #{subcat['n']}"
405
+ Category.from_node subcat, parent: c, language: @language
406
+ end
407
+ node.xpath("g").each do |game|
408
+ c.games << Game.from_node(game, c, @language)
409
+ end
410
+
411
+ c.parent = opts[:parent]
412
+ c.parent.children << c unless c.parent.nil?
413
+ return c
414
+ end
415
+ end
416
+
417
+ class Games
418
+ attr_accessor :images, :categories
419
+
420
+ def initialize()
421
+ @categories = []
422
+ @games = []
423
+ end
424
+
425
+ def load_from_xml(the_xml, language = IGE_ISB_API::Constants::DEFAULT_LANGUAGE)
426
+ doc = Nokogiri::XML(the_xml)
427
+ @images = doc.xpath("//images").first['url']
428
+ doc.xpath("//games/c").each do |cat_node|
429
+ @categories << Category.from_node(cat_node, language: language)
430
+ end
431
+ end
432
+ end
433
+ end