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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +33 -0
- data/LICENSE +20 -0
- data/README.md +237 -0
- data/ige_isb_api.gemspec +29 -0
- data/lib/ige_isb_api.rb +49 -0
- data/lib/ige_isb_api/api.rb +251 -0
- data/lib/ige_isb_api/bonus.rb +249 -0
- data/lib/ige_isb_api/bonus_api.rb +125 -0
- data/lib/ige_isb_api/callback.rb +83 -0
- data/lib/ige_isb_api/constants.rb +284 -0
- data/lib/ige_isb_api/games.rb +433 -0
- data/lib/ige_isb_api/request.rb +164 -0
- data/lib/ige_isb_api/user_api.rb +251 -0
- data/lib/ige_isb_api/validation.rb +130 -0
- data/lib/ige_isb_api/version.rb +6 -0
- metadata +130 -0
@@ -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
|