var config = require('../config'), transport = require('./transport'); var token = '', user = null, storageKey = 'juzi.taobao.session.v1'; function assetUrl(path) { return config.assetBase.replace(/\/?$/, '/') + path.replace(/^assets\//, ''); } function clear() { token = ''; user = null; try { my.removeStorageSync({ key: storageKey }); } catch (_) {} var app = typeof getApp === 'function' && getApp(); if (app) { app.globalData.profile = null; app.globalData.photos = null; app.globalData.payload = null; } } function request(path, body) { var requestToken = token; return transport.request('/api/taobao/' + path, body || {}, requestToken).then(function (data) { if (!data || !data.ok) { var err = new Error(data && data.message || '服务暂不可用,请稍后重试'); err.status = data && data.http_status; err.code = data && data.code; if (err.status === 401 && requestToken === token) clear(); throw err; } return data; }); } function authorize() { if (config.transport === 'direct') return Promise.resolve(); return new Promise(function (resolve, reject) { my.authorize({ scopes: 'scope.userInfo', success: resolve, fail: function () { reject(new Error('请授权淘宝账号后继续')); } }); }); } function login(consent) { if (!consent) return Promise.reject(new Error('请先阅读并同意隐私协议')); return authorize().then(function () { return request('challenge'); }).then(function (data) { return request('session', { consent: true, challenge: data.challenge }); }).then(function (data) { token = data.token; user = data.user; my.setStorageSync({ key: storageKey, data: { token: token, user: user } }); return user; }); } function restore() { try { var saved = my.getStorageSync({ key: storageKey }).data; if (saved) { token = saved.token || ''; user = saved.user || null; } } catch (_) {} if (!token) return Promise.resolve(null); var restoredToken = token; return request('me').then(function (data) { if (token === restoredToken) user = data.user; return user; }); } function canceled(signal) { if (signal && signal.canceled) { var e = new Error('已取消检测'); e.canceled = true; throw e; } } function wait(ms, signal) { return new Promise(function (resolve) { setTimeout(resolve, ms); }).then(function () { canceled(signal); }); } function poll(job, signal, deadline) { canceled(signal); if (Date.now() >= deadline) throw new Error('检测仍在处理中,请稍后从历史报告查看'); return request('analysis', { job: job }).then(function (data) { canceled(signal); if (data.status !== 'complete') return wait(1000, signal).then(function () { return poll(job, signal, deadline); }); if (!data.payload || !data.payload.ok) throw new Error(data.payload && data.payload.message || '检测失败,请重试'); return data.payload; }); } function upload(view, photo, signal) { var b64 = photo.replace(/^data:image\/[^;]+;base64,/, ''), size = 64 * 1024; if (!b64 || b64.length > 4 * 1024 * 1024) return Promise.reject(new Error('照片过大,请重新拍摄')); var id = Date.now().toString(36) + '-' + Math.random().toString(36).slice(2), total = Math.ceil(b64.length / size); var chain = Promise.resolve(); for (var i = 0; i < total; i++) (function (index) { chain = chain.then(function () { canceled(signal); return request('photo', { view: view, upload_id: id, index: index, total: total, data: b64.slice(index * size, (index + 1) * size) }); }); })(i); return chain.then(function () { return id; }); } function analyze(photos, profile, signal) { if (config.mock) { var SS = require('../vendor/skin-score'), UI = require('../vendor/report-ui'); var vm = SS.buildViewModel(SS.MOCK_RESULT, SS.MOCK_SIDE, { realAge: profile.real_age, skinType: profile.daily_skin_type }); return Promise.resolve({ ok: true, result: SS.MOCK_RESULT, side: SS.MOCK_SIDE, vm: vm, presentation: UI.build(vm, SS.MOCK_RESULT) }); } var refs = {}; return ['front', 'left', 'right'].reduce(function (chain, view, i) { return chain.then(function () { return upload(view, photos[i], signal); }).then(function (id) { refs[view] = id; }); }, Promise.resolve()).then(function () { canceled(signal); return request('skin-analyze', { photo_refs: refs, profile: profile }); }).then(function (data) { return poll(data.job, signal, Date.now() + 90000); }); } function wrinkleViews(jobToken, signal) { return request('wrinkle-views', { token: jobToken }).then(function (data) { return poll(data.job, signal, Date.now() + 90000); }); } function logout() { return request('logout').catch(function (err) { // An expired/revoked session is already signed out; network failures still surface. if (err.status !== 401) throw err; }).then(clear); } module.exports = { assetUrl: assetUrl, analyze: analyze, login: login, restore: restore, request: request, user: function () { return user; }, logout: logout, wrinkleViews: wrinkleViews };