s41c 0.0.2 → 0.0.4
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.
- data/README.md +52 -26
- data/lib/s41c/client.rb +12 -23
- data/lib/s41c/sandbox.rb +32 -0
- data/lib/s41c/server.rb +47 -57
- data/lib/s41c/utils.rb +19 -4
- data/lib/s41c/version.rb +1 -1
- data/lib/s41c.rb +1 -1
- metadata +3 -3
- data/s41c-0.0.1.gem +0 -0
data/README.md
CHANGED
@@ -16,21 +16,29 @@ TCP-socket-сервер и клиент для платформы "1С:Пред
|
|
16
16
|
|
17
17
|
### Пример использования
|
18
18
|
|
19
|
-
|
19
|
+
#### Сервер
|
20
|
+
|
21
|
+
Запустить сервер для 1C:Предприятия 7.7 (сетевая версия) на localhost:1421
|
22
|
+
и использовать базу "C:\Base\"
|
20
23
|
|
21
24
|
require 's41c'
|
22
25
|
|
23
26
|
server = S41C::Server.new
|
27
|
+
server.db('C:\Base\\')
|
24
28
|
server.start
|
25
29
|
|
26
30
|
Или чуть сложнее: запустить сервер для 1С:Предприятия (локальная версия) на
|
27
|
-
127.0.0.1:2000,
|
28
|
-
|
31
|
+
127.0.0.1:2000, использовать базу "C:\Base\", при подключении требовать логин
|
32
|
+
"username" и пароль "password", писать лог в c:\server.log и записать время
|
33
|
+
остановки сервера в файл
|
29
34
|
|
30
35
|
require 's41c'
|
31
36
|
|
32
37
|
server = S41C::Server.new('127.0.0.1', 2000, 'c:\server.log')
|
33
|
-
server.
|
38
|
+
server.ole_name = 'V77L.Application'
|
39
|
+
server.db('C:\Base\\')
|
40
|
+
|
41
|
+
server.login('username', 'password')
|
34
42
|
|
35
43
|
server.at_exit do
|
36
44
|
File.open('c:\server_stoped_at.txt', 'w') { |f| f.puts Time.now }
|
@@ -38,38 +46,56 @@ TCP-socket-сервер и клиент для платформы "1С:Пред
|
|
38
46
|
|
39
47
|
server.start
|
40
48
|
|
41
|
-
|
42
|
-
|
43
|
-
можно
|
49
|
+
#### Клиент
|
50
|
+
|
51
|
+
При подключении можно указать хост и порт сервера (если не указаны, будут
|
52
|
+
использоваться localhost:1421), а также данные для авторизации. После
|
53
|
+
подключения на сервер передаётся руби-код в виде строки, который и выполняет все,
|
54
|
+
что нам нужно
|
55
|
+
|
56
|
+
require 's41c'
|
57
|
+
|
58
|
+
client = S41C::Client.new('127.0.0.1', 2000)
|
59
|
+
client.login('username', 'password')
|
60
|
+
|
61
|
+
response = client.eval %{
|
44
62
|
|
45
|
-
|
46
|
-
=> "utf8-\xD1\x81\xD1\x82\xD1\x80\xD0\xBE\xD0\xBA\xD0\xB0"
|
63
|
+
spr = @ole.CreateObject('Справочник.Товары')
|
47
64
|
|
48
|
-
|
49
|
-
|
65
|
+
if spr.invoke('НайтиПоНаименованию', 'Название товара') == 1.0
|
66
|
+
item = spr.invoke('ТекущийЭлемент')
|
67
|
+
item_id = get_1c_id(item)
|
68
|
+
expr = 'КакаяНибудьФункция(ЗначениеИзСтрокиВнутр(' + item_id + '))'
|
69
|
+
result = @ole.EvalExpr(expr)
|
70
|
+
end
|
50
71
|
|
51
|
-
|
52
|
-
=> "utf8-строка"
|
72
|
+
to_utf8(result)
|
53
73
|
|
54
|
-
|
74
|
+
}
|
55
75
|
|
56
|
-
|
57
|
-
|
58
|
-
'connect|/d c:\1c\\'
|
76
|
+
puts response
|
77
|
+
client.disconnect
|
59
78
|
|
60
|
-
|
61
|
-
|
62
|
-
'eval_expr|ОсновнойЯзык()'
|
79
|
+
Внутри кода доступен объект @ole, который и является инстансом 1С. У него есть
|
80
|
+
3 метода
|
63
81
|
|
64
|
-
*
|
82
|
+
* CreateObject - создает объект агрегатного типа данных 1С:Предприятия и
|
83
|
+
возвращает ссылку на него.
|
65
84
|
|
66
|
-
|
85
|
+
* EvalExpr - вычислияет выражение системы 1С:Предприятие и возвращает результат
|
86
|
+
вычисления
|
67
87
|
|
68
|
-
*
|
88
|
+
* ExecuteBatch - выполняет последовательность операторов системы
|
89
|
+
1С:Предприятие и возвращает статус выполнения (true/false)
|
69
90
|
|
70
|
-
|
91
|
+
Вызов функций и процедур созданных объектов осуществляется с помощью метода
|
92
|
+
'invoke', которому в качестве первого аргумента передаётся название
|
93
|
+
функции/процедуры, а последующих - параметры.
|
71
94
|
|
72
|
-
|
73
|
-
* 'shutdown' - остановить сервер
|
95
|
+
Также достпен ряд вспомогательных функций
|
74
96
|
|
97
|
+
* to_bin - переводит utf-строку в бинарный формат
|
98
|
+
* to_utf8 - переводит бинарную или строку из 1С в utf-8
|
99
|
+
* get_1c_id - обертка над 1С-функцией 'ЗначениеВСтрокуВнутр', возращает
|
100
|
+
строковый идентификатор объекта.
|
75
101
|
|
data/lib/s41c/client.rb
CHANGED
@@ -4,6 +4,8 @@ module S41C
|
|
4
4
|
|
5
5
|
class Client
|
6
6
|
|
7
|
+
include S41C::Utils
|
8
|
+
|
7
9
|
def initialize(host='localhost', port=1421)
|
8
10
|
require 'net/telnet'
|
9
11
|
|
@@ -16,6 +18,8 @@ module S41C
|
|
16
18
|
def login(username, password = nil)
|
17
19
|
@login = username.nil? || username.empty? ? nil : username
|
18
20
|
@password = password
|
21
|
+
|
22
|
+
self
|
19
23
|
end # login
|
20
24
|
|
21
25
|
def errors
|
@@ -23,25 +27,13 @@ module S41C
|
|
23
27
|
end # errors
|
24
28
|
|
25
29
|
def connect(options)
|
26
|
-
cmd "connect
|
30
|
+
cmd "connect\0#{options}"
|
27
31
|
end # connect
|
28
32
|
|
29
33
|
def ping
|
30
34
|
cmd "ping"
|
31
35
|
end # ping
|
32
36
|
|
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
37
|
def disconnect
|
46
38
|
cmd "disconnect"
|
47
39
|
end # disconnect
|
@@ -50,6 +42,10 @@ module S41C
|
|
50
42
|
cmd "shutdown"
|
51
43
|
end # shutdown
|
52
44
|
|
45
|
+
def eval(code)
|
46
|
+
cmd "eval\0\n#{code}\nend_of_code"
|
47
|
+
end
|
48
|
+
|
53
49
|
private
|
54
50
|
|
55
51
|
def conn
|
@@ -77,21 +73,14 @@ module S41C
|
|
77
73
|
|
78
74
|
def cmd(str)
|
79
75
|
return @errors unless conn
|
80
|
-
parse @client.cmd(
|
76
|
+
parse @client.cmd(to_bin(str))
|
81
77
|
end # cmd
|
82
78
|
|
83
79
|
def parse(response)
|
84
|
-
resp =
|
85
|
-
|
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
|
80
|
+
resp = to_utf8(response)
|
81
|
+
resp.lines.first.chomp
|
92
82
|
end # parse
|
93
83
|
|
94
84
|
end # Client
|
95
85
|
|
96
86
|
end # S41C
|
97
|
-
|
data/lib/s41c/sandbox.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module S41C
|
4
|
+
|
5
|
+
class Sandbox
|
6
|
+
|
7
|
+
include S41C::Utils
|
8
|
+
|
9
|
+
def initialize(ole, code)
|
10
|
+
@ole = ole
|
11
|
+
code.untaint
|
12
|
+
@code = proc {
|
13
|
+
$SAFE = 3
|
14
|
+
instance_eval code, __FILE__, __LINE__
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def eval_code
|
19
|
+
begin
|
20
|
+
@code.call
|
21
|
+
rescue WIN32OLERuntimeError => e
|
22
|
+
"Error: #{to_utf8(e.message)}"
|
23
|
+
rescue Exception => e
|
24
|
+
"Error: #{e.message}"
|
25
|
+
rescue => e
|
26
|
+
"Error: #{e.message} from #{__FILE__}:#{__LINE__}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end # S41C
|
data/lib/s41c/server.rb
CHANGED
@@ -4,27 +4,45 @@ module S41C
|
|
4
4
|
|
5
5
|
class Server
|
6
6
|
|
7
|
+
include S41C::Utils
|
8
|
+
|
7
9
|
def initialize(host='localhost', port=1421, log_file=nil)
|
10
|
+
require 'socket'
|
8
11
|
require 'win32ole'
|
9
12
|
|
10
13
|
@host, @port = host, port
|
11
14
|
@logger = log_file ? ::STDOUT.reopen(log_file, 'a') : ::STDOUT
|
12
|
-
@
|
15
|
+
@ole_name = 'V77.Application'
|
16
|
+
|
13
17
|
end # initialize
|
14
18
|
|
15
|
-
def
|
19
|
+
def login(username, password)
|
16
20
|
@login = username
|
17
21
|
@password = password
|
18
|
-
end # login_info
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
self
|
24
|
+
end # login
|
25
|
+
|
26
|
+
def db(database, user=nil, password=nil)
|
27
|
+
@conn_options = "/d #{database}"
|
28
|
+
@conn_options << " /n #{user}" if user
|
29
|
+
@conn_options << " /p #{password}" if password
|
30
|
+
|
31
|
+
self
|
32
|
+
end # db
|
33
|
+
|
34
|
+
def ole_name=(name)
|
35
|
+
@ole_name = name
|
36
|
+
|
37
|
+
self
|
38
|
+
end # ole_name=
|
23
39
|
|
24
40
|
def at_exit(&block)
|
25
41
|
::Kernel::at_exit do
|
26
42
|
yield
|
27
43
|
end
|
44
|
+
|
45
|
+
self
|
28
46
|
end # at_exit
|
29
47
|
|
30
48
|
def start
|
@@ -36,6 +54,8 @@ module S41C
|
|
36
54
|
}
|
37
55
|
end
|
38
56
|
|
57
|
+
connect_to_1c
|
58
|
+
|
39
59
|
server = TCPServer.open(@host, @port)
|
40
60
|
|
41
61
|
log "*** Server has been started on #{@host}:#{@port}"
|
@@ -53,7 +73,7 @@ module S41C
|
|
53
73
|
private
|
54
74
|
|
55
75
|
def read_response(session)
|
56
|
-
|
76
|
+
to_utf8(session.gets || '').chomp
|
57
77
|
end # read_response
|
58
78
|
|
59
79
|
def log(msg)
|
@@ -61,52 +81,27 @@ module S41C
|
|
61
81
|
@logger.flush
|
62
82
|
end # log
|
63
83
|
|
64
|
-
def connect_to_1c
|
65
|
-
@conn.ole_free unless @conn.nil?
|
66
|
-
options = args.shift || ''
|
84
|
+
def connect_to_1c
|
67
85
|
begin
|
68
|
-
@
|
69
|
-
|
70
|
-
@
|
71
|
-
|
86
|
+
@ole = ::WIN32OLE.new(@ole_name)
|
87
|
+
@conn = @ole.Initialize(
|
88
|
+
@ole.RMTrade,
|
89
|
+
(@conn_options),
|
72
90
|
''
|
73
91
|
)
|
74
|
-
|
92
|
+
rescue WIN32OLERuntimeError => e
|
93
|
+
@conn = nil
|
94
|
+
log "*** Error: #{to_utf8(e.message)}"
|
75
95
|
rescue => e
|
76
|
-
|
77
|
-
"Error: #{e.message}"
|
96
|
+
log "*** Error: #{e.message} from #{__FILE__}:#{__LINE__}"
|
78
97
|
end
|
79
98
|
end
|
80
99
|
|
81
|
-
def
|
100
|
+
def eval_code(code)
|
82
101
|
return "Error: not connected" unless @conn
|
83
|
-
obj_name = args.shift || ''
|
84
|
-
begin
|
85
|
-
@obj = @conn.CreateObject(obj_name)
|
86
|
-
"Created"
|
87
|
-
rescue => e
|
88
|
-
"Error: #{e.message}"
|
89
|
-
end
|
90
|
-
end
|
91
102
|
|
92
|
-
|
93
|
-
|
94
|
-
expr = args.shift || ''
|
95
|
-
begin
|
96
|
-
@conn.invoke("EvalExpr", expr).to_s
|
97
|
-
rescue => e
|
98
|
-
"Error: #{e.message}"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def invoke(args)
|
103
|
-
return "Error: working object not found. You must create it before" unless @conn
|
104
|
-
begin
|
105
|
-
@obj.invoke(*args).to_s.encode("UTF-8", "IBM866", :invalid => :replace, :replace => "?")
|
106
|
-
rescue => e
|
107
|
-
"Error: #{e.message}"
|
108
|
-
end
|
109
|
-
end
|
103
|
+
S41C::Sandbox.new(@ole, code).eval_code
|
104
|
+
end # eval_code
|
110
105
|
|
111
106
|
def main_loop(server)
|
112
107
|
loop do
|
@@ -138,20 +133,15 @@ module S41C
|
|
138
133
|
end
|
139
134
|
|
140
135
|
loop {
|
141
|
-
args =
|
136
|
+
args = read_response(session).split("\0")
|
142
137
|
cmd = args.shift
|
143
138
|
case cmd
|
144
|
-
when "
|
145
|
-
|
146
|
-
session.
|
147
|
-
|
148
|
-
|
149
|
-
session.puts
|
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))
|
139
|
+
when "eval"
|
140
|
+
code = ""
|
141
|
+
while !(part = session.gets)['end_of_code']
|
142
|
+
code << to_utf8(part)
|
143
|
+
end
|
144
|
+
session.puts to_bin(eval_code(code))
|
155
145
|
session.puts "+OK"
|
156
146
|
when "ping"
|
157
147
|
session.puts "pong"
|
@@ -165,7 +155,7 @@ module S41C
|
|
165
155
|
session.close
|
166
156
|
exit
|
167
157
|
else
|
168
|
-
session.puts "Bad command"
|
158
|
+
session.puts "Bad command: `#{cmd}`"
|
169
159
|
session.puts "+OK"
|
170
160
|
end
|
171
161
|
}
|
data/lib/s41c/utils.rb
CHANGED
@@ -1,15 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module S41C
|
2
4
|
|
3
5
|
module Utils
|
4
6
|
|
5
|
-
def
|
6
|
-
str.force_encoding("BINARY")
|
7
|
+
def to_bin(str)
|
8
|
+
str.to_s.force_encoding("BINARY")
|
7
9
|
end
|
8
10
|
|
9
|
-
def
|
10
|
-
str.
|
11
|
+
def to_utf8(str)
|
12
|
+
return unless str.is_a?(String)
|
13
|
+
if str.encoding.to_s == "IBM866"
|
14
|
+
str.to_s.encode("UTF-8", "IBM866", :invalid => :replace, :replace => "?")
|
15
|
+
else
|
16
|
+
str.to_s.force_encoding("UTF-8")
|
17
|
+
end
|
11
18
|
end
|
12
19
|
|
20
|
+
def get_1c_id(obj)
|
21
|
+
return false unless @ole
|
22
|
+
|
23
|
+
str_id = @ole.invoke('ЗначениеВСтрокуВнутр', obj)
|
24
|
+
escaped_str_id = "\"#{str_id.gsub('"', '""')}\""
|
25
|
+
|
26
|
+
end # get_1c_id
|
27
|
+
|
13
28
|
end # Utils
|
14
29
|
|
15
30
|
end # S41C
|
data/lib/s41c/version.rb
CHANGED
data/lib/s41c.rb
CHANGED
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.
|
4
|
+
version: 0.0.4
|
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-
|
12
|
+
date: 2012-03-24 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: TCP-socket сервер и клиент для платформы "1С:Предприятие"
|
15
15
|
email:
|
@@ -20,8 +20,8 @@ extra_rdoc_files: []
|
|
20
20
|
files:
|
21
21
|
- LICENSE.BSD
|
22
22
|
- s41c.gemspec
|
23
|
-
- s41c-0.0.1.gem
|
24
23
|
- README.md
|
24
|
+
- lib/s41c/sandbox.rb
|
25
25
|
- lib/s41c/version.rb
|
26
26
|
- lib/s41c/utils.rb
|
27
27
|
- lib/s41c/server.rb
|
data/s41c-0.0.1.gem
DELETED
Binary file
|