Module: Dialog

Extended by:
Dry::Configurable
Defined in:
lib/require.rb,
lib/version.rb,
lib/begin/bot.rb,
lib/tdlib/auth.rb,
lib/tdlib/func.rb,
lib/tdlib/init.rb,
lib/begin/_main.rb,
lib/begin/tdlib.rb,
lib/dialog_ruby.rb,
lib/tooling/log.rb,
lib/tooling/lang.rb,
lib/configuration.rb,
lib/metamess/_run.rb,
lib/metamess/func.rb,
lib/triggers/init.rb,
lib/begin/_pre_bot.rb,
lib/triggers/_func.rb,
lib/triggers/false.rb,
lib/metamess/naming.rb,
lib/statistics/func.rb,
lib/telegram/botapi.rb,
lib/tooling/strings.rb,
lib/triggers/deploy.rb,
lib/begin/background.rb,
lib/metamess/event_c.rb,
lib/telegram/wrappers.rb,
lib/statistics/general.rb,
lib/storage/redis/func.rb,
lib/dialect/codegen/run.rb,
lib/telegram/infra_info.rb,
lib/statistics/redisDump.rb,
lib/dialect/canvas/canvas.rb,
lib/triggers/console_start.rb,
lib/triggers/systemd_start.rb,
lib/dialect/codegen/codegen.rb,
lib/metamess/event/notify_o.rb,
lib/storage/redis/stat/push.rb,
lib/metamess/content/content_o.rb,
lib/metamess/service/service_o.rb,
lib/dialect/canvas/mod/send/func.rb,
lib/storage/redis/cached/pullpush.rb,
lib/metamess/event/notify_o-create_f.rb,
lib/metamess/event/notify_o-pinned_f.rb,
lib/storage/redis/cached/pushPreproc.rb,
lib/metamess/event/notify_o-migrate_f.rb,
lib/dialect/canvas/element/data/search.rb,
lib/dialect/canvas/mod/send/_keyboards.rb,
lib/metamess/content/content_o-media_f.rb,
lib/metamess/content/content_o-simple_f.rb,
lib/metamess/event/notify_o-chattitle_f.rb,
lib/metamess/service/service_o-inline_f.rb,
lib/dialect/canvas/element/send/restrict.rb,
lib/dialect/canvas/mod/send/general/chat.rb,
lib/dialect/canvas/mod/send/general/user.rb,
lib/metamess/content/content_o-command_f.rb,
lib/metamess/content/content_o-contact_f.rb,
lib/metamess/event/notify_o-chatmember_f.rb,
lib/dialect/canvas/element/send/keyboards.rb,
lib/dialect/canvas/element/send/recognize.rb,
lib/metamess/service/service_o-callback_f.rb,
lib/dialect/canvas/element/send/background.rb,
lib/dialect/canvas/element/send/tdlib_chat.rb,
lib/dialect/canvas/mod/send/general/_heads.rb,
lib/dialect/canvas/mod/send/general/common.rb,
lib/dialect/canvas/element/send/bot_message.rb,
lib/dialect/canvas/mod/send/general/message.rb,
lib/dialect/canvas/element/send/tdlib_message.rb,
lib/dialect/canvas/element/convert/SearchBaloo.rb,
lib/dialect/canvas/mod/send/_Inline_query_result.rb,
lib/dialect/canvas/element/send/Inline_query_result.rb,
lib/dialect/codegen/repack/functional/1.Expect2Events.rb,
lib/dialect/codegen/repack/functional/7.ElementChains.rb,
lib/dialect/canvas/mod/send/inline_query_result/common.rb,
lib/dialect/codegen/repack/constructor/Element2ModSend.rb,
lib/dialect/codegen/repack/constructor/ElementsInElements.rb,
lib/dialect/codegen/repack/functional/5.2.Element2ModSend.rb,
lib/dialect/codegen/repack/functional/2.2.1.Events2ModReceive.rb,
lib/dialect/codegen/repack/functional/5.1.Element2ModElements.rb,
lib/dialect/codegen/repack/functional/2.2.2.ModReceive2AppEvent.rb,
lib/dialect/codegen/repack/constructor/DockedGroupings2AppFunctions.rb

Overview

####### ######## ####### ######## ########

 / / / /    License    \ \ \ \ 
Copyleft culture, Copyright (C) is prohibited here
This work is licensed under a CC BY-SA 4.0
Creative Commons Attribution-ShareAlike 4.0 License
Refer to the http://creativecommons.org/licenses/by-sa/4.0/
#######    ########    #######    ########    ########
/ / / /    Code Climate    \ \ \ \ 
Language = ruby
Indent = space;    2 chars;
#######    ########    #######    ########    ########

Defined Under Namespace

Modules: BotApi, Canvas, Dialect, ElementData, ElementSend, Lang, Metamess, ModSend, Naming, Statistics, Storage, Strings, TDLib, Triggers, Wrappers Classes: Log

Constant Summary collapse

VERSION =
'0.1.11'.freeze

Class Method Summary collapse

Class Method Details

._requireObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/require.rb', line 47

def _require
  ### SYSTEM
  require 'uri'
  require 'erb'
  require 'shellwords'
  require 'drb'      

  ### GEMS
  require 'active_support/time'       
  require 'dialect_lookup'
  require 'telegram/bot'
  require 'i18n'
  require 'redis'
  require 'concurrent'
  require 'oj'
  require 'sidekiq'
  require 'sidekiq/batch'                  
  require 'sidekiq-status'      
  require 'sidekiq-cron'
  require 'sidekiq-rate-limiter'
  #lazy_object

  ### DRY
  # require 'dry-monads'
  # require 'dry-matcher'
  # require 'dry-transaction'
  # require 'dry/inflector'
  # require 'dry-validation'
  # require 'dry-struct'
  # require 'dry-types'

  #dry-events - pub/sub

  ### CODE
  Dir.glob(File.join("#{File.dirname(__FILE__)}/**", "*.rb")).each{|f| require f}
end

._require_backgroundObject



37
38
39
40
41
42
43
44
# File 'lib/require.rb', line 37

def _require_background
  require 'sidekiq'
  require 'sidekiq/batch'   
  require 'sidekiq/api'      
  require 'sidekiq-status'      
  require 'sidekiq-cron'
  require 'sidekiq-rate-limiter'
end

._require_minObject



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/require.rb', line 16

def _require_min
  ### SYSTEM
  require 'pp'
  require 'timeout'
  require 'logger'
  require 'socket'
  require 'fileutils'
  require 'open3'
  require 'date'      
  

  ### GEMS
  require 'dry-configurable'
  
  
  require_relative './version.rb'
  Dir.glob(File.join("#{File.dirname(__FILE__)}/triggers/**", "*.rb")).each{|f| require f}      
  Dir.glob(File.join("#{File.dirname(__FILE__)}/begin/**", "*.rb")).each{|f| require f}            
  require_relative './configuration.rb'
end

._run(mode = false) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/begin/_main.rb', line 16

def _run(mode=false)
  args = {}
  mode == false ? mode = Dialog.config.run.mode : true
  Dialog.logger.debug "Using mode '#{mode}'"      
  case mode
  when 'check'
    _require
    jsonDriven(args, :check)
  when 'bot'
    _require
    jsonDriven(args, :prod)
    bot(args)
  when 'dialect'
    _require
    dialectDriven(args)
    jsonDriven(args, :check) 
  when 'tdlib'
    start_tdlib(args) 
  when 'background'
    start_background(args)         
  else
     Dialog.logger.error "ERROR: no such mode - '#{mode}'"
  end      
end

.bot(args) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/begin/bot.rb', line 17

def bot(args)
  args[:globals] = {}
  
  ### LANG
  i18n = Dialog::Lang.initial
  
  ###DRb
  DRb.start_service
  
  begin    
    Dialog::redisDBStore.call(['info', 'clients'])
    Dialog::redisDBCache.call(['info', 'clients']) 
    Dialog::redisDBStat.call(['info', 'clients'])                
  rescue
    Dialog.logger.error "No Redis connection!"
    sleep(2) 
    retry
  end
  
  ##Sidekiq
  Sidekiq.configure_client do |config|
    config.redis = { path: Dialog.config.db.redis_url, db: Dialog.config.db.redisDBBackground }
  end 
  
  #Dirs
  Dialog.directoriesMustExists
  
  Telegram::Bot::Client.run Dialog.config.secure.token do |bot|
    args[:bot]= bot; args[:bot].freeze
    
    #bot getMe
    Dialog.logger.info 'BotAPI getMe-request started'        
    me = bot.api.send(:getMe)
    Dialog.logger.info 'BotAPI getMe-request completed'     
    
    #bot globals
    args[:globals][:botUsername] = me["result"]["username"]
    args[:globals][:botFirstName] = me["result"]["first_name"]
    args[:globals][:botFirstNameArray] = me["result"]["first_name"].split("\s")
    args[:globals][:tdlibUser] = DRbObject.new_with_uri("drbunix:./_data/tdlib/#{Dialog.config.tdlib.instance}/drb.sock")        
    args[:globals].freeze
    
    DRb.start_service("drbunix:./_data/bot/#{Dialog.config.naming.instance}/drb.sock", bot)
    #DRb.thread.join
    
    #common queue
    args[:queue] = {}
    args[:queue][:threadCommon] = Concurrent::CachedThreadPool.new
    
    #Success
    Dialog.logger.info "Started: Bot named \"#{args[:globals][:botUsername]}\", instance=\"#{Dialog.config.naming.instance}\", interface=\"#{Dialog.config.naming.interface}\", ID=\"#{Dialog.config.naming.id}\", loglevel=\"#{Dialog.config.log.base}\""
    
    begin        
      bot.listen do |rmsg|
        args[:rmsg] = rmsg
        Dialog.clear(args) 
        Dialog.clearApi(args)
        args[:perf] = {init: Time.now}
          if args[:rmsg].respond_to?(:from)
            fromId = args[:rmsg][:from][:id]
            args[:queue][fromId] ||= {}
            args[:queue][fromId][:thread] = Concurrent::ImmediateExecutor.new unless args[:queue][fromId][:thread]
            args[:queue][fromId][:thread].post do
              runMessage(args)
            end
          else
            Concurrent::Future.execute(executor: args[:queue][:threadCommon]) do
              runMessage(args)
            end                
          end

      end
      rescue
#         rescue Exception => @e
      retry
#           Dialog.logger.error "ERROR - #{@e.inspect}\n\n Backtrace:\n #{@e.backtrace.join("\n\t")}\n \
#           MMSG:\n#{args[:mmsg]}\n" if @e             
    end        
  end
end

.checkEnv(env, val, err = []) ⇒ Object



20
21
22
23
24
25
26
27
28
29
# File 'lib/configuration.rb', line 20

def self.checkEnv(env, val, err=[])
  if ENV[env].nil?
    case val
      when true;  res = true  
      when false; res = false && err << "There is no #{env} in envs"
      else        res = val 
    end
  else res = ENV[env]; end
  return res
end

.clear(args) ⇒ Object



29
30
31
32
# File 'lib/begin/_pre_bot.rb', line 29

def clear(args)
  args[:x] = {metamess: {}, data: {}, labels: {}, send: {}, exec: {}}
  args[:smsg] = {}
end

.clearApi(args) ⇒ Object



39
40
41
# File 'lib/begin/_pre_bot.rb', line 39

def clearApi(args)
  args[:api] = {}
end

.createObject



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/dialog_ruby.rb', line 16

def create
  Encoding.default_internal = Encoding::UTF_8
  Encoding.default_external = Encoding::UTF_8
  
  version = RUBY_VERSION.split('.').map { |x| x.to_i }
  if (version <=> [2, 4, 9]) >= 1
    require_relative './require.rb'
    _require_min
    Dialog::Triggers.send("trigger_#{Dialog.config.run.scope}".to_sym)
  else
    puts "Minimum required Ruby version - 2.5.0"
  end
end

.dialectDriven(args) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/begin/_main.rb', line 42

def dialectDriven(args)
  require 'dialect_lookup'
  state = {
    dialectFolder:  Dialog.config.naming.interface, 
    myAppName:      Dialog.config.naming.app, 
    sqlite:         Dialog.config.dialect.sqlite, 
    json:           Dialog.config.dialect.json
  }
  ::Dialect::Lookup.new.run(state)
#       File.delete(Dialog.config.dialect.sqlite)
end

.directoriesMustExistsObject



34
35
36
37
# File 'lib/begin/_pre_bot.rb', line 34

def directoriesMustExists
   FileUtils.mkdir_p("#{Dialog.config.path.dialogData}/#{Dialog.config.run.mode}/#{Dialog.config.naming.instance}")      
   FileUtils.mkdir_p("#{Dialog.config.path.dialogTmpfiles}")
end

.getDialog_rubyPathObject



18
# File 'lib/configuration.rb', line 18

def self.getDialog_rubyPath; return File.dirname(__FILE__);  end

.getDialogPathObject



17
# File 'lib/configuration.rb', line 17

def self.getDialogPath; return @dialogPath;  end

.jsonDriven(args, type) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/begin/_main.rb', line 55

def jsonDriven(args, type)
  FileUtils.rm_rf(Dir.glob("#{Dialog.config.path.dialogRender}/code_#{type}/*.rb"))     
  args[:dialect] = {}      
  
  json = Dialog.config.dialect.json
  if File.file?(json)
    jsonLoad = Oj.load(File.read(json), symbol_keys: true)
    args[:dialect] = jsonLoad[:stages][Dialog.config.naming.interface.to_sym]
    Dialog::Dialect.run(args, type)

    args[:dialect] ={} 
    args[:tmp] = {}      
    Dir.glob(File.join("#{Dialog.config.path.dialogRender}/code_#{type}/**", "*.rb")).sort.each{|f| require f}
    Dialog.logger.info "Rendered bot code is ok"    
  else
    Dialog.logger.info "No JSON to render, trying to export"
    begin
      trigger_start('dialect')
    rescue
      Dialog.logger.error "Seems like no Dialect DB, exiting! Please upload valid JSON or use a valid Dialect DB"          
      exit(false)
    end
  end
end

.loggerObject



15
16
17
# File 'lib/tooling/log.rb', line 15

def self.logger
  @logger ||= Log.new(Dialog.config.log.base)
end

.perf(perf) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/begin/_pre_bot.rb', line 44

def perf(perf)
  a = []
  a << "mmsg: #{perf[:metamess] - perf[:init]}s"
  if perf.has_key?(:preApiAction)
    a << "canvas: #{perf[:preApiAction] - perf[:metamess]}s"        
    a << "ApiAction in canvas: #{perf[:postApiAction] - perf[:preApiAction]}s"  
  else
    a << "canvas: #{perf[:canvas] - perf[:metamess]}s"          
  end
  a << "statistics: #{perf[:statistics] - perf[:canvas]}s" if perf.has_key?(:statistics)    
  a << "full: #{perf[:fullend] - perf[:init]}s"  
end

.redisDBCacheObject



21
22
23
# File 'lib/begin/_pre_bot.rb', line 21

def redisDBCache
  @redisDBCache ||= Redis.new(path: Dialog.config.db.redis_url, db: Dialog.config.db.redisDBCache)
end

.redisDBStatObject



25
26
27
# File 'lib/begin/_pre_bot.rb', line 25

def redisDBStat
  @redisDBStat ||= Redis.new(path: Dialog.config.db.redis_url, db: Dialog.config.db.redisDBStat)
end

.redisDBStoreObject



17
18
19
# File 'lib/begin/_pre_bot.rb', line 17

def redisDBStore
  @redisDBStore ||= Redis.new(path: Dialog.config.db.redis_url, db: Dialog.config.db.redisDBStore)
end

.runMessage(args) ⇒ Object



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/begin/bot.rb', line 99

def runMessage(args)      
    begin
#           Dialog.logger.debug "######### - REDIS STAT:\n #{Dialog::redisDBCache.call(['client', 'list'])}\n\n"
      Dialog::Metamess.firstpoint(args)
      Dialog::Statistics.general(args)
      args[:perf][:statistics] = Time.now                               
      args[:perf][:fullend] = Time.now                     
      Dialog.logger.info("## PERF: #{perf(args[:perf]).join(", ")}")  
      
    rescue Exception => @e
      Dialog.logger.error "ERROR - #{@e.inspect}\n\n Backtrace:\n #{@e.backtrace.join("\n\t")}\n \
      MMSG:\n#{args[:mmsg]}\n
      RMSG:\n#{args[:rmsg].to_hash}\n" if @e
      args[:bot].api.send("sendMessage".to_sym, {chat_id: Dialog.config.monitoring.channel, disable_notification: true, text: @e}) unless Dialog.config.monitoring.channel.nil?
      raise
    end
end

.start_background(args) ⇒ Object



16
17
18
19
20
# File 'lib/begin/background.rb', line 16

def start_background(args)
  exec("#{Dir.home}/.gem/ruby/2.5.0/bin/sidekiq", "-r", "#{Dialog.config.path.dialog_ruby}/background/_init.rb")
#       require_relative "#{Dir.home}/.gem/ruby/2.5.0/gems/sidekiq-5.2.2/lib/sidekiq/cli"

end

.start_tdlib(args) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/begin/tdlib.rb', line 16

def start_tdlib(args)
  require 'tdlib-ruby'
  require 'drb/drb'

  args[:globals] = {}
  Dir.glob(File.join("#{Dialog.config.path.dialog_rubyLib}/tdlib/**", "*.rb")).each{|f| require f}      
  unless File.exists?("#{Dialog.config.path.dialogData}/tdlib/#{Dialog.config.naming.instance}/td.binlog")
      Dialog.logger.error "ERROR: please make init of the '#{init}' using 'ruby dialog.rb init #{init}"
      exit(false)
  end
  sess = Dialog::TDLib.tdlibInit
  sess.on_ready do |client|
    a = client.fetch('@type' => 'getMe')
    args[:globals][:cliId] = a['id'].to_i
  end  

  DRb.start_service("drbunix:./_data/tdlib/#{Dialog.config.naming.instance}/drb.sock", sess)
  DRb.thread.join
end