ige_isb_api 1.0.0

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.
@@ -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