s41c 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.BSD ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2012 DansingBytes.ru
2
+ All rights reserved.
3
+
4
+ Author: redfield (up.redfield@gmail.com)
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+ * Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL DansingBytes BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ S41C (Socket for 1C)
2
+ ======
3
+
4
+
5
+ TCP-socket-сервер и клиент для платформы "1С:Предприятие"
6
+
7
+ ### Системные требования
8
+
9
+ * Microsoft Windows семейства NT (32bit)
10
+ * 1С:Предприятие v7
11
+ * [Ruby](http://rubyinstaller.org/downloads/) 1.9.3
12
+
13
+ ### Установка
14
+
15
+ gem install s41c
16
+
17
+ ### Пример использования
18
+
19
+ Запустить сервер для 1C:Предприятия 7.7 (сетевая версия) на localhost:1421
20
+
21
+ require 's41c'
22
+
23
+ server = S41C::Server.new
24
+ server.start
25
+
26
+ Или чуть сложнее: запустить сервер для 1С:Предприятия (локальная версия) на
27
+ 127.0.0.1:2000, писать лог в c:\server.log и записать время остановки
28
+ сервера в файл
29
+
30
+ require 's41c'
31
+
32
+ server = S41C::Server.new('127.0.0.1', 2000, 'c:\server.log')
33
+ server.ole_object = 'V77L.Application'
34
+
35
+ server.at_exit do
36
+ File.open('c:\server_stoped_at.txt', 'w') { |f| f.puts Time.now }
37
+ end
38
+
39
+ server.start
40
+
41
+ После запуска с сервером можно общаться по telnet. Комманды, содержащие не-ASCII
42
+ символы, должны быть utf8-строками переведенными в бинарный формат. В руби это
43
+ можно сделать с помощью метода [String#force_encoding](http://ruby-doc.org/core-1.9.3/String.html#method-i-force_encoding):
44
+
45
+ "utf8-строка".force_encoding("BINARY")
46
+ => "utf8-\xD1\x81\xD1\x82\xD1\x80\xD0\xBE\xD0\xBA\xD0\xB0"
47
+
48
+ Отвечает сервер в том же формате, т.е. на стороне клиента ответ нужно
49
+ преобразовать в utf-строку:
50
+
51
+ "utf8-\xD1\x81\xD1\x82\xD1\x80\xD0\xBE\xD0\xBA\xD0\xB0".force_encoding("UTF-8")
52
+ => "utf8-строка"
53
+
54
+ Список команд:
55
+
56
+ * 'connect|параметры_подключения' - подключиться к базе, например:
57
+
58
+ 'connect|/d c:\1c\\'
59
+
60
+ * 'eval_expr|команда' - выполнить команду
61
+
62
+ 'eval_expr|ОсновнойЯзык()'
63
+
64
+ * 'create|Название.Объекта' - создать объект
65
+
66
+ 'create|Справочник.Товары'
67
+
68
+ * 'invoke|НазваниеМетода|параметры|метода' - выполнить процедуру/функцию для объекта
69
+
70
+ 'invoke|НайтиПоНаименованию|Шляпа с полями'
71
+
72
+ * 'disconnect' - отключиться от 1С
73
+ * 'shutdown' - остановить сервер
74
+
75
+
data/lib/s41c.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'socket'
1
2
  require 's41c/version'
2
3
  require 's41c/utils'
3
4
  require 's41c/server'
data/lib/s41c/client.rb CHANGED
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ module S41C
4
+
5
+ class Client
6
+
7
+ def initialize(host='localhost', port=1421)
8
+ require 'net/telnet'
9
+
10
+ @host, @port = host, port
11
+ @prompt = /^\+OK/n
12
+ @errors = []
13
+
14
+ end # initialize
15
+
16
+ def login(username, password = nil)
17
+ @login = username.nil? || username.empty? ? nil : username
18
+ @password = password
19
+ end # login
20
+
21
+ def errors
22
+ @errors
23
+ end # errors
24
+
25
+ def connect(options)
26
+ cmd "connect|#{options}"
27
+ end # connect
28
+
29
+ def ping
30
+ cmd "ping"
31
+ end # ping
32
+
33
+ def eval_expr(expr)
34
+ cmd "eval_expr|#{expr}"
35
+ end # eval_expr
36
+
37
+ def create(obj_name)
38
+ cmd "create|#{obj_name}"
39
+ end # create
40
+
41
+ def invoke(method_name, *args)
42
+ cmd "invoke|#{method_name}|#{args.join('|')}"
43
+ end # invoke
44
+
45
+ def disconnect
46
+ cmd "disconnect"
47
+ end # disconnect
48
+
49
+ def shutdown
50
+ cmd "shutdown"
51
+ end # shutdown
52
+
53
+ private
54
+
55
+ def conn
56
+ return true if @client
57
+ begin
58
+
59
+ @client = Net::Telnet.new('Host' => @host, 'Port' => @port, "Prompt" => @prompt)
60
+
61
+ if @login
62
+ resp = @client.login(@login, @password)
63
+
64
+ unless resp["success"]
65
+ @errors << "Invalid login or password"
66
+ return false
67
+ end # unless
68
+ end # if
69
+
70
+ return true
71
+
72
+ rescue Errno::ECONNREFUSED => e
73
+ @errors << e.message
74
+ return false
75
+ end
76
+ end # conn
77
+
78
+ def cmd(str)
79
+ return @errors unless conn
80
+ parse @client.cmd(S41C::Utils.to_bin(str))
81
+ end # cmd
82
+
83
+ def parse(response)
84
+ resp = S41C::Utils.to_utf8(response)
85
+ res = []
86
+
87
+ resp.each_line do |line|
88
+ res << line.chomp unless line[@prompt]
89
+ end # each_line
90
+
91
+ res.count > 1 ? res : res.first
92
+ end # parse
93
+
94
+ end # Client
95
+
96
+ end # S41C
97
+
data/lib/s41c/server.rb CHANGED
@@ -2,17 +2,21 @@
2
2
 
3
3
  module S41C
4
4
 
5
- require 'win32ole'
6
- require 'socket'
7
-
8
5
  class Server
9
6
 
10
7
  def initialize(host='localhost', port=1421, log_file=nil)
8
+ require 'win32ole'
9
+
11
10
  @host, @port = host, port
12
11
  @logger = log_file ? ::STDOUT.reopen(log_file, 'a') : ::STDOUT
13
12
  @ole_object = 'V77.Application'
14
13
  end # initialize
15
14
 
15
+ def set_login(username, password)
16
+ @login = username
17
+ @password = password
18
+ end # login_info
19
+
16
20
  def ole_object=(name)
17
21
  @ole_object = name
18
22
  end # ole_object
@@ -37,60 +41,29 @@ module S41C
37
41
  log "*** Server has been started on #{@host}:#{@port}"
38
42
  log "*** Ctrl+C for stopping"
39
43
 
40
- loop do
41
-
42
- begin
43
- session = server.accept_nonblock
44
- rescue IO::WaitReadable, Errno::EINTR
45
- IO.select([server])
46
- retry
47
- end
48
-
49
- session.print "Welcome\r\n"
50
-
51
- loop {
52
- attrs = S41C::Utils.to_utf8(session.gets || '').chomp.split('|')
53
- cmd = attrs.shift
54
- case cmd
55
- when "connect"
56
- session.puts S41C::Utils.to_bin(connect_to_1c(attrs))
57
- session.puts "+OK"
58
- when "create"
59
- session.puts S41C::Utils.to_bin(create(attrs))
60
- session.puts "+OK"
61
- when "eval_expr"
62
- session.puts S41C::Utils.to_bin(eval_expr(attrs))
63
- session.puts "+OK"
64
- when "invoke"
65
- session.puts S41C::Utils.to_bin(invoke(attrs))
66
- session.puts "+OK"
67
- when "disconnect"
68
- session.puts "Goodbye"
69
- session.close
70
- break
71
- when "shutdown"
72
- session.puts "Server is going down now"
73
- session.close
74
- exit
75
- else
76
- session.puts "Bad command"
77
- session.puts "+OK"
78
- end
79
- }
80
-
44
+ begin
45
+ main_loop(server)
46
+ rescue Errno::ECONNABORTED
47
+ log "*** [#{Time.now}] Session aborted"
48
+ retry
81
49
  end
50
+
82
51
  end # start
83
52
 
84
53
  private
85
54
 
55
+ def read_response(session)
56
+ S41C::Utils.to_utf8(session.gets || '').chomp
57
+ end # read_response
58
+
86
59
  def log(msg)
87
60
  @logger.puts msg
88
61
  @logger.flush
89
62
  end # log
90
63
 
91
- def connect_to_1c(attrs)
64
+ def connect_to_1c(args)
92
65
  @conn.ole_free unless @conn.nil?
93
- options = attrs.shift || ''
66
+ options = args.shift || ''
94
67
  begin
95
68
  @conn = ::WIN32OLE.new('V77.Application')
96
69
  res = @conn.Initialize(
@@ -105,9 +78,9 @@ module S41C
105
78
  end
106
79
  end
107
80
 
108
- def create(attrs)
81
+ def create(args)
109
82
  return "Error: not connected" unless @conn
110
- obj_name = attrs.shift || ''
83
+ obj_name = args.shift || ''
111
84
  begin
112
85
  @obj = @conn.CreateObject(obj_name)
113
86
  "Created"
@@ -116,9 +89,9 @@ module S41C
116
89
  end
117
90
  end
118
91
 
119
- def eval_expr(attrs)
92
+ def eval_expr(args)
120
93
  return "Error: not connected" unless @conn
121
- expr = attrs.shift || ''
94
+ expr = args.shift || ''
122
95
  begin
123
96
  @conn.invoke("EvalExpr", expr).to_s
124
97
  rescue => e
@@ -126,15 +99,80 @@ module S41C
126
99
  end
127
100
  end
128
101
 
129
- def invoke(attrs)
102
+ def invoke(args)
130
103
  return "Error: working object not found. You must create it before" unless @conn
131
104
  begin
132
- @obj.invoke(*attrs).to_s.encode("UTF-8", "IBM866", :invalid => :replace, :replace => "?")
105
+ @obj.invoke(*args).to_s.encode("UTF-8", "IBM866", :invalid => :replace, :replace => "?")
133
106
  rescue => e
134
107
  "Error: #{e.message}"
135
108
  end
136
109
  end
137
110
 
111
+ def main_loop(server)
112
+ loop do
113
+
114
+ begin
115
+ session = server.accept_nonblock
116
+ rescue IO::WaitReadable, Errno::EINTR
117
+ IO.select([server])
118
+ retry
119
+ end
120
+
121
+ if @login
122
+ res = true
123
+ session.print "login"
124
+ res = res && (read_response(session) == @login)
125
+ if @password
126
+ session.print "password"
127
+ res = res && (read_response(session) == @password)
128
+ end
129
+
130
+ if res
131
+ session.puts("success")
132
+ session.puts("+OK")
133
+ else
134
+ session.puts "\n\rInvalid login or password"
135
+ session.close
136
+ next
137
+ end # if
138
+ end
139
+
140
+ loop {
141
+ args = S41C::Utils.to_utf8(session.gets || '').chomp.split('|')
142
+ cmd = args.shift
143
+ case cmd
144
+ when "connect"
145
+ session.puts S41C::Utils.to_bin(connect_to_1c(args))
146
+ session.puts "+OK"
147
+ when "create"
148
+ session.puts S41C::Utils.to_bin(create(args))
149
+ session.puts "+OK"
150
+ when "eval_expr"
151
+ session.puts S41C::Utils.to_bin(eval_expr(args))
152
+ session.puts "+OK"
153
+ when "invoke"
154
+ session.puts S41C::Utils.to_bin(invoke(args))
155
+ session.puts "+OK"
156
+ when "ping"
157
+ session.puts "pong"
158
+ session.puts "+OK"
159
+ when "disconnect"
160
+ session.puts "Goodbye"
161
+ session.close
162
+ break
163
+ when "shutdown"
164
+ session.puts "Server is going down now"
165
+ session.close
166
+ exit
167
+ else
168
+ session.puts "Bad command"
169
+ session.puts "+OK"
170
+ end
171
+ }
172
+
173
+ end
174
+ end # main_loop
175
+
138
176
  end # Server
139
177
 
140
178
  end # S41C
data/lib/s41c/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module S41C
2
2
 
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
 
5
5
  end # S41C
data/s41c-0.0.1.gem ADDED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s41c
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-17 00:00:00.000000000 Z
12
+ date: 2012-03-19 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: TCP-socket сервер и клиент для платформы "1С:Предприятие"
15
15
  email:
@@ -18,8 +18,10 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - LICENSE.BSD
21
22
  - s41c.gemspec
22
23
  - s41c-0.0.1.gem
24
+ - README.md
23
25
  - lib/s41c/version.rb
24
26
  - lib/s41c/utils.rb
25
27
  - lib/s41c/server.rb