UNPKG

srtrain

Version:
188 lines (187 loc) 7.62 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SRT = void 0; const axios_1 = __importDefault(require("axios")); const moment_1 = __importDefault(require("moment")); const axios_cookiejar_support_1 = require("axios-cookiejar-support"); const lodash_1 = __importDefault(require("lodash")); const random_useragent_1 = require("random-useragent"); const tough_cookie_1 = require("tough-cookie"); const errorCode_1 = require("./constants/errorCode"); const loginMethod_1 = require("./constants/loginMethod"); const station_1 = require("./constants/station"); const error_1 = require("./error"); const reservation_1 = require("./reservation"); const station_2 = require("./station"); const train_1 = require("./train"); class SRT { isLoggined = false; axios; userId; password; baseURL = 'https://app.srail.or.kr'; userAgent = this.generateUserAgent(); cookieJar = new tough_cookie_1.CookieJar(); constructor(options) { if (options) { const { baseURL, userAgent } = options; if (baseURL) this.baseURL = baseURL; if (userAgent) this.userAgent = userAgent; } this.axios = this.initAxios(); } initAxios() { this.axios = (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({ jar: this.cookieJar, baseURL: this.baseURL, headers: { 'User-Agent': this.userAgent, 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json', }, })); this.axios.interceptors.response.use(async (res) => { if (lodash_1.default.get(res.data, 'resultMap[0].msgCd') !== 'S111') return res; const { userId, password } = this; if (!userId || !password || res.retry) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.LOGIN_REQUIRED, '로그인 후 사용하십시요.'); } res.retry = true; this.isLoggined = false; await this.login({ userId, password }); return this.axios(res.config); }); return this.axios; } async login(options) { const { userId, password, accessToken } = options; this.userId = userId; this.password = password; if (accessToken) { this.isLoggined = true; const json = JSON.parse(accessToken); this.cookieJar = await tough_cookie_1.CookieJar.deserialize(json); this.initAxios(); return; } const method = this.detectUserMethod(userId); const referer = options.referer || 'https://app.srail.or.kr/main/main.do'; const { data } = await this.axios.post('/apb/selectListApb01080_n.do', { 'auto': 'Y', 'check': 'Y', 'page': 'menu', 'deviceKey': '-', 'customerYn': '', 'login_referer': referer, 'srchDvCd': method, 'srchDvNm': userId.replace(/-/g, ''), 'hmpgPwdCphd': password, }); const message = data.MSG || ''; if (message.includes('존재하지않는 회원입니다')) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.USER_NOT_FOUND, message); } if (message.includes('비밀번호 오류')) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.PASSWORD_INCORRECT, message); } this.isLoggined = true; } getStation(name) { const code = station_1.SRTStationCode[name]; if (!code) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.STATION_NOT_FOUND, '해당 역을 찾을 수 없습니다.'); } return new station_2.SRTStation(code); } async find(options) { const { departureStation, arrivalStation, date, all } = options; const actualDate = (date || (0, moment_1.default)()).format('YYYYMMDD'); const actualTime = date?.format('HHmmss') || '000000'; const { data } = await this.axios.post('/ara/selectListAra10007_n.do', { 'chtnDvCd': '1', 'arriveTime': 'N', 'seatAttCd': '015', 'psgNum': 1, 'trnGpCd': 109, 'stlbTrnClsfCd': '05', 'dptDt': actualDate, 'dptTm': actualTime, 'arvRsStnCd': arrivalStation.code, 'dptRsStnCd': departureStation.code, }); if (!all) this.parseResponse(data); const message = data.resultMap[0]?.msgTxt; if (message && message === '조회 결과가 없습니다.') return []; const output = data.outDataSets.dsOutput1; const trains = output.map((train) => new train_1.SRTTrain(this, train)); if (!all) return trains; const lastDepartureDate = trains[trains.length - 1].departureDate; const nextDepartureDate = lastDepartureDate.clone().add(1, 'seconds'); const nextTrains = await this.find({ departureStation, arrivalStation, date: nextDepartureDate, all: true, }); trains.push(...nextTrains); return trains; } async getReservationById(reservationId) { const reservations = await this.getReservations(); return reservations.find((r) => r.reservationId === reservationId); } async getReservations() { if (!this.isLoggined) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.LOGIN_REQUIRED, '로그인이 필요한 서비스입니다.'); } const { data } = await this.axios.post('/atc/selectListAtc14016_n.do', { pageNo: '0', }); this.parseResponse(data); const reservations = lodash_1.default.zip(data['trainListMap'], data['payListMap']).map(([trainData, payData]) => new reservation_1.SRTReservation(this, { trainData, payData })); return reservations; } parseResponse(data) { if (data.resultMap?.length !== 1) { throw new error_1.SRTError(errorCode_1.SRTErrorCode.UNKNOWN, '오류가 발생하였습니다.'); } const [firstOfResult] = data.resultMap; const resultCode = firstOfResult.strResult; const errorCode = firstOfResult.msgCd; const message = firstOfResult.msgTxt; if (resultCode !== 'SUCC') { let code = errorCode_1.SRTErrorCode.UNKNOWN; if (errorCode === 'S111') code = errorCode_1.SRTErrorCode.LOGIN_REQUIRED; if (errorCode === 'ERR800052') code = errorCode_1.SRTErrorCode.ALREADY_CANCELLED; throw new error_1.SRTError(code, message); } return data; } detectUserMethod(userId) { if (userId.match(/[^@]+@[^@]+\.[^@]+/g)) return loginMethod_1.SRTLoginMethod.EMAIL; if (userId.match(/^\d{3}-\d{3,4}-\d{4}$/g)) { return loginMethod_1.SRTLoginMethod.PHONE_NUMBER; } return loginMethod_1.SRTLoginMethod.MEMBERSHIP_ID; } generateUserAgent() { const ua = (0, random_useragent_1.getRandom)((ua) => ua.osName === 'Android'); return `${ua} SRT-APP-Android V.1.0.6`; } async getAccessToken() { return this.cookieJar.serialize().then((r) => JSON.stringify(r)); } } exports.SRT = SRT;