copper-cti 2.2.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.
- checksums.yaml +7 -0
- data/src/code/CTI/Builder/FileBuilder.rb +36 -0
- data/src/code/CTI/Builder/NullBuilder.rb +29 -0
- data/src/code/CTI/Builder/StreamBuilder.rb +212 -0
- data/src/code/CTI/CTIP2/CTIP2.rb +396 -0
- data/src/code/CTI/CTIP2/Utils.rb +119 -0
- data/src/code/CTI/Driver.rb +70 -0
- data/src/code/CTI/Results/DirectoryResults.rb +31 -0
- data/src/code/CTI/Results/SingleResult.rb +36 -0
- data/src/code/CTI/Session.rb +566 -0
- data/src/code/CTI.rb +53 -0
- metadata +52 -0
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
require File.expand_path('CTIP2/CTIP2', File.dirname(__FILE__))
|
|
2
|
+
require File.expand_path('Builder/FileBuilder', File.dirname(__FILE__))
|
|
3
|
+
require File.expand_path('Results/SingleResult', File.dirname(__FILE__))
|
|
4
|
+
require File.expand_path('Builder/StreamBuilder', File.dirname(__FILE__))
|
|
5
|
+
require File.expand_path('Results/DirectoryResults', File.dirname(__FILE__))
|
|
6
|
+
require "io/nonblock"
|
|
7
|
+
|
|
8
|
+
include CTI::Builder, CTI::Results
|
|
9
|
+
|
|
10
|
+
module CTI
|
|
11
|
+
=begin rdoc
|
|
12
|
+
Version:: $Id: Session.rb 1617 2022-01-24 07:26:44Z miyabe $
|
|
13
|
+
|
|
14
|
+
ドキュメント変換サーバーへの接続オブジェクトです。
|
|
15
|
+
=end
|
|
16
|
+
class Session
|
|
17
|
+
=begin rdoc
|
|
18
|
+
セッションを構築します。このメソッドを直接呼び出す必要はありません。
|
|
19
|
+
|
|
20
|
+
CTI#get_session メソッドを使用してください。
|
|
21
|
+
|
|
22
|
+
io:: サーバーと通信するための IO オブジェクト
|
|
23
|
+
opts:: 接続オプション(ハッシュ型で、'encoding', 'user', 'password'というキーで文字コード、ユーザー名、パスワードを設定することができます。)
|
|
24
|
+
|
|
25
|
+
返り値:: サーバー情報のデータ文字列(XML)
|
|
26
|
+
=end
|
|
27
|
+
def initialize(io, opts)
|
|
28
|
+
self.reset
|
|
29
|
+
@io = io
|
|
30
|
+
|
|
31
|
+
io.extend CTIP2
|
|
32
|
+
|
|
33
|
+
opts.default = 'UTF-8'
|
|
34
|
+
@encoding = opts['encoding']
|
|
35
|
+
opts.default = ''
|
|
36
|
+
user = opts['user']
|
|
37
|
+
password = opts['password']
|
|
38
|
+
|
|
39
|
+
io.cti_connect(@encoding)
|
|
40
|
+
data = "PLAIN: #{user} #{password}\n"
|
|
41
|
+
io.write(data)
|
|
42
|
+
res = io.read(4)
|
|
43
|
+
raise "Authentication failure." if res != "OK \n"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
=begin rdoc
|
|
47
|
+
サーバー情報を返します。
|
|
48
|
+
詳細は{オンラインのドキュメント}[http://sourceforge.jp/projects/copper/wiki/CTIP2.0%E3%81%AE%E3%82%B5%E3%83%BC%E3%83%90%E3%83%BC%E6%83%85%E5%A0%B1]をご覧下さい。
|
|
49
|
+
|
|
50
|
+
uri:: サーバー情報のURI
|
|
51
|
+
|
|
52
|
+
返り値:: サーバー情報のデータ文字列(XML)
|
|
53
|
+
=end
|
|
54
|
+
|
|
55
|
+
def get_server_info(uri)
|
|
56
|
+
@io.req_server_info(uri)
|
|
57
|
+
data = ''
|
|
58
|
+
while true
|
|
59
|
+
res = @io.res_next
|
|
60
|
+
break if res['type'] == CTIP2::RES_EOF
|
|
61
|
+
data += res['bytes']
|
|
62
|
+
end
|
|
63
|
+
return data
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
=begin rdoc
|
|
67
|
+
変換結果の出力先を指定します。
|
|
68
|
+
|
|
69
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
70
|
+
この関数を呼び出さないデフォルトの状態では、出力先は標準出力( STDOUT )になります。
|
|
71
|
+
|
|
72
|
+
また、デフォルトの状態では、自動的にContent-Type, Content-Lengthヘッダが送出されます。
|
|
73
|
+
|
|
74
|
+
results:: 出力先の CTI::Results オブジェクト
|
|
75
|
+
=end
|
|
76
|
+
|
|
77
|
+
def set_results(results)
|
|
78
|
+
raise "set_results: Main content is already sent." if @state >= 2
|
|
79
|
+
@results = results
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
=begin rdoc
|
|
83
|
+
変換結果の出力先ファイル名を指定します。
|
|
84
|
+
|
|
85
|
+
CTI::Session#set_results の簡易版です。
|
|
86
|
+
こちらは、1つだけ結果を出力するファイル名を直接設定することができます。
|
|
87
|
+
|
|
88
|
+
file:: 出力先ファイル名
|
|
89
|
+
=end
|
|
90
|
+
|
|
91
|
+
def set_output_as_file(file)
|
|
92
|
+
set_results(SingleResult.new(FileBuilder.new(file)))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
=begin rdoc
|
|
96
|
+
変換結果の出力先ディレクトリ名を指定します。
|
|
97
|
+
|
|
98
|
+
CTI::Session#set_results の簡易版です。
|
|
99
|
+
こちらは、複数の結果をファイルとして出力するディレクトリ名を直接設定することができます。
|
|
100
|
+
ファイル名は prefix ページ番号 suffix をつなげたものです。
|
|
101
|
+
|
|
102
|
+
dir:: 出力先ディレクトリ名
|
|
103
|
+
prefix:: 出力するファイルの名前の前に付ける文字列
|
|
104
|
+
suffix:: 出力するファイルの名前の後に付ける文字列
|
|
105
|
+
=end
|
|
106
|
+
|
|
107
|
+
def set_output_as_directory(dir, prefix = '', suffix = '')
|
|
108
|
+
set_results(DirectoryResults.new(dir, prefix, suffix))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
=begin rdoc
|
|
112
|
+
変換結果の出力先リソースを指定します。
|
|
113
|
+
|
|
114
|
+
CTI::Session#set_results の簡易版です。
|
|
115
|
+
こちらは、1つだけの結果出力先を直接設定することができます。
|
|
116
|
+
|
|
117
|
+
out:: 出力先 IO オブジェクト
|
|
118
|
+
=end
|
|
119
|
+
|
|
120
|
+
def set_output_as_stream(out)
|
|
121
|
+
set_results(SingleResult.new(StreamBuilder.new(out)))
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
=begin rdoc
|
|
125
|
+
エラーメッセージ受信のためのブロックを設定します。
|
|
126
|
+
|
|
127
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
128
|
+
ブロックの引数は、エラーコード(int)、メッセージ(string)、付属データ(array)です。
|
|
129
|
+
|
|
130
|
+
&messageFunc:: ブロック
|
|
131
|
+
|
|
132
|
+
例:
|
|
133
|
+
session.receive_message do |code, message, args|
|
|
134
|
+
printf("%X %s\n", code, message)
|
|
135
|
+
p args
|
|
136
|
+
end
|
|
137
|
+
=end
|
|
138
|
+
|
|
139
|
+
def receive_message(&messageFunc)
|
|
140
|
+
raise "receive_message: Main content is already sent." if @state >= 2
|
|
141
|
+
@messageFunc = messageFunc;
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
=begin rdoc
|
|
145
|
+
進行状況受信のためのブロックを設定します。
|
|
146
|
+
|
|
147
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
148
|
+
ブロックの引数は、全体のバイト数(int)、読み込み済みバイト数(int)です。
|
|
149
|
+
|
|
150
|
+
&progressFunc:: ブロック
|
|
151
|
+
|
|
152
|
+
例:
|
|
153
|
+
session.receive_progress do |length, read|
|
|
154
|
+
puts "#{read} / #{length}"
|
|
155
|
+
end
|
|
156
|
+
=end
|
|
157
|
+
|
|
158
|
+
def receive_progress(&progressFunc)
|
|
159
|
+
raise "receive_progress: Main content is already sent." if @state >= 2
|
|
160
|
+
@progressFunc = progressFunc;
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
=begin rdoc
|
|
164
|
+
リソース解決のためのブロックを設定します。
|
|
165
|
+
|
|
166
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
167
|
+
ブロックの引数は、URI(string)、リソース出力クラス( CTI::Resource )です。
|
|
168
|
+
|
|
169
|
+
&resolverFunc:: ブロック
|
|
170
|
+
|
|
171
|
+
URIに対応するリソースが見つかった場合、 CTI::Resource#found メソッドを呼び出してください。
|
|
172
|
+
foundの呼び出しがない場合、リソースは見つからなかったものと扱われます。
|
|
173
|
+
|
|
174
|
+
例:
|
|
175
|
+
session.resolver do |uri, r|
|
|
176
|
+
if File.exist?(uri)
|
|
177
|
+
r.found do |out|
|
|
178
|
+
copy_stream(File.open(uri), out)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
=end
|
|
183
|
+
|
|
184
|
+
def resolver(&resolverFunc)
|
|
185
|
+
raise "resolver: Main content is already sent." if @state >= 2
|
|
186
|
+
@resolverFunc = resolverFunc;
|
|
187
|
+
@io.req_client_resource(resolverFunc ? 1 : 0)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
=begin rdoc
|
|
191
|
+
複数の結果を結合するモードを切り替えます。
|
|
192
|
+
モードが有効な場合、 CTI::Session#join の呼び出しで複数の結果を結合して返します。
|
|
193
|
+
|
|
194
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
195
|
+
|
|
196
|
+
continuous:: 有効にするにはtrue
|
|
197
|
+
=end
|
|
198
|
+
|
|
199
|
+
def set_continuous(continuous)
|
|
200
|
+
raise "set_continuous: Main content is already sent." if @state >= 2
|
|
201
|
+
@io.req_continuous(continuous ? 1 : 0)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
=begin rdoc
|
|
205
|
+
プロパティを設定します。
|
|
206
|
+
|
|
207
|
+
セッションを作成した直後に呼び出してください。
|
|
208
|
+
利用可能なプロパティの一覧は{資料集}[http://dl.cssj.jp/docs/copper/3.0/html/5100_io-properties.html]を参照してください。
|
|
209
|
+
|
|
210
|
+
name:: 名前
|
|
211
|
+
value:: 値
|
|
212
|
+
=end
|
|
213
|
+
|
|
214
|
+
def property(name, value)
|
|
215
|
+
raise "property: Main content is already sent." if @state >= 2
|
|
216
|
+
@io.req_property(name, value)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
=begin rdoc
|
|
220
|
+
リソース送信処理を行います。
|
|
221
|
+
CTI::Session#transcode および CTI::Session#transcode_server の前に呼び出してください。
|
|
222
|
+
|
|
223
|
+
uri:: 仮想URI
|
|
224
|
+
opts:: リソースオプション(ハッシュ型で、'mime_type', 'encoding', 'length'というキーでデータ型、文字コード、長さを設定することができます。)
|
|
225
|
+
&block:: リソースを送信するためのブロックで、引数としてリソースの出力先ストリームが渡されます。
|
|
226
|
+
|
|
227
|
+
戻り値:: &blockがない場合はリソースの出力先ストリームが返されます。
|
|
228
|
+
|
|
229
|
+
例:
|
|
230
|
+
session.resource('test.css', {'mime_type' => 'test/css'}) do |out|
|
|
231
|
+
copy_stream(File.open('data/test.css'), out)
|
|
232
|
+
end
|
|
233
|
+
=end
|
|
234
|
+
|
|
235
|
+
def resource(uri, opts = {}, &block)
|
|
236
|
+
raise "resource: Main content is already sent." if @state >= 2
|
|
237
|
+
opts.default = 'text/css'
|
|
238
|
+
mime_type = opts['mime_type']
|
|
239
|
+
opts.default = ''
|
|
240
|
+
encoding = opts['encoding']
|
|
241
|
+
opts.default = -1
|
|
242
|
+
length = opts['length']
|
|
243
|
+
@io.req_resource(uri, mime_type, encoding, length)
|
|
244
|
+
|
|
245
|
+
out = ResourceOut.new(@io)
|
|
246
|
+
if block
|
|
247
|
+
begin
|
|
248
|
+
block.call(out)
|
|
249
|
+
ensure
|
|
250
|
+
out.close
|
|
251
|
+
end
|
|
252
|
+
else
|
|
253
|
+
return out
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
=begin rdoc
|
|
258
|
+
変換対象の文書リソースを送信し、変換処理を行います。
|
|
259
|
+
|
|
260
|
+
uri:: 仮想URI
|
|
261
|
+
opts:: リソースオプション(ハッシュ型で、'mime_type', 'encoding', 'length'というキーでデータ型、文字コード、長さを設定することができます。)
|
|
262
|
+
&block:: リソースを送信するためのブロックで、引数としてリソースの出力先ストリームが渡されます。
|
|
263
|
+
|
|
264
|
+
戻り値:: &blockがない場合はリソースの出力先ストリームが返されます。
|
|
265
|
+
|
|
266
|
+
例:
|
|
267
|
+
session.transcode('.', {'mime_type' => 'text/html'}) do |out|
|
|
268
|
+
copy_stream(File.open('data/test.html'), out)
|
|
269
|
+
end
|
|
270
|
+
=end
|
|
271
|
+
|
|
272
|
+
def transcode(uri = '.', opts = {}, &block)
|
|
273
|
+
raise "transcode: Main content is already sent." if @state >= 2
|
|
274
|
+
opts.default = 'text/css'
|
|
275
|
+
mime_type = opts['mime_type']
|
|
276
|
+
opts.default = ''
|
|
277
|
+
encoding = opts['encoding']
|
|
278
|
+
opts.default = -1
|
|
279
|
+
length = opts['length']
|
|
280
|
+
state = 2
|
|
281
|
+
@io.req_start_main(uri, mime_type, encoding, length)
|
|
282
|
+
|
|
283
|
+
out = MainOut.new(@io, self)
|
|
284
|
+
if block
|
|
285
|
+
begin
|
|
286
|
+
block.call(out)
|
|
287
|
+
ensure
|
|
288
|
+
out.close
|
|
289
|
+
end
|
|
290
|
+
else
|
|
291
|
+
return out
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
=begin rdoc
|
|
296
|
+
サーバー側リソースを変換します。
|
|
297
|
+
|
|
298
|
+
uri:: URI
|
|
299
|
+
=end
|
|
300
|
+
|
|
301
|
+
def transcode_server(uri)
|
|
302
|
+
raise "transcode_server: Main content is already sent." if @state >= 2
|
|
303
|
+
@io.req_server_main(uri)
|
|
304
|
+
@state = 2
|
|
305
|
+
while build_next
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
=begin rdoc
|
|
310
|
+
<b>DEPRECATED:</b> {#transcode_server} を使って下さい。
|
|
311
|
+
|
|
312
|
+
サーバー側リソースを変換します。
|
|
313
|
+
|
|
314
|
+
uri:: URI
|
|
315
|
+
=end
|
|
316
|
+
def transcodeServer(uri)
|
|
317
|
+
transcode_server(uri)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
=begin rdoc
|
|
321
|
+
変換処理の中断を要求します。
|
|
322
|
+
|
|
323
|
+
mode:: 中断モード 0=生成済みのデータを出力して中断, 1=即時中断
|
|
324
|
+
=end
|
|
325
|
+
|
|
326
|
+
def abort(mode)
|
|
327
|
+
raise "abort: The session is already closed." if @state >= 3
|
|
328
|
+
@io.req_abort(mode)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
=begin rdoc
|
|
332
|
+
全ての状態をリセットします。
|
|
333
|
+
=end
|
|
334
|
+
|
|
335
|
+
def reset
|
|
336
|
+
raise "reset: The session is already closed." if @state && @state >= 3
|
|
337
|
+
if @io
|
|
338
|
+
@io.req_reset
|
|
339
|
+
end
|
|
340
|
+
@progressFunc = nil
|
|
341
|
+
@messageFunc = nil
|
|
342
|
+
@resolverFunc = nil
|
|
343
|
+
@results = SingleResult.new(StreamBuilder.new(STDOUT) do |length|
|
|
344
|
+
print "Content-Length: #{length}\r\n\r\n"
|
|
345
|
+
end) do |opts|
|
|
346
|
+
print "Content-Type: #{opts['mime_type']}\r\n"
|
|
347
|
+
end
|
|
348
|
+
@state = 1
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
=begin rdoc
|
|
352
|
+
結果を結合します。
|
|
353
|
+
|
|
354
|
+
先に CTI::Session#set_continuous を呼び出しておく必要があります。
|
|
355
|
+
=end
|
|
356
|
+
|
|
357
|
+
def join
|
|
358
|
+
raise "join: The session is already closed." if @state >= 3
|
|
359
|
+
@io.req_join
|
|
360
|
+
@state = 2
|
|
361
|
+
while build_next
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
=begin rdoc
|
|
366
|
+
セッションを閉じます。
|
|
367
|
+
=end
|
|
368
|
+
|
|
369
|
+
def close
|
|
370
|
+
raise "close: The session is already closed." if @state >= 3
|
|
371
|
+
@io.req_close;
|
|
372
|
+
@state = 3
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def build_next
|
|
376
|
+
res = @io.res_next
|
|
377
|
+
case res['type']
|
|
378
|
+
when CTIP2::RES_START_DATA
|
|
379
|
+
if @builder
|
|
380
|
+
@builder.finish
|
|
381
|
+
@builder.dispose
|
|
382
|
+
end
|
|
383
|
+
@builder = @results.next_builder(res)
|
|
384
|
+
|
|
385
|
+
when CTIP2::RES_BLOCK_DATA
|
|
386
|
+
@builder.write(res['block_id'], res['bytes'])
|
|
387
|
+
|
|
388
|
+
when CTIP2::RES_ADD_BLOCK
|
|
389
|
+
@builder.add_block
|
|
390
|
+
|
|
391
|
+
when CTIP2::RES_INSERT_BLOCK
|
|
392
|
+
@builder.insert_block_before(res['block_id'])
|
|
393
|
+
|
|
394
|
+
when CTIP2::RES_CLOSE_BLOCK
|
|
395
|
+
@builder.close_block(res['block_id'])
|
|
396
|
+
|
|
397
|
+
when CTIP2::RES_DATA
|
|
398
|
+
@builder.serial_write(res['bytes'])
|
|
399
|
+
|
|
400
|
+
when CTIP2::RES_MESSAGE
|
|
401
|
+
@messageFunc.call(res['code'], res['message'], res['args']) if @messageFunc
|
|
402
|
+
|
|
403
|
+
when CTIP2::RES_MAIN_LENGTH
|
|
404
|
+
@mainLength = res['length']
|
|
405
|
+
@progressFunc.call(@mainLength, @mainRead) if @progressFunc
|
|
406
|
+
|
|
407
|
+
when CTIP2::RES_MAIN_READ
|
|
408
|
+
@mainRead = res['length']
|
|
409
|
+
@progressFunc.call(@mainLength, @mainRead) if @progressFunc
|
|
410
|
+
|
|
411
|
+
when CTIP2::RES_RESOURCE_REQUEST
|
|
412
|
+
uri = res['uri']
|
|
413
|
+
r = Resource.new(@io, uri)
|
|
414
|
+
@resolverFunc.call(uri, r) if @resolverFunc
|
|
415
|
+
r.finish
|
|
416
|
+
@io.req_missing_resource(uri) if r.missing
|
|
417
|
+
|
|
418
|
+
when CTIP2::RES_ABORT
|
|
419
|
+
if @builder
|
|
420
|
+
@builder.finish if res['mode'] == 0
|
|
421
|
+
@builder.dispose
|
|
422
|
+
@builder = nil
|
|
423
|
+
end
|
|
424
|
+
@mainLength = nil
|
|
425
|
+
@mainRead = nil
|
|
426
|
+
@state = 1
|
|
427
|
+
return false
|
|
428
|
+
|
|
429
|
+
when CTIP2::RES_EOF
|
|
430
|
+
@builder.finish
|
|
431
|
+
@builder.dispose
|
|
432
|
+
@builder = nil
|
|
433
|
+
@mainLength = nil
|
|
434
|
+
@mainRead = nil
|
|
435
|
+
@state = 1
|
|
436
|
+
return false
|
|
437
|
+
|
|
438
|
+
when CTIP2::RES_NEXT
|
|
439
|
+
@state = 1
|
|
440
|
+
return false
|
|
441
|
+
end
|
|
442
|
+
return true
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
protected
|
|
447
|
+
|
|
448
|
+
class ResourceOut
|
|
449
|
+
def initialize(io)
|
|
450
|
+
@io = io
|
|
451
|
+
@closed = false
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
def write(str)
|
|
455
|
+
e = str.encoding;
|
|
456
|
+
str.force_encoding(Encoding::ASCII_8BIT)
|
|
457
|
+
while str.bytesize > 0
|
|
458
|
+
data = str.slice!(0, CTIP2::CTI_BUFFER_SIZE)
|
|
459
|
+
@io.req_write(data)
|
|
460
|
+
end
|
|
461
|
+
str.force_encoding(e)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def close
|
|
465
|
+
unless @closed
|
|
466
|
+
@io.req_eof
|
|
467
|
+
@cloded = true
|
|
468
|
+
end
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
class MainOut
|
|
473
|
+
def initialize(io, session)
|
|
474
|
+
@io = io
|
|
475
|
+
@session = session
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def write(str)
|
|
479
|
+
e = str.encoding;
|
|
480
|
+
str.force_encoding(Encoding::ASCII_8BIT)
|
|
481
|
+
# SSLSocket は write_nonblock を持つが nonblock= を持たない。
|
|
482
|
+
# 両方あるときだけ非ブロック書き込みを使う(2026-09-10。
|
|
483
|
+
# ctips:// で `undefined method 'nonblock='` になっていた)
|
|
484
|
+
bio = @io.respond_to?('write_nonblock') && @io.respond_to?('nonblock=')
|
|
485
|
+
while str.bytesize > 0
|
|
486
|
+
data = str.slice!(0, CTIP2::CTI_BUFFER_SIZE)
|
|
487
|
+
packet = [data.bytesize + 1, CTIP2::REQ_DATA].pack('NC') + data
|
|
488
|
+
while packet.bytesize > 0
|
|
489
|
+
rs, ws = IO::select([@io], [@io])
|
|
490
|
+
if packet.bytesize > 0 && ws[0]
|
|
491
|
+
if bio
|
|
492
|
+
len = @io.write_nonblock(packet)
|
|
493
|
+
@io.nonblock = false
|
|
494
|
+
else
|
|
495
|
+
len = @io.write(packet)
|
|
496
|
+
end
|
|
497
|
+
packet.slice!(0, len)
|
|
498
|
+
end
|
|
499
|
+
if rs[0]
|
|
500
|
+
@session.build_next
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
str.force_encoding(e)
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
def close
|
|
508
|
+
@io.req_eof
|
|
509
|
+
while @session.build_next
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
=begin rdoc
|
|
515
|
+
CTI::Session#resolver により設定したブロック内で、サーバーにリソースを送るためのオブジェクトです。
|
|
516
|
+
=end
|
|
517
|
+
|
|
518
|
+
class Resource
|
|
519
|
+
def initialize(io, uri)
|
|
520
|
+
@io = io
|
|
521
|
+
@uri = uri
|
|
522
|
+
@missing = true
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def missing
|
|
526
|
+
@missing
|
|
527
|
+
end
|
|
528
|
+
=begin rdoc
|
|
529
|
+
サーバーから要求されたリソースが見つかった場合の処理をします。
|
|
530
|
+
|
|
531
|
+
opts:: リソースオプション(ハッシュ型で、'mime_type', 'encoding', 'length'というキーでデータ型、文字コード、長さを設定することができます。)
|
|
532
|
+
&block:: リソースを送信するためのブロックで、引数としてリソースの出力先ストリームが渡されます。
|
|
533
|
+
|
|
534
|
+
戻り値:: &blockがない場合はリソースの出力先ストリームが返されます。
|
|
535
|
+
|
|
536
|
+
例:
|
|
537
|
+
CTI::Session#resolver を参照してください。
|
|
538
|
+
=end
|
|
539
|
+
|
|
540
|
+
def found(opts = {}, &block)
|
|
541
|
+
opts.default = 'text/css'
|
|
542
|
+
mime_type = opts['mime_type']
|
|
543
|
+
opts.default = ''
|
|
544
|
+
encoding = opts['encoding']
|
|
545
|
+
opts.default = -1
|
|
546
|
+
length = opts['length']
|
|
547
|
+
@io.req_resource(@uri, mime_type, encoding, length)
|
|
548
|
+
@missing = false;
|
|
549
|
+
@out = ResourceOut.new(@io)
|
|
550
|
+
if block
|
|
551
|
+
begin
|
|
552
|
+
block.call(@out)
|
|
553
|
+
ensure
|
|
554
|
+
@out.close
|
|
555
|
+
@out = nil
|
|
556
|
+
end
|
|
557
|
+
else
|
|
558
|
+
return @out
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def finish
|
|
563
|
+
@out.close if @out
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
end
|
data/src/code/CTI.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.expand_path('CTI/Driver', File.dirname(__FILE__))
|
|
2
|
+
=begin rdoc
|
|
3
|
+
:main:CTI
|
|
4
|
+
= CTI driver for Ruby
|
|
5
|
+
Version:: $Id: CTI.rb 1617 2022-01-24 07:26:44Z miyabe $
|
|
6
|
+
|
|
7
|
+
RubyでCopper PDF 2.1以降にアクセスするためのドライバです。
|
|
8
|
+
以下のドキュメントを参照してください。
|
|
9
|
+
|
|
10
|
+
http://dl.cssj.jp/docs/copper/3.1/html/3424_ctip2_ruby.html
|
|
11
|
+
=end
|
|
12
|
+
module CTI
|
|
13
|
+
module_function
|
|
14
|
+
=begin rdoc
|
|
15
|
+
指定されたURIに接続するためのドライバを返します。
|
|
16
|
+
|
|
17
|
+
uri:: 接続先アドレス
|
|
18
|
+
|
|
19
|
+
返り値:: CTI::Driver オブジェクト
|
|
20
|
+
=end
|
|
21
|
+
def get_driver(uri)
|
|
22
|
+
return Driver.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
=begin rdoc
|
|
26
|
+
指定されたURIに接続し、セッションを返します。
|
|
27
|
+
|
|
28
|
+
uri:: 接続先アドレス
|
|
29
|
+
options:: 接続オプション
|
|
30
|
+
|
|
31
|
+
返り値:: CTI::Session オブジェクト
|
|
32
|
+
=end
|
|
33
|
+
def get_session(uri, options = {}, &block)
|
|
34
|
+
get_driver(uri).get_session(uri, options, &block)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
=begin rdoc
|
|
38
|
+
指定された inp から out へコピーします。コピーしたバイト数を返します。
|
|
39
|
+
inp には read メソッド、out には write メソッドが必要です。
|
|
40
|
+
仕様が変わってしまったRubyのFileUtils::copy_stream, IO::copy_streamに代わるものです。
|
|
41
|
+
|
|
42
|
+
inp:: 転送元
|
|
43
|
+
out:: 転送先
|
|
44
|
+
|
|
45
|
+
=end
|
|
46
|
+
def copy_stream(inp, out)
|
|
47
|
+
read = 0;
|
|
48
|
+
while buff = inp.read(16 * 1024)
|
|
49
|
+
read += buff.length
|
|
50
|
+
out.write(buff)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: copper-cti
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 2.2.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Zamasoft
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: Ruby driver for connecting to the Copper PDF document conversion server
|
|
13
|
+
via the CTIP protocol.
|
|
14
|
+
email:
|
|
15
|
+
- info@zamasoft.jp
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- src/code/CTI.rb
|
|
21
|
+
- src/code/CTI/Builder/FileBuilder.rb
|
|
22
|
+
- src/code/CTI/Builder/NullBuilder.rb
|
|
23
|
+
- src/code/CTI/Builder/StreamBuilder.rb
|
|
24
|
+
- src/code/CTI/CTIP2/CTIP2.rb
|
|
25
|
+
- src/code/CTI/CTIP2/Utils.rb
|
|
26
|
+
- src/code/CTI/Driver.rb
|
|
27
|
+
- src/code/CTI/Results/DirectoryResults.rb
|
|
28
|
+
- src/code/CTI/Results/SingleResult.rb
|
|
29
|
+
- src/code/CTI/Session.rb
|
|
30
|
+
homepage: https://github.com/zamasoftnet/cti.ruby
|
|
31
|
+
licenses:
|
|
32
|
+
- Apache-2.0
|
|
33
|
+
metadata:
|
|
34
|
+
source_code_uri: https://github.com/zamasoftnet/cti.ruby
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
require_paths:
|
|
37
|
+
- src/code
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: 1.8.7
|
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
requirements: []
|
|
49
|
+
rubygems_version: 4.0.3
|
|
50
|
+
specification_version: 4
|
|
51
|
+
summary: CTI driver for Copper PDF server
|
|
52
|
+
test_files: []
|