ass_maintainer-info_base 0.1.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,80 @@
1
+ module AssMaintainer
2
+ class InfoBase
3
+ module ServerIb
4
+ require 'ass_ole'
5
+ module EnterpriseServers
6
+ require 'ass_maintainer/info_base/server_ib/enterprise_servers/support'
7
+ require 'ass_maintainer/info_base/server_ib/enterprise_servers/server_agent'
8
+ require 'ass_maintainer/info_base/server_ib/enterprise_servers/cluster'
9
+ require 'ass_maintainer/info_base/server_ib/enterprise_servers/wp_connection'
10
+
11
+ # @api private
12
+ # Wrappers for 1C OLE objects
13
+ module Wrappers
14
+ # @api private
15
+ # Wrapper for 1C:Enterprise +IWorkingProcessInfo+ ole object
16
+ class WorkingProcessInfo
17
+ include Support::SendToOle
18
+ attr_reader :ole, :cluster, :sagent, :connection
19
+ def initialize(ole, cluster)
20
+ @ole, @cluster, @sagent = ole, cluster, cluster.sagent
21
+ end
22
+
23
+ def connect(infobase_wrapper)
24
+ WpConnection.new(self).connect(infobase_wrapper)
25
+ end
26
+
27
+ # Return +true+ if TCP port available on server
28
+ def ping?
29
+ tcp_ping.ping?
30
+ end
31
+
32
+ require 'net/ping/tcp'
33
+ # @return [Net::Ping::TCP] instance
34
+ def tcp_ping
35
+ @tcp_ping ||= Net::Ping::TCP.new(hostName, mainPort)
36
+ end
37
+ end
38
+
39
+ # @api private
40
+ # Wrapper for 1C:Enterprise +ISessionInfo+ ole object
41
+ class Session
42
+ include Support::SendToOle
43
+
44
+ # @api private
45
+ # @return +ISessionInfo+ ole object
46
+ attr_reader :ole
47
+
48
+ # @api private
49
+ # @return [EnterpriseServers::Cluster] cluster where session
50
+ # registred
51
+ attr_reader :cluster
52
+
53
+ # @api private
54
+ # @return [EnterpriseServers::ServerAgent] 1C server where session
55
+ # registred
56
+ attr_reader :sagent
57
+
58
+ # @api private
59
+ def initialize(ole, cluster)
60
+ @ole, @cluster, @sagent = ole, cluster, cluster.sagent
61
+ end
62
+
63
+ # Terminate session
64
+ def terminate
65
+ sagent.TerminateSession(cluster.ole, ole)
66
+ rescue WIN32OLERuntimeError
67
+ end
68
+
69
+ # @return [InfoBase::Session]
70
+ # @param infobase [InfoBase] instance
71
+ def to_session(infobase)
72
+ InfoBase::Session
73
+ .new SessionId(), AppId(), Host(), UserName(), infobase
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,114 @@
1
+ module AssMaintainer
2
+ class InfoBase
3
+ module ServerIb
4
+ module EnterpriseServers
5
+ # @api private
6
+ # Object descrbed 1C cluster
7
+ class Cluster
8
+ # Deafult 1C:Enterprise cluster TCP port
9
+ DEF_PORT = '1541'
10
+
11
+ include Support::ServerConnection
12
+ include Support::SendToOle
13
+ include Support::InfoBaseFind
14
+
15
+ # @return [String] {DEF_PORT}
16
+ def default_port
17
+ DEF_PORT
18
+ end
19
+
20
+ # Attache cluster into server agent
21
+ # @param agent [ServerAgent]
22
+ # @raise (see #authenticate)
23
+ def attach(agent)
24
+ @sagent = agent unless @sagent
25
+ ole_set
26
+ authenticate
27
+ end
28
+
29
+ # @return [ServerAgent] which cluster attached
30
+ # @raise [RuntimeError] unless cluster attached
31
+ def sagent
32
+ fail 'Cluster must be attachet to ServerAgent' unless @sagent
33
+ @sagent
34
+ end
35
+
36
+ # @return +IClusterInfo+ ole object
37
+ # @raise [RuntimeError] if cluster not found on {#sagent} server
38
+ def ole
39
+ fail ArgumentError, "Cluster `#{host_port}'"\
40
+ " not found on server `#{sagent.host_port}'" unless @ole
41
+ @ole
42
+ end
43
+
44
+ # Authenticate cluster user
45
+ # @raise (see #ole)
46
+ def authenticate
47
+ sagent.Authenticate(ole, user.to_s, password.to_s)
48
+ self
49
+ end
50
+
51
+ def ole_set
52
+ @ole = sagent.cluster_find(host, port)
53
+ ole
54
+ end
55
+ private :ole_set
56
+
57
+ # @return [Array<WIN32OLE>] aray of +IInfoBaseShort+ ole objects
58
+ # registred in cluster
59
+ # @raise (see #ole)
60
+ # @raise (see #sagent)
61
+ def infobases
62
+ sagent.GetInfoBases(ole)
63
+ end
64
+
65
+ # @return [nil Array<Wrappers::Session>] sessions for infobase
66
+ # runned in cluster. +nil+ if infobase +ib_name+ not registred in
67
+ # cluster.
68
+ # @param ib_name [String] infobase name
69
+ # @raise (see #sagent)
70
+ def infobase_sessions(ib_name)
71
+ ib = infobase_find(ib_name)
72
+ return unless ib
73
+ sagent.GetInfoBaseSessions(ole, ib).map do |s|
74
+ Wrappers::Session.new(s, self)
75
+ end
76
+ end
77
+
78
+ # All Working processes in cluster
79
+ # @return [Array<Wrappers::WorkingProcessInfo]
80
+ def wprocesses
81
+ sagent.GetWorkingProcesses(ole).map do |wpi|
82
+ Wrappers::WorkingProcessInfo.new(wpi, self)
83
+ end
84
+ end
85
+
86
+ # Connect to working process
87
+ # @return [WpConnection] object for comunication with 1C Working
88
+ # process
89
+ def wp_connection(infobase_wrapper)
90
+ if !@wp_connection.nil? && !@wp_connection.ping?
91
+ @wp_connection = nil
92
+ end
93
+ @wp_connection ||= alive_wprocess_get.connect(infobase_wrapper)
94
+ end
95
+
96
+ def alive_wprocess_get
97
+ wp_info = wprocesses.select{|p| p.Running == 1 && p.ping?}[0]
98
+ fail 'No alive working processes found' unless wp_info
99
+ wp_info
100
+ end
101
+
102
+ # Delete infobase
103
+ # @param infobase_wrapper [InfoBaseWrapper] infobase wrapper
104
+ # @param mode [Symbol] defines what should do with
105
+ # infobase's database. See {WpConnection::DROP_MODES}
106
+ def drop_infobase!(infobase_wrapper, mode)
107
+ wp_connection(infobase_wrapper).drop_infobase!(mode)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
@@ -0,0 +1,91 @@
1
+ module AssMaintainer
2
+ class InfoBase
3
+ module ServerIb
4
+ module EnterpriseServers
5
+ # @api private
6
+ # Object descrbed 1C server agent connection.
7
+ # @example
8
+ # # Get 1C:Eneterprise server agent connection object and connect
9
+ # # to net service
10
+ # sagent = ServerAgent.new('localhost:1540', 'admin', 'password')
11
+ # .connect('~> 8.3.8.0')
12
+ #
13
+ # # Working with server agent connection
14
+ # sagent.ConnectionString #=> "tcp://localhost:1540"
15
+ # cl = sagent.cluster_find 'localhost', '1542'
16
+ #
17
+ # # Close connection
18
+ # sagent.disconnect
19
+ #
20
+ module ServerAgent
21
+ include Support::ServerConnection
22
+ include Support::OleRuntime
23
+ include Support::Reconnect
24
+
25
+ # Make new object of anonymous class which included this module.
26
+ def self.new(host_port, user, password)
27
+ Class.new do
28
+ include ServerAgent
29
+ end.new host_port, user, password
30
+ end
31
+
32
+ # @return [String] wrapper for {InfoBase::DEFAULT_SAGENT_PORT}
33
+ def default_port
34
+ InfoBase::DEFAULT_SAGENT_PORT
35
+ end
36
+
37
+ def runtime_type
38
+ :agent
39
+ end
40
+
41
+ # Connect to 1C:Eneterprise server via OLE
42
+ # @note while connecting in instance class will be included
43
+ # {.runtime_new} module
44
+ # @param platform_require [String Gem::Requirement]
45
+ # 1C:Eneterprise version required
46
+ # @return +self+
47
+ def connect(platform_require)
48
+ _connect(host_port, platform_require)
49
+ end
50
+
51
+ # Authenticate {#user}
52
+ # @raise if not connected
53
+ def authenticate
54
+ AuthenticateAgent(user.to_s, password.to_s) if\
55
+ connected? && !authenticate?
56
+ end
57
+
58
+ # True if #{user} authenticate
59
+ def authenticate?
60
+ return false unless connected?
61
+ begin
62
+ ole_connector.GetAgentAdmins
63
+ rescue WIN32OLERuntimeError
64
+ return false
65
+ end
66
+ true
67
+ end
68
+
69
+ # @return [nil WIN32OLE] +IClusterInfo+ ole object
70
+ # @raise if not connected
71
+ def cluster_find(host, port)
72
+ reconnect
73
+ GetClusters().find do |cl|
74
+ cl.HostName.upcase == host.upcase && cl.MainPort == port.to_i
75
+ end
76
+ end
77
+
78
+ def platform_require
79
+ return unless connected?
80
+ ole_connector.send(:__ole_binary__).requirement.to_s
81
+ end
82
+
83
+ def _reconnect_required?
84
+ getClusters.empty?
85
+ end
86
+ private :_reconnect_required?
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,200 @@
1
+ module AssMaintainer
2
+ class InfoBase
3
+ module ServerIb
4
+ module EnterpriseServers
5
+ # @api private
6
+ # Mixins
7
+ module Support
8
+ # Mixin for redirect +method_missing+ to +ole+ object
9
+ module SendToOle
10
+ def method_missing(m, *args)
11
+ ole.send m, *args
12
+ end
13
+ end
14
+
15
+ # Ole runtime mixin
16
+ module OleRuntime
17
+ require 'ass_ole'
18
+ # Close connection with 1C:Enterprise server
19
+ def disconnect
20
+ runtime_stop
21
+ end
22
+
23
+ # True if connected
24
+ def connected?
25
+ respond_to?(:ole_runtime_get) && ole_runtime_get.runned?
26
+ end
27
+
28
+ def runtime_stop
29
+ ole_runtime_get.stop if respond_to? :ole_runtime_get
30
+ end
31
+ private :runtime_stop
32
+
33
+ # Include and run {.runtime_new} runtime
34
+ def runtime_run(host_port, platform_require)
35
+ self.class.like_ole_runtime OleRuntime.runtime_new(self) unless\
36
+ respond_to? :ole_runtime_get
37
+ ole_runtime_get.run host_port, platform_require
38
+ end
39
+ private :runtime_run
40
+
41
+ # Make new runtime module +AssOle::Runtimes::Claster::(Agent|Wp)+
42
+ # for access to
43
+ # +AssLauncher::Enterprise::Ole::(AgentConnection|WpConnection)+
44
+ # @param inst [#runtime_type] +#runtime_type+ must returns
45
+ # +:wp+ or +:agent+ values
46
+ # @return [Module]
47
+ def self.runtime_new(inst)
48
+ Module.new do
49
+ is_ole_runtime inst.runtime_type
50
+ end
51
+ end
52
+
53
+ def _connect(host_port, platform_require)
54
+ runtime_run host_port, platform_require unless connected?
55
+ begin
56
+ authenticate unless authenticate?
57
+ rescue
58
+ runtime_stop
59
+ raise
60
+ end
61
+ self
62
+ end
63
+
64
+ def authenticate
65
+ fail 'Abstract method'
66
+ end
67
+
68
+ def authenticate?
69
+ fail 'Abstract method'
70
+ end
71
+ end
72
+
73
+ # Mixin for find infobase per name
74
+ module InfoBaseFind
75
+ def infobases
76
+ fail 'Abstract method'
77
+ end
78
+
79
+ # Searching infobase in {#infobases} array
80
+ # @param ib_name [String] infobase name
81
+ # @return [WIN32OLE] +IInfoBaseShort+ ole object
82
+ # @raise (see #infobases)
83
+ def infobase_find(ib_name)
84
+ infobases.find do |ib|
85
+ ib.Name.upcase == ib_name.upcase
86
+ end
87
+ end
88
+
89
+ # True if infobase registred in cluster
90
+ # @param ib_name [String] infobase name
91
+ # @raise (see #infobase_find)
92
+ def infobase_include?(ib_name)
93
+ !infobase_find(ib_name).nil?
94
+ end
95
+ end
96
+
97
+ # Mixin for reconnect ole runtime
98
+ module Reconnect
99
+ def reconnect
100
+ fail "Serevice #{host_port} not"\
101
+ " available: #{tcp_ping.exception}" unless ping?
102
+ return unless reconnect_required?
103
+ ole_connector.__close__
104
+ ole_connector.__open__ host_port
105
+ end
106
+ private :reconnect
107
+
108
+ def reconnect_required?
109
+ return true unless ole_connector.__opened__?
110
+ begin
111
+ _reconnect_required?
112
+ rescue WIN32OLERuntimeError => e
113
+ return true if e.message =~ %r{descr=10054}
114
+ end
115
+ end
116
+ private :reconnect_required?
117
+
118
+ def _reconnect_required?
119
+ fail 'Abstract method'
120
+ end
121
+ private :_reconnect_required?
122
+ end
123
+
124
+ # @api private
125
+ # Abstract server connection.
126
+ # Mixin for {Cluster} and {ServerAgent}
127
+ module ServerConnection
128
+ # Server user name
129
+ # See {#initialize} +user+ argument.
130
+ # @return [String]
131
+ attr_accessor :user
132
+
133
+ # Server user password
134
+ # See {#initialize} +password+ argument.
135
+ # @return [String]
136
+ attr_accessor :password
137
+
138
+ # Host name
139
+ attr_accessor :host
140
+
141
+ # TCP port
142
+ attr_accessor :port
143
+
144
+ # @param host_port [String] string like a +host_name:port_number+
145
+ # @param user [String] server user name
146
+ # @param password [String] server user password
147
+ def initialize(host_port, user = nil, password = nil)
148
+ fail ArgumentError, 'Host name require' if host_port.to_s.empty?
149
+ @raw_host_port = host_port
150
+ @host = parse_host
151
+ @port = parse_port || default_port
152
+ @user = user
153
+ @password = password
154
+ end
155
+
156
+ # String like a +host_name:port_number+.
157
+ # @return [String]
158
+ def host_port
159
+ "#{host}:#{port}"
160
+ end
161
+
162
+ def parse_port
163
+ p = @raw_host_port.split(':')[1].to_s.strip
164
+ return p unless p.empty?
165
+ end
166
+ private :parse_port
167
+
168
+ def parse_host
169
+ p = @raw_host_port.split(':')[0].to_s.strip
170
+ fail ArgumentError, "Invalid host_name for `#{@raw_host_port}'" if\
171
+ p.empty?
172
+ p
173
+ end
174
+ private :parse_host
175
+
176
+ def default_port
177
+ fail 'Abstract method'
178
+ end
179
+
180
+ # Return +true+ if TCP port available on server
181
+ def ping?
182
+ tcp_ping.ping?
183
+ end
184
+
185
+ require 'net/ping/tcp'
186
+ # @return [Net::Ping::TCP] instance
187
+ def tcp_ping
188
+ @tcp_ping ||= Net::Ping::TCP.new(host, port)
189
+ end
190
+
191
+ def eql?(other)
192
+ host.upcase == other.host.upcase && port == other.port
193
+ end
194
+ alias_method :==, :eql?
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end