2.1.1 • Published 5 years ago
@articulatesydney/gmservice v2.1.1
GM-SERVICE
About
本JS库目的在于管理游戏列表 主要特性有 1. 提供常用的异步数据支持 2. 封装常用的展示游戏列表的方式 3. 基于rxjs 非常extendable
GMService基于rxjs,数据交互操作全部为异步实现。 获取数据的接口的使用方式基本上都是
instance.someapi.subscribe(data => {
//...
})
如何使用
安装
npm install --save @articulatesydney/gmservice
或者直接在html中加入
<script src="....bundle.js"></script>
测试
npm run test
Build
npm run build
使用
- 设置参数并初始化gmservice 得到gmservice的instance
var instance = new gmservice({
games: GAMELISR,
cache: 10000,
launchGame: function (game, { resolve }) {
// ... resolve(xxxx)
}
})
从instance提供的api中获取数据
获取provider
instance.providers.subscribe(providers => {
console.log(providers);
})
获取完整游戏列表
instance.list(games => {
console.log(games);
})
Tips
- 请避免使用fat arrow functions(transform函数以及process函数除外)
- 在gallery中使用transform.order的时候, GALLERY_FORMAT.PROVIDERS_OF_CATEGORIES模式中将会先调用category的order方法;对于每个category内部的providers的顺序会由groups order决定(example请见测试用例以及example lobby.html)
Configuration
gmservice内部默认认为传入的游戏列表为标准格式, 可以在games中直接传入标准格式的游戏列表;也可以使用rawProcess函数进行
标准格式包含以下property
- cn_name: string
- en_name: string
- image: string
- code: string
- provider: string
- category:string
- types: object - 这个设计是为了实现一个游戏可以同时有多个类型的需求
{
slot: true,
jackpot: true,
asian: true
}
- extra: object - 用于记录额外的数据:可能在自定义的搜索中使用
配置列表
var instance = new gmservice({
/**
* 1. games
* - 如果网页版游戏列表与h5有出入, 具体如何加载合适的游戏列表需要使用者自己处理
*
* format:
* - array of games OR
* - function
* 主要用于异步加载游戏列表:在load完成后调用resolve
*
*/
games: gamelist,
games: (resolve) => {
fetch('/gamelist')
.then(d => d.json())
.then(games => {
resolve(games)
})
/*
games: (resolve) => resolve(gamelist)
与
games: gamelist
等价
*/
}
/**
* 2. providers
* - 在游戏列表上筛选特定平台的游戏
* - 主要用于在cache了完整的游戏列表的环境中 只向玩家显示特定平台的相关游戏数据
*
* **如果游戏列表中本来就没有给定平台的游戏 也不会造成多余的显示
*
* providers format
* - array of provider names
* - function
*
*/
providers: ['PNG', 'MG']
providers: (resolve) => {
fetch('/valid_providers')
.then(d => d.json())
.then(providers => resolve(providers));
},
/**
* 3. categories
* - 在游戏列表上筛选特定类型的游戏
* - 主要用于在cache了完整的游戏列表的环境中 只向玩家显示特定类型的相关游戏数据
*
* **如果游戏列表中本来就没有给定平台的游戏 也不会造成多余的显示
*
* categories format
* - array of provider names
* - function
*
*/
categories: ['slots', 'live']
categories: (resolve) => {
fetch('/valid_categories')
.then(d => d.json())
.then(categories => resolve(categories));
},
/**
* 4. filter - function
* - 在游戏列表上自定义筛选游戏
* - 主要用于根据特殊条件过滤游戏: 比如说 不希望玩家看到 rtp超过95%的游戏;
* 或者不希望玩家看到PNG的带有slot字样的游戏
*
* filter format
* - function
*
*/
filter: (game) => {
return game.extra.rtp < 0.95;
// return game.provider !== 'PNG' || game.en_name.search('slots') < 0
}
/**
* 5. rawProcess - function
* - 用于对游戏列表进行预处理 以转换至标准格式
*
*/
rawProcess: function (g) {
return Object.assign(g, {
code: g.game_code,
cn_name: g.name,
en_name: g.english_name,
types: (g.game_type || '').split('_').reduce((prev, t) => ({ ...prev, [t]: true }), {}),
extra: {}
})
},
/**
* 6. injectUpdates - function
*
* function injectUpdates({gamelist, cache_updated_at, cache_expire_at}, resolveFn): void
*
* - 检查游戏列表是否有更新:如果有的话将新的数据纳入系统
* - 新的数据不会被rawProcess处理(因为可能还有updated/removed games的情况,injectUpdates用来处理一些非常灵活的情形)
* - 如果同时还开启了cache 新的数据以及当前的timestamp将被写入cache;做为下次调用时的cache_updated_at
*
* - 一个特别的使用例子:在lobby上使用时 推荐cache设置为999999999: 即使有cache也会检查更新,而且更新的timestamp会被写在cache中
*
*/
injectUpdates: ({gamelist, cache_updated_at, cache_expire_at}, resolve) => {
fetch(`/new_games?updated_at=${cache_updated_at}`)
.then(d => d.json())
.then((newgames = []) => {
resolve([...gamelist, newgames]);
})
},
/**
* 7. cache -
* - 保存处理完成之后的游戏列表
* - 如果有合法的cached游戏列表存在的话 将不会使用games参数传入的游戏列表或者function
* - 网页版与h5版的游戏列表将分别cache
* -
*
* format:
* - number - 浏览器中使用localStorage: 在浏览器中保存
* - string: 'session' - 浏览器中使用 sessionStorage: 本次tab session中cache游戏列表
*
*/
cache: 1000 * 60 * 60 * 24 * 7, // 1 week
cache: 'session',
/**
* 8. recommends:
* - 接受的数据为一个array:将index=0的数据视为全局推荐游戏列表
* index=1的数据视为对应agent的推荐游戏列表
* - 为了解决inconsistancy 推荐游戏列表实际上提供一些标准 还是会从gamelist中去匹配合适的数据;每个object只需要但必须要提供provider,category以及code
*
* format:
* - array of gamelist arrays [gamelist1, gamelist2]
* - function
*
*/
recommends: [general_recommends, operator_recommends],
recommends: (resolve) => {
fetch('/some-recommends?playerid=111')
.then(d => d.json())
.then(data => resolve(data))
},
/**
* 9. recommendProcess - function
* - 类似于 rawProcess: 将推荐游戏列表的数据处理成标准状态
*
*/
recommendProcess: function (g) {
return ({
category: g.category,
provider: g.provider,
code: g.code,
extra: {
priority: g.priority,
}
});
},
/**
* 10. recommendStrategy - function
* - 接受一个第一个元素为全局推荐游戏列表、第二个元素为agent推荐游戏列表的array为参数
* - 返回一个推荐游戏array
* - strategy将在 recommendProcess之前调用:数据尚未被处理
* - 默认stategy为 general.concat(operator); 主要使用方式包括 将operator推荐游戏前置 或者将某一类型的推荐游戏前置
*
*/
recommendStrategy: ([general, operator]) =>
general.filter(g => g.provider == 'PNG').concat(operator)
/**
* 11. launchGame - function
* - 打开游戏请求的处理函数
* - 在instance上使用getLaunchUrl时触发
* resolve and launchGame get success status and data
* reject and launchGame get error status and data
*
**/
launchGame: (game, { resolve, reject }) => {
const {provider, code} = game;
fetch(`/open-game?provider=${provider}&code=${code}`)
.then(response => {
if (provider == 'PNG') resolve('....' + response);
else resolve(response);
})
.catch(error => {
reject(error);
})
},
/**
* 12. getBalance - function
* - 获取平台余额的处理函数
* - 在instance上使用 getBalance 时触发
* resolve and getBalance get success status and data
* reject and getBalance get error status and data
*
**/
getBalance: (provider, { resolve, reject }) => {
fetch(`/get——balance?provider=${provider}`)
.then(balance => {
resolve(balance);
})
.catch(error => {
reject(error);
})
},
/**
* 12. transform
*
* format: {order: fn, rename:fn}
*
* - transform主要是用于
* - transform会在gmservice即将输出的时候执行,不会对内容数据产生影响:因此可以配合config使用、即时更新输出数据
* - 主要的使用方式: 更改名字、改变order,以及在切换语言的时候即时更新所有受影响的部分
*
* - order: function (groups, providers, categories, types):void
* 会在原有的object上操作 所有需要使用 .sort/.splice 之类的function
*
* - rename: function(keyword, type)
* rename如果没有明确返回值 则使用原本的value
* rename type分为了三类 provider, category 以及type
**/
/*
const cateOrder = {
'sports': 1,
'live': 2,
'slots': 3,
'sports': 4
}
*/
transform: {
rename: function(key, type) {
if (type == TYPES.GAMETYPE) return ({
roulette: "百家乐",
slots: '老虎机',
probability: '概率',
tablegame: '桌游',
videopoker: '扑克游戏',
'video-bingo': "宾果"
})[key];
if (type == TYPES.CATEGORY) return ({
slots: '电子游戏'
})[key];
},
order: function(groups, providers, categories, types) {
if (categories) categories.sort((cateA, cateB) => {
return cateOrder[cateA] - cateOrder[cateB]
})
}
},
})
API
active group 任何时候都会存在一个provider+category的组合作为active group;默认值为
{provider: null, category: null}
. gamelist, types, recommend等数据都会受当前active group影响- 同时存在provider与category
- 只有provider - 显示provider下所有category的数据
- 只有category - 显示category下所有provider的数据
- 都没有 - 显示全局数据
filters gameStream emit的是active group中的游戏列表, filterStream emit的是gameStream 的数据经过筛选后的结果. 筛选的filter有三种
- keyword: 游戏名称
- type: 游戏类型
- limitTo: 最大显示游戏数
stream stream即rxjs中的observable: 在api中主要操作方式为 .subscribe ; 所有以stream结尾命名的api都会多次emit数据:只需要subscribe一次; 如果只想获取一次数据可以使用 take(1) 比如
instance.typeStream.take(1).subscribe(types => {/*....*/})
# | API | 功能 | 示例 |
---|---|---|---|
1 | recommends(groupObject) | 根据provider + category获取推荐游戏列表 | instance.recommends({provider: 'PNG', category: 'live'}) .subscribe(games => {/* .... */}) |
2 | recommendStream | 当前active group的推荐游戏列表 | instance.recommendStream .subscribe(games => {/* .... */}) |
3 | list | 完整游戏列表 | instance.list(games => {/* do something */}) |
4 | setGroup | 设置active的group | instance.setGroup({provider:'PNG', category: 'slots'}}) instance.setGroup({provider:'Betsoft'}) |
5 | setFilter(filters, reset) (limitTo默认为20) reset如果为true 则会将filters先reset再加上传入的filters; 如果为false,则只会更新传入的filter,未传入的部分不变 | 更新Filter | instance.setFilter({keyword: 'diamond'}) instance.setFilter({ type:'slot' }) instance.setFilter({ limitTo: 50}) instance.setFilter({}, true) |
6 | loadMore(howmany?) 默认额外加载20个游戏 | 加载更多游戏(更新filter) | instance.loadMore() instance.loadMore(30) |
7 | gameStream | 当前active group对应游戏列表 | instance.gameStream .subscribe(games => {/* do something */}) |
8 | filteredStream | filter之后的当前active group对应游戏列表 | instance.filteredStream .subscribe(games => {/* do something */}) |
9 | gameGroupStream (相同于gameStream+typeStream) | active group的数据 | |
10 | typeStream (注意!只有当active group同时设置了provider与category, typeStream才会有数据) | 当前active group对应类型列表 | instance.typeStream .subscribe(types => {/* do something */}) |
11 | activeGroup | 当前active的group | instance.activeGroup .subscribe(group => {/* do something */}) |
12 | getLaunchUrl | 打开游戏 | api.getLaunchUrl({ provider: 'PNG', code: 1000 }) .subscribe(data => { data.status == 'success' && window.open(data.data) || alert(data.data) |
13 | getBalance | 获取平台余额 | api.getBalance('PNG') .subscribe(data => { data.status == 'success' && alert('balance=' + data.data) || alert(data.data) |
14 | providers (会被transform影响) | 平台列表 | instance.providers .subscribe(providers => {/* do something */}) |
15 | balances 会在getBalance请求完成时更新(注意: 进入或退出loading的状态不会造成balances的emit) | 平台余额Map | instance.balances .subscribe(balances => {/* do something */}) |
16 | categories (会被transform影响) | 类型列表 | instance.categories .subscribe(categories => {/* do something */}) |
17 | groups (会被transform影响) | group列表 | instance.groups .subscribe(groups => {/* do something */}) |
18 | indicators 两个subscribable的indicator: moreToLoad (boolean) , loading (array of targets in loading state) | 当前数据状态的指示 | indicators.moreToLoad .subscribe(moreToLoad => moreToLoad && show(loadMoreButton); }) indicators.loading .subscribe(states => { app.ready = states.length === 0 }) |
19 | gallery(会被transform影响) | 按照一定格式获取全部或者部分数据 | instance.gallery({}, GALLERY_FORMAT.PROVIDERS_OF_CATEGORIES).subscribe(games => {...}) instance.gallery({provider:'PNG'}).subscribe(games => {...}) |
20 | config | 重新设置rename/order函数; 操作之后各个stream将会重新计算并emit 因此可以支持语言切换 | api.config({transform: {rename: fn}}) |
Loading State 列表
- LOADING_GAMELIST
- LOADING_PROVIDERS
- LOADING_CATEGORIES
- LOADING_RECOMMENDS
GALLERY_FORMAT 列表
- CATEGORIES_OF_PROVIDERS
- PROVIDERS_OF_CATEGORIES
TYPES 列表
- PROVIDER
- GAMETYPE
- CATEGORY