fsa.pm 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. use Modern::Perl;
  2. use Data::Dumper;
  3. use Mojo::Base -strict, -signatures;
  4. use FSA::Rules;
  5. our $redis;
  6. our $config;
  7. our $client;
  8. our $commands;
  9. our $kb_menu;
  10. my %main = (
  11. logged_out => {
  12. rules => [
  13. logged_out => sub($state, $line, $chatid, $rest)
  14. {
  15. if ($line ne "/start")
  16. {
  17. notify($chatid, _("Для начала работы наберите <b>/start</b>"), $rest);
  18. return 1;
  19. }
  20. return undef;
  21. },
  22. dummy => sub($state, $line, $chatid, $rest)
  23. {
  24. my $res = $client->get("client", "/telegram/$chatid/client");
  25. if (my $err = $client->error)
  26. {
  27. if ($err->{code}==410)
  28. {
  29. reply($rest, _("Вас приветствует провайдер") . " " . $config->{provider});
  30. reply($rest, _("Введите номер учетной записи или логин"));
  31. $state->result("ask_login");
  32. }
  33. else
  34. {
  35. report($chatid, $err);
  36. $state->result("error");
  37. }
  38. }
  39. else
  40. {
  41. $state->result("logined");
  42. $state->notes(uid => $res->{uid});
  43. }
  44. return undef;
  45. },
  46. needs_login => sub($state, $line, $chatid, $rest)
  47. {
  48. return $state->result eq "ask_login";
  49. },
  50. logged_out => sub($state, $line, $chatid, $rest)
  51. {
  52. return $state->result eq "error";
  53. },
  54. command => 1,
  55. ],
  56. },
  57. needs_login => {
  58. rules => [
  59. needs_password => sub($state, $login, $chatid, $rest)
  60. {
  61. $state->notes(login => $login);
  62. reply($rest, _("Теперь введите пароль"));
  63. 1;
  64. },
  65. ],
  66. },
  67. needs_password => {
  68. rules => [
  69. logged_out => sub($state, $password, $chatid, $rest)
  70. {
  71. my $login = $state->notes("login");
  72. my $res = $client->post("client", "/telegram/client", {login=>$login, password=>$password, telegram_id=>$chatid});
  73. $state->notes(login => undef);
  74. if (my $err = $client->error)
  75. {
  76. report($chatid, $err);
  77. return 1;
  78. }
  79. my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
  80. my $greet = $hour>=4 && $hour<=10 ? _("Доброе утро") : $hour>10 && $hour<6 ? _("Добрый день") : _("Добрый вечер");
  81. reply($rest, "$greet, " . $res->{fio});
  82. $state->notes(uid => $res->{uid});
  83. return undef;
  84. },
  85. command => 1,
  86. ],
  87. },
  88. command => {
  89. rules => [
  90. command => sub($state, $line, $chatid, $rest)
  91. {
  92. do_command($line, $chatid, $rest);
  93. 1;
  94. }
  95. ],
  96. },
  97. dummy => {
  98. },
  99. );
  100. our $fsa = FSA::Rules->new(%main);
  101. sub report($chatid, $err)
  102. {
  103. if ($err->{code}>=400 && $err->{code}<500 && ref $err->{body} eq "HASH")
  104. {
  105. notify($chatid, $err->{body}->{text_ru});
  106. }
  107. else
  108. {
  109. my $code = int(rand(10000));
  110. say STDERR "====== $code";
  111. say STDERR Dumper $err;
  112. notify($chatid, _("Ошибка авторизации. Сообщите в службу технической поддержки код") . " $code");
  113. }
  114. }
  115. ######################
  116. sub save_fsa_state($id)
  117. {
  118. my $ks = make_key($id, "state");
  119. my $kn = make_key($id, "notes");
  120. $redis->set($ks, $fsa->curr_state->name);
  121. $redis->expire($ks, 3600*24);
  122. $fsa->notes(chatid => undef);
  123. say "saving state ", $fsa->curr_state->name, Dumper map { ($_, $fsa->notes->{$_}) } grep { defined $fsa->notes->{$_} } keys %{ $fsa->notes };
  124. $redis->hmset($kn, map { ($_, $fsa->notes->{$_}) } grep { defined $fsa->notes->{$_} } keys %{ $fsa->notes });
  125. $redis->expire($kn, 3600*24);
  126. }
  127. sub restore_fsa_state($chat, $from)
  128. {
  129. my $state = $redis->get(make_key($chat, "state"));
  130. set_fsa_state($state, $chat, $from);
  131. }
  132. sub set_fsa_state($state, $chat, $from)
  133. {
  134. if ($state)
  135. {
  136. my $notes = { $redis->hgetall(make_key($chat, "notes")) };
  137. $fsa->notes($_ => $notes->{$_}) for keys %$notes;
  138. $fsa->notes(chatid => $chat);
  139. $fsa->curr_state($state);
  140. say "restore ", $state, Dumper make_key($chat, "notes"), $notes;
  141. }
  142. else
  143. {
  144. $fsa->reset;
  145. $fsa->notes(chatid => $chat);
  146. $fsa->notes(lang => $from->{language_code});
  147. $fsa->start;
  148. }
  149. }
  150. sub process_input($line, $chatid, $rest)
  151. {
  152. say "*** current state = ", $fsa->curr_state->name;
  153. $fsa->switch($line, $chatid, $rest);
  154. if (defined (my $new_state = $fsa->notes("new_state")))
  155. {
  156. say "*** mandatory switching to $new_state";
  157. set_fsa_state($new_state, $chatid, $rest);
  158. $fsa->notes(new_state => undef);
  159. }
  160. say "*** Switched to ", $fsa->curr_state->name;
  161. }
  162. sub set_new_state($name)
  163. {
  164. $fsa->notes(new_state => $name);
  165. }
  166. 1;