You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

560 lines
22KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Reflection;
  5. using System.Linq;
  6. using System.Text.RegularExpressions;
  7. using OpenQA.Selenium;
  8. using OpenQA.Selenium.Chrome;
  9. using OpenQA.Selenium.Support.UI;
  10. using SeleniumExtras.WaitHelpers;
  11. using CSVDownloader.Code;
  12. using CSVDownloader.File;
  13. using CSVDownloader.Store;
  14. using CSVDownloader.Store.CreditCSVData;
  15. using CSVDownloader.Store.QRCSVData;
  16. using CSVDownloader.Store.ElectronicMoneyDataStore;
  17. using CSVDownloader.Web;
  18. using CSVDownloader.Exceptions;
  19. using MySql.Data.MySqlClient;
  20. namespace CSVDownloader {
  21. class Program {
  22. static void Main(string[] args) {
  23. // 作業ディレクトリを実行ファイルに合わせる。
  24. var exe_path = Assembly.GetEntryAssembly().Location;
  25. var exe_directory_path = Path.GetDirectoryName(exe_path);
  26. Directory.SetCurrentDirectory(exe_directory_path);
  27. var controller = new Controller(args);
  28. String ret = controller.Start();
  29. if (ret.Length != 0) {
  30. // エラー検知
  31. Console.WriteLine(ret);
  32. Console.WriteLine("エラー発生 詳細はログを参照");
  33. Environment.Exit(1);
  34. }
  35. }
  36. }
  37. class Controller {
  38. private log4net.ILog logger_ = log4net.LogManager.GetLogger("");
  39. private List<WebController> web_controller_list_ = new List<WebController>();
  40. private HistoryDAO history_dao_;
  41. private ParkingCreditCardAgenciesSpotIDDAO parking_credit_card_agencies_spotID_dao_;
  42. private DaitoCreitDataStore daito_credit_store_;
  43. private ZeusCreditDataStore zeus_credit_store_;
  44. private ItecCreditDataStore itec_credit_store_;
  45. private HelloTechnoCreditDataStore hello_techno_credit_store_;
  46. private DaitoQRDataStore daito_qr_store_;
  47. private DaitoElectronicMoneyDataStore daito_electronic_money_store_;
  48. private CreditCSVDataGMOStore gmo_credit_store_;
  49. private GMOElectronicMoneyDataStore gmo_electronic_money_store_;
  50. private ParkingCreditCardAgenciesSpotIDErrorDAO parking_credit_card_agencies_spotID_error_dao_;
  51. private IConfigReader config_;
  52. private ChromeDriver driver_;
  53. private MySqlConnection conn_;
  54. private MySqlTransaction transaction_;
  55. private Dictionary<Code.CreditAgent, CreditCSVDataStore> credit_datastore_map_ = new Dictionary<Code.CreditAgent, CreditCSVDataStore>();
  56. private Dictionary<Code.CreditAgent, QRCSVDataStore> qr_datastore_map_ = new Dictionary<Code.CreditAgent, QRCSVDataStore>();
  57. private Dictionary<Code.CreditAgent, ElectronicMoneyCSVDataStore> electronic_money_datastore_map_ = new Dictionary<Code.CreditAgent, ElectronicMoneyCSVDataStore>();
  58. private int save_chunk_num_ = 100;
  59. // パラメータあり起動時の動作条件------ START
  60. private bool hasParam_ = false;
  61. private DateTime paramDateFrom_ = DateTime.Today;
  62. private DateTime paramDateTo_ = DateTime.Today;
  63. private string paramAgentCode_ = "";
  64. // パラメータあり起動時の動作条件------ END
  65. public Controller(string[] args) {
  66. // 引数なしは通常動作
  67. if (args.Count() == 0) {
  68. return;
  69. }
  70. // 開始終了日付指定 決済会社コード指定
  71. if (args.Count() == 3) {
  72. DateTime from = DateTime.Today;
  73. DateTime to = DateTime.Today;
  74. var fromStr = args[0];
  75. var toStr = args[1];
  76. var dateReg = new Regex(@"^\d{4}/\d{2}/\d{2}$");
  77. if (dateReg.IsMatch(fromStr) && !DateTime.TryParse(fromStr, out from)) {
  78. throw new Exception("起動引数不正 FROM 日付フォーマット");
  79. }
  80. if (dateReg.IsMatch(toStr) && !DateTime.TryParse(toStr, out to)) {
  81. throw new Exception("起動引数不正 TO 日付フォーマット");
  82. }
  83. if (to < from) {
  84. throw new Exception("起動引数不正 FROMが大きい");
  85. }
  86. hasParam_ = true;
  87. paramDateFrom_ = from;
  88. paramDateTo_ = to;
  89. paramAgentCode_ = args[2];
  90. var message = $"★★★★★★起動引数あり FROM:{fromStr} TO:{toStr} AGENT:{paramAgentCode_}★★★★★★";
  91. Console.WriteLine(message);
  92. logger_.Info(message);
  93. return;
  94. }
  95. throw new Exception("起動引数不正");
  96. }
  97. public String Start() {
  98. Console.WriteLine("★★★★★★自動CSVダウンロード 起動★★★★★");
  99. logger_.Info("★★★★★★自動CSVダウンロード 起動★★★★★");
  100. String returnable = "";
  101. // 各種ストアを用意
  102. history_dao_ = new HistoryDAO();
  103. config_ = new ConfigReader("config/config.ini");
  104. var mysql_param = new MySqlConnectionParameter() {
  105. host = "192.168.0.28",
  106. port = 3306,
  107. database = "ypark",
  108. user = "ypuser2",
  109. password = "ypp@ssw0rd2"
  110. };
  111. //var mysql_param = new MySqlConnectionParameter() {
  112. // host = "localhost",
  113. // port = 3306,
  114. // database = "yp",
  115. // user = "docker",
  116. // password = "docker",
  117. //};
  118. try {
  119. conn_ = MySQL.GetConnection(mysql_param);
  120. parking_credit_card_agencies_spotID_dao_ = new ParkingCreditCardAgenciesSpotIDDAO(conn_);
  121. parking_credit_card_agencies_spotID_error_dao_ = new ParkingCreditCardAgenciesSpotIDErrorDAO(conn_);
  122. daito_credit_store_ = new DaitoCreitDataStore(conn_);
  123. zeus_credit_store_ = new ZeusCreditDataStore(conn_);
  124. itec_credit_store_ = new ItecCreditDataStore(conn_);
  125. hello_techno_credit_store_ = new HelloTechnoCreditDataStore(conn_);
  126. daito_qr_store_ = new DaitoQRDataStore(conn_);
  127. gmo_credit_store_ = new CreditCSVDataGMOStore(conn_);
  128. gmo_electronic_money_store_ = new GMOElectronicMoneyDataStore(conn_);
  129. daito_electronic_money_store_ = new DaitoElectronicMoneyDataStore(conn_);
  130. } catch (Exception e) {
  131. logger_.Error("DB接続失敗");
  132. logger_.Error(e.Message);
  133. return "DBへのコネクト失敗";
  134. }
  135. // エラーリストを初期化する(全削除)
  136. parking_credit_card_agencies_spotID_error_dao_.DeleteAll();
  137. // サイトごとにコントローラーを用意する。
  138. MakeConttollers();
  139. // 各コントローラーを起動する。
  140. foreach (var web_controller in web_controller_list_) {
  141. var ret = HandleWebController(web_controller);
  142. if (ret == Code.ResultCode.NG) {
  143. logger_.Error($"処理失敗 {web_controller.GetCreditAgent().ToString()}");
  144. returnable = "処理失敗";
  145. }
  146. }
  147. // ブラウザの終了
  148. if (driver_ != null) {
  149. driver_.Quit();
  150. }
  151. // 終了
  152. logger_.Info("処理成功");
  153. return returnable;
  154. }
  155. private void MakeConttollers() {
  156. driver_ = DriverFactory.GetDriver();
  157. // CREVAS
  158. {
  159. var controller = new DaitoController(driver_);
  160. if (!hasParam_ || paramAgentCode_ == controller.GetCreditAgentCode()) {
  161. var dic = parking_credit_card_agencies_spotID_dao_.GetDictionary(controller.GetCreditAgent());
  162. controller.SetParkingDic(dic);
  163. web_controller_list_.Add(controller);
  164. credit_datastore_map_.Add(controller.GetCreditAgent(), daito_credit_store_);
  165. qr_datastore_map_.Add(controller.GetCreditAgent(), daito_qr_store_);
  166. electronic_money_datastore_map_.Add(controller.GetCreditAgent(), daito_electronic_money_store_);
  167. }
  168. }
  169. // Zeus
  170. {
  171. var controller = new ZeusController(driver_);
  172. if (!hasParam_ || paramAgentCode_ == controller.GetCreditAgentCode()) {
  173. var dic = parking_credit_card_agencies_spotID_dao_.GetDictionary(controller.GetCreditAgent());
  174. controller.SetParkingDic(dic);
  175. web_controller_list_.Add(controller);
  176. credit_datastore_map_.Add(controller.GetCreditAgent(), zeus_credit_store_);
  177. }
  178. }
  179. // Itec
  180. {
  181. //var controller = new ItecController(driver_);
  182. //var dic = parking_credit_card_agencies_spotID_dao_.GetDictionary(controller.GetCreditAgent());
  183. //controller.SetParkingDic(dic);
  184. //web_controller_list_.Add(controller);
  185. //credit_datastore_map_.Add(controller.GetCreditAgent(), itec_credit_store_);
  186. }
  187. // HelloTechno
  188. {
  189. //var controller = new HelloTechnoController(driver_);
  190. //var dic = parking_credit_card_agencies_spotID_dao_.GetDictionary(controller.GetCreditAgent());
  191. //controller.SetParkingDic(dic);
  192. //web_controller_list_.Add(controller);
  193. //credit_datastore_map_.Add(controller.GetCreditAgent(), hello_techno_credit_store_);
  194. }
  195. // HelloTechno(GMO)
  196. {
  197. var controller = new GMOController(driver_);
  198. if (!hasParam_ || paramAgentCode_ == controller.GetCreditAgentCode()) {
  199. var dic = parking_credit_card_agencies_spotID_dao_.GetDictionary(controller.GetCreditAgent());
  200. controller.SetParkingDic(dic);
  201. web_controller_list_.Add(controller);
  202. credit_datastore_map_.Add(controller.GetCreditAgent(), gmo_credit_store_);
  203. electronic_money_datastore_map_.Add(controller.GetCreditAgent(), gmo_electronic_money_store_);
  204. }
  205. }
  206. }
  207. private Code.ResultCode HandleWebController(WebController web_controller) {
  208. Code.ResultCode result_code = Code.ResultCode.OK;
  209. // 実行対象日判定
  210. if (!web_controller.IsWorkDate()) {
  211. logger_.Info($"処理対象日外:{ web_controller.GetCreditAgent()}");
  212. return result_code;
  213. }
  214. try {
  215. // 各ダウンロードディレクトリをクリーンする。
  216. CreanDirectries();
  217. // カード会社を特定する。
  218. Code.CreditAgent agent = web_controller.GetCreditAgent();
  219. logger_.Info($"ダウンロード開始 対象:{agent}");
  220. // 履歴を参照する。
  221. var history = history_dao_.GetHistory(agent);
  222. // 履歴から取得範囲を特定する。
  223. (var from, var to) = GetFromTo(agent, history);
  224. logger_.Info($"取得範囲 {from.ToString("yyyy/MM/dd")} ~ {to.ToString("yyyy/MM/dd")}");
  225. // ログイン情報を取得
  226. var login_info = GetLoginInfo(agent);
  227. // ログインを開始
  228. result_code = web_controller.Login(login_info);
  229. if (result_code != Code.ResultCode.OK) {
  230. throw new Exception("ログイン失敗");
  231. }
  232. logger_.Info("ログイン成功");
  233. // ダウンロード開始
  234. result_code = web_controller.Download(from, to);
  235. if (result_code != Code.ResultCode.OK) {
  236. throw new Exception("ダウンロード失敗");
  237. }
  238. logger_.Info("ダウンロード成功");
  239. // ログアウト
  240. result_code = web_controller.Logout();
  241. if (result_code != Code.ResultCode.OK) {
  242. throw new Exception("ログアウト失敗");
  243. }
  244. logger_.Info("ログアウト成功");
  245. // ロード画面の表示
  246. var load_html_path = Path.GetFullPath(@"static\html\load.html");
  247. driver_.Navigate().GoToUrl($"file://{load_html_path}");
  248. // データリストの取得
  249. // 取得に失敗したものはエラーリストとして登録する。
  250. bool list_get_success = true;
  251. List<CreditCSVData> credit_info_list = null;
  252. List<QRCSVData> qr_info_list = null;
  253. List<ElectronicMoneyCSVData> electronic_money_info_list = null;
  254. try {
  255. credit_info_list = web_controller.GetCreditCSVDataList();
  256. } catch (SpotNameNotMatchException e) {
  257. list_get_success = false;
  258. parking_credit_card_agencies_spotID_error_dao_.Save(e.GetList());
  259. }
  260. try {
  261. qr_info_list = web_controller.GetQRCSVDataList();
  262. } catch (SpotNameNotMatchException e) {
  263. list_get_success = false;
  264. parking_credit_card_agencies_spotID_error_dao_.Save(e.GetList());
  265. }
  266. try {
  267. electronic_money_info_list = web_controller.GetElectronicMoneyCSVDataList();
  268. } catch (SpotNameNotMatchException e) {
  269. list_get_success = false;
  270. parking_credit_card_agencies_spotID_error_dao_.Save(e.GetList());
  271. }
  272. if (!list_get_success) {
  273. throw new Exception("データリスト取得失敗");
  274. }
  275. // データ保存
  276. int delete_count_credit = 0;
  277. int delete_count_qr = 0;
  278. int delete_count_electronic_money = 0;
  279. transaction_ = conn_.BeginTransaction();
  280. // クレジット
  281. if (0 < credit_info_list.Count) {
  282. ShowTotalCount(credit_info_list.Count);
  283. var store = credit_datastore_map_[agent];
  284. delete_count_credit = store.Delete(from, to);
  285. var current_count = 0;
  286. ShowCurrentCount(current_count);
  287. var chunk_data_list = credit_info_list.Select((CreditCSVData data, int index) => new { data, index })
  288. .GroupBy(x => x.index / save_chunk_num_)
  289. .Select(g => g.Select(r => r.data));
  290. foreach (var data_list in chunk_data_list) {
  291. var list = data_list.ToList();
  292. store.Save(list);
  293. current_count += list.Count;
  294. ShowCurrentCount(current_count);
  295. }
  296. }
  297. // QR
  298. if (0 < qr_info_list.Count) {
  299. ShowTotalCount(qr_info_list.Count);
  300. var store = qr_datastore_map_[agent];
  301. delete_count_qr = store.Delete(from, to);
  302. var current_count = 0;
  303. ShowCurrentCount(current_count);
  304. var chunk_data_list = qr_info_list.Select((QRCSVData data, int index) => new { data, index })
  305. .GroupBy(x => x.index / save_chunk_num_)
  306. .Select(g => g.Select(r => r.data));
  307. foreach (var data_list in chunk_data_list) {
  308. var list = data_list.ToList();
  309. store.Save(list);
  310. current_count += list.Count;
  311. ShowCurrentCount(current_count);
  312. }
  313. }
  314. // 電子マネー
  315. if (0 < electronic_money_info_list.Count) {
  316. ShowTotalCount(electronic_money_info_list.Count);
  317. var store = electronic_money_datastore_map_[agent];
  318. delete_count_electronic_money = store.Delete(from, to);
  319. var current_count = 0;
  320. ShowCurrentCount(current_count);
  321. var chunk_data_list = electronic_money_info_list.Select((ElectronicMoneyCSVData data, int index) => new { data, index })
  322. .GroupBy(x => x.index / save_chunk_num_)
  323. .Select(g => g.Select(r => r.data));
  324. foreach (var data_list in chunk_data_list) {
  325. var list = data_list.ToList();
  326. store.Save(list);
  327. current_count += list.Count;
  328. ShowCurrentCount(current_count);
  329. }
  330. }
  331. // コミット処理
  332. transaction_.Commit();
  333. logger_.Info($"削除件数 CREDIT :{delete_count_credit}");
  334. logger_.Info($"削除件数 QR :{delete_count_qr}");
  335. logger_.Info($"削除件数 電子マネー :{delete_count_electronic_money}");
  336. logger_.Info($"登録件数 CREDIT :{credit_info_list.Count}");
  337. logger_.Info($"登録件数 QR :{qr_info_list.Count}");
  338. logger_.Info($"登録件数 電子マネー :{electronic_money_info_list.Count}");
  339. web_controller.Archive(GetArchiveFilename(agent, DateTime.Now));
  340. // 履歴の登録
  341. if (!hasParam_) {
  342. history_dao_.Save(agent, DateTime.Now);
  343. } else {
  344. logger_.Info("パラメータ指定起動のため、取得履歴は保存しない");
  345. }
  346. logger_.Info($"ダウンロード終了 対象:{agent}");
  347. } catch (Exception e) {
  348. // ロールバック処理
  349. logger_.Error(e.Message);
  350. logger_.Error(e.StackTrace);
  351. if (transaction_ != null) {
  352. transaction_.Rollback();
  353. }
  354. transaction_ = null;
  355. return Code.ResultCode.NG;
  356. }
  357. transaction_ = null;
  358. return Code.ResultCode.OK;
  359. }
  360. /// <summary>
  361. /// データ取得範囲を特定する。<br/>
  362. /// </summary>
  363. /// <param name="history"></param>
  364. /// <returns></returns>
  365. private (DateTime, DateTime) GetFromTo(Code.CreditAgent agent, List<History> history) {
  366. // 起動パラメータがある場合はそれを設定する
  367. if (hasParam_) {
  368. return (paramDateFrom_, paramDateTo_);
  369. }
  370. DateTime from, to;
  371. if (agent == Code.CreditAgent.Zeus) {
  372. // Zeusの場合は、データが修正されるケースがあるため
  373. // 期間を制御する
  374. // 前回取得日から1か月遡る。
  375. // var prev_date = DateTime.Now.AddMonths(-1);
  376. // from = new DateTime(prev_date.Year, prev_date.Month, 1);
  377. // to = from.AddMonths(1).AddDays(-1);
  378. var now_date = DateTime.Now.Date;
  379. from = now_date.AddMonths(-1);
  380. to = now_date;
  381. } else {
  382. var now_date = DateTime.Now.Date;
  383. from = now_date.AddDays(-20);
  384. to = now_date;
  385. if (history.Count != 0) {
  386. var prev_date = history[0].date;
  387. if (from < prev_date) {
  388. from = prev_date.Date;
  389. }
  390. }
  391. }
  392. return (from, to);
  393. }
  394. /// <summary>
  395. /// コンフィグファイルよりログイン情報を取得する。
  396. /// </summary>
  397. /// <param name="agent"></param>
  398. /// <returns></returns>
  399. private LoginInfo GetLoginInfo(Code.CreditAgent agent) {
  400. var login_info = new LoginInfo();
  401. String sesction = $"LOGIN_INFO_{agent.ToString()}";
  402. login_info.user_name = config_.Read(sesction, "user");
  403. if (login_info.user_name.Length == 0) {
  404. throw new Exception($"ログイン情報不足 host {agent.ToString()}");
  405. }
  406. login_info.password = config_.Read(sesction, "password");
  407. if (login_info.password.Length == 0) {
  408. throw new Exception($"ログイン情報不足 password {agent.ToString()}");
  409. }
  410. login_info.company_name = config_.Read(sesction, "company");
  411. return login_info;
  412. }
  413. private String GetArchiveFilename(Code.CreditAgent agent, DateTime now) {
  414. return $"{agent}_{now.ToString("yyyyMMddHHmmss")}.zip";
  415. }
  416. private void CreanDirectries() {
  417. var dir_download = new DirectoryInfo(DriverFactory.GetDownloadDir());
  418. foreach (var file in dir_download.GetFiles()) {
  419. file.Delete();
  420. }
  421. var tmp_download = new DirectoryInfo(DriverFactory.GetTmpDownloadDir());
  422. foreach (var file in tmp_download.GetFiles()) {
  423. file.Delete();
  424. }
  425. }
  426. private void ShowTotalCount(int num) {
  427. driver_.ExecuteScript($"setTotal({num})");
  428. }
  429. private void ShowCurrentCount(int num) {
  430. driver_.ExecuteScript($"setCount({num})");
  431. }
  432. }
  433. }