async-ruby-zip 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.
- data/Gemfile.lock +31 -0
- data/README.md +30 -0
- data/async-ruby-zip.gemspec +77 -0
- data/ext/LICENSE +20 -0
- data/ext/archive.c +106 -0
- data/ext/archive.h +8 -0
- data/ext/archive_data.c +61 -0
- data/ext/archive_data.h +25 -0
- data/ext/archive_data_fwd.h +6 -0
- data/ext/async_zip.c +18 -0
- data/ext/async_zip.h +8 -0
- data/ext/callback.c +121 -0
- data/ext/callback.h +9 -0
- data/ext/carchive.c +219 -0
- data/ext/carchive.h +10 -0
- data/ext/carray.c +80 -0
- data/ext/carray.h +28 -0
- data/ext/cerror.c +74 -0
- data/ext/cerror.h +35 -0
- data/ext/cfilesystem.c +107 -0
- data/ext/cfilesystem.h +11 -0
- data/ext/extconf.rb +10 -0
- data/ext/task.c +62 -0
- data/ext/task.h +13 -0
- data/ext/writer.c +96 -0
- data/ext/writer.h +7 -0
- data/lib/async_zip.rb +5 -0
- data/lib/async_zip/version.rb +3 -0
- metadata +140 -0
data/Gemfile.lock
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.8.4)
|
7
|
+
bundler (~> 1.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
rdoc
|
11
|
+
json (1.7.3)
|
12
|
+
rake (0.9.2.2)
|
13
|
+
rdoc (3.12)
|
14
|
+
json (~> 1.4)
|
15
|
+
rspec (2.10.0)
|
16
|
+
rspec-core (~> 2.10.0)
|
17
|
+
rspec-expectations (~> 2.10.0)
|
18
|
+
rspec-mocks (~> 2.10.0)
|
19
|
+
rspec-core (2.10.1)
|
20
|
+
rspec-expectations (2.10.0)
|
21
|
+
diff-lcs (~> 1.1.3)
|
22
|
+
rspec-mocks (2.10.1)
|
23
|
+
|
24
|
+
PLATFORMS
|
25
|
+
ruby
|
26
|
+
|
27
|
+
DEPENDENCIES
|
28
|
+
bundler
|
29
|
+
jeweler (~> 1.8.3)
|
30
|
+
rdoc (~> 3.12)
|
31
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
async-ruby-zip
|
2
|
+
==============
|
3
|
+
|
4
|
+
Non-blocking zip reading and writing for Ruby
|
5
|
+
|
6
|
+
|
7
|
+
## Requirements.
|
8
|
+
|
9
|
+
* OS X or Linux
|
10
|
+
* MRI 1.9.2
|
11
|
+
* libzip >=0.10.1
|
12
|
+
|
13
|
+
## Example.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'rubygems'
|
17
|
+
require 'async_zip'
|
18
|
+
include AsyncZip
|
19
|
+
|
20
|
+
|
21
|
+
# Non-blocking zip-file creation:
|
22
|
+
AsyncZip.create(files, './output.zip') do |task|
|
23
|
+
puts task.inspect
|
24
|
+
end
|
25
|
+
|
26
|
+
# Non-blocking zip-file extraction:
|
27
|
+
AsyncZip.extract('./output.zip', './extracted') do |task|
|
28
|
+
puts task.inspect
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "async-ruby-zip"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Grigoriy Chudnov"]
|
12
|
+
s.date = "2012-08-04"
|
13
|
+
s.description = "Non-blocking zip reading and writing for Ruby."
|
14
|
+
s.email = "g.chudnov@gmail.com"
|
15
|
+
s.extensions = ["ext/extconf.rb"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile.lock",
|
21
|
+
"README.md",
|
22
|
+
"async-ruby-zip-1.0.0.gem",
|
23
|
+
"async-ruby-zip.gemspec",
|
24
|
+
"ext/LICENSE",
|
25
|
+
"ext/archive.c",
|
26
|
+
"ext/archive.h",
|
27
|
+
"ext/archive_data.c",
|
28
|
+
"ext/archive_data.h",
|
29
|
+
"ext/archive_data_fwd.h",
|
30
|
+
"ext/async_zip.c",
|
31
|
+
"ext/async_zip.h",
|
32
|
+
"ext/callback.c",
|
33
|
+
"ext/callback.h",
|
34
|
+
"ext/carchive.c",
|
35
|
+
"ext/carchive.h",
|
36
|
+
"ext/carray.c",
|
37
|
+
"ext/carray.h",
|
38
|
+
"ext/cerror.c",
|
39
|
+
"ext/cerror.h",
|
40
|
+
"ext/cfilesystem.c",
|
41
|
+
"ext/cfilesystem.h",
|
42
|
+
"ext/extconf.rb",
|
43
|
+
"ext/task.c",
|
44
|
+
"ext/task.h",
|
45
|
+
"ext/writer.c",
|
46
|
+
"ext/writer.h",
|
47
|
+
"lib/async_zip.rb",
|
48
|
+
"lib/async_zip/version.rb"
|
49
|
+
]
|
50
|
+
s.homepage = "https://github.com/gchudnov/async-ruby-zip"
|
51
|
+
s.licenses = ["MIT"]
|
52
|
+
s.require_paths = ["lib"]
|
53
|
+
s.rubygems_version = "1.8.24"
|
54
|
+
s.summary = "async-ruby-zip is a ruby extension that zip files asynchronously."
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
61
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
63
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
64
|
+
else
|
65
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
66
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
68
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
72
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
74
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
data/ext/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Grigoriy Chudnov
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/ext/archive.c
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
#include "archive.h"
|
2
|
+
#include "carchive.h"
|
3
|
+
#include "cerror.h"
|
4
|
+
#include "carray.h"
|
5
|
+
#include "archive_data.h"
|
6
|
+
#include "callback.h"
|
7
|
+
#include "writer.h"
|
8
|
+
|
9
|
+
|
10
|
+
static VALUE az_create(VALUE self, VALUE zip_path, VALUE files);
|
11
|
+
static VALUE az_extract(VALUE self, VALUE zip_path, VALUE dest_path);
|
12
|
+
|
13
|
+
|
14
|
+
static void* az_archive_thread_func(void* data)
|
15
|
+
{
|
16
|
+
archive_data_t* adata = (archive_data_t*)data;
|
17
|
+
if(!adata)
|
18
|
+
return NULL;
|
19
|
+
|
20
|
+
cerror_t err = { 0 };
|
21
|
+
|
22
|
+
if(adata->zip_path && !adata->dst_path) // create
|
23
|
+
{
|
24
|
+
err = carchive_create(adata->zip_path, adata->files_arr);
|
25
|
+
}
|
26
|
+
else if(adata->zip_path && adata->dst_path) // extract
|
27
|
+
{
|
28
|
+
err = carchive_extract(adata->zip_path, adata->dst_path, &adata->files_arr);
|
29
|
+
}
|
30
|
+
|
31
|
+
// error
|
32
|
+
if(cerror_is_error(&err))
|
33
|
+
{
|
34
|
+
adata->err_str = strdup(err.message);
|
35
|
+
}
|
36
|
+
cerror_free_message(&err);
|
37
|
+
|
38
|
+
az_add_to_event_qeueue(adata);
|
39
|
+
|
40
|
+
return NULL;
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
/* Add files to archive */
|
45
|
+
static VALUE az_create(VALUE self, VALUE files, VALUE zip_path)
|
46
|
+
{
|
47
|
+
rb_need_block();
|
48
|
+
VALUE proc = rb_block_proc();
|
49
|
+
|
50
|
+
int len = RARRAY_LEN(files);
|
51
|
+
if(len > 0)
|
52
|
+
{
|
53
|
+
carray_str_t* parr = carray_str_create(len);
|
54
|
+
|
55
|
+
int i;
|
56
|
+
for(i = 0; i != len; ++i)
|
57
|
+
{
|
58
|
+
VALUE current = rb_ary_entry(files, i);
|
59
|
+
if(rb_respond_to(current, rb_intern("to_s")))
|
60
|
+
{
|
61
|
+
VALUE name = rb_funcall(current, rb_intern("to_s"), 0);
|
62
|
+
|
63
|
+
carray_str_set(parr, i, StringValuePtr(name));
|
64
|
+
}
|
65
|
+
else
|
66
|
+
{
|
67
|
+
carray_str_set(parr, i, NULL);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
archive_data_t* adata = az_make_archive_data(StringValuePtr(zip_path), NULL, parr);
|
72
|
+
adata->proc = proc;
|
73
|
+
|
74
|
+
rb_gc_register_address(&adata->proc);
|
75
|
+
|
76
|
+
//
|
77
|
+
az_enqueue_task(az_archive_thread_func, adata);
|
78
|
+
}
|
79
|
+
|
80
|
+
return self;
|
81
|
+
}
|
82
|
+
|
83
|
+
/* Extract files from archive */
|
84
|
+
static VALUE az_extract(VALUE self, VALUE zip_path, VALUE dest_path)
|
85
|
+
{
|
86
|
+
rb_need_block();
|
87
|
+
VALUE proc = rb_block_proc();
|
88
|
+
|
89
|
+
archive_data_t* adata = az_make_archive_data(StringValuePtr(zip_path), StringValuePtr(dest_path), NULL);
|
90
|
+
adata->proc = proc;
|
91
|
+
|
92
|
+
rb_gc_register_address(&adata->proc);
|
93
|
+
|
94
|
+
//
|
95
|
+
az_enqueue_task(az_archive_thread_func, adata);
|
96
|
+
|
97
|
+
return self;
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
/* Initialize zip pipeline */
|
102
|
+
void init_async_zip_archive(void)
|
103
|
+
{
|
104
|
+
rb_define_singleton_method(mAsyncZip, "create", az_create, 2);
|
105
|
+
rb_define_singleton_method(mAsyncZip, "extract", az_extract, 2);
|
106
|
+
}
|
data/ext/archive.h
ADDED
data/ext/archive_data.c
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#include "archive_data.h"
|
2
|
+
|
3
|
+
// Create a new archive-data structure
|
4
|
+
archive_data_t* az_make_archive_data(const char* zip_path, const char* dst_path, carray_str_t* files_arr)
|
5
|
+
{
|
6
|
+
archive_data_t* adata = (archive_data_t*)malloc(sizeof(archive_data_t));
|
7
|
+
if(adata)
|
8
|
+
{
|
9
|
+
memset(adata, 0, sizeof(archive_data_t));
|
10
|
+
|
11
|
+
if(zip_path)
|
12
|
+
{
|
13
|
+
adata->zip_path = strdup(zip_path);
|
14
|
+
}
|
15
|
+
|
16
|
+
if(dst_path)
|
17
|
+
{
|
18
|
+
adata->dst_path = strdup(dst_path);
|
19
|
+
}
|
20
|
+
|
21
|
+
if(files_arr)
|
22
|
+
{
|
23
|
+
adata->files_arr = files_arr;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
return adata;
|
28
|
+
}
|
29
|
+
|
30
|
+
// Free archive-data structure
|
31
|
+
void az_free_archive_data(archive_data_t* adata)
|
32
|
+
{
|
33
|
+
if(!adata)
|
34
|
+
return;
|
35
|
+
|
36
|
+
if(adata->zip_path)
|
37
|
+
{
|
38
|
+
free(adata->zip_path);
|
39
|
+
adata->zip_path = NULL;
|
40
|
+
}
|
41
|
+
|
42
|
+
if(adata->dst_path)
|
43
|
+
{
|
44
|
+
free(adata->dst_path);
|
45
|
+
adata->dst_path = NULL;
|
46
|
+
}
|
47
|
+
|
48
|
+
if(adata->err_str)
|
49
|
+
{
|
50
|
+
free(adata->err_str);
|
51
|
+
adata->err_str = NULL;
|
52
|
+
}
|
53
|
+
|
54
|
+
if(adata->files_arr)
|
55
|
+
{
|
56
|
+
carray_str_destroy(adata->files_arr);
|
57
|
+
adata->files_arr = NULL;
|
58
|
+
}
|
59
|
+
|
60
|
+
free(adata);
|
61
|
+
}
|
data/ext/archive_data.h
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#ifndef ASYNC_ZIP_ARCHIVE_DATA_H
|
2
|
+
#define ASYNC_ZIP_ARCHIVE_DATA_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "carray.h"
|
6
|
+
|
7
|
+
typedef struct _archive_data_t
|
8
|
+
{
|
9
|
+
char* zip_path; // source zip-file
|
10
|
+
char* dst_path; // destination folder to extract zip-file { used only for extraction }
|
11
|
+
|
12
|
+
carray_str_t* files_arr; // array of files to archive or files that were extracted
|
13
|
+
|
14
|
+
VALUE proc;
|
15
|
+
char* err_str;
|
16
|
+
|
17
|
+
struct _archive_data_t* next;
|
18
|
+
} archive_data_t;
|
19
|
+
|
20
|
+
|
21
|
+
archive_data_t* az_make_archive_data(const char* zip_path, const char* dst_path, carray_str_t* files_arr);
|
22
|
+
void az_free_archive_data(archive_data_t* adata);
|
23
|
+
|
24
|
+
#endif
|
25
|
+
|
data/ext/async_zip.c
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#include "async_zip.h"
|
2
|
+
#include "archive.h"
|
3
|
+
#include "task.h"
|
4
|
+
#include "callback.h"
|
5
|
+
|
6
|
+
VALUE mAsyncZip, eZipError;
|
7
|
+
|
8
|
+
/* Initialize extension */
|
9
|
+
void Init_async_zip_ext()
|
10
|
+
{
|
11
|
+
mAsyncZip = rb_define_module("AsyncZip");
|
12
|
+
eZipError = rb_define_class_under(mAsyncZip, "Error", rb_eStandardError);
|
13
|
+
|
14
|
+
//
|
15
|
+
init_async_zip_archive();
|
16
|
+
init_async_zip_task();
|
17
|
+
init_async_zip_event_thread();
|
18
|
+
}
|
data/ext/async_zip.h
ADDED
data/ext/callback.c
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
#include "callback.h"
|
2
|
+
#include "async_zip.h"
|
3
|
+
#include "task.h"
|
4
|
+
#include "archive_data.h"
|
5
|
+
#include <pthread.h>
|
6
|
+
|
7
|
+
|
8
|
+
typedef struct _adata_wait_t
|
9
|
+
{
|
10
|
+
archive_data_t* adata;
|
11
|
+
int abort;
|
12
|
+
} adata_wait_t;
|
13
|
+
|
14
|
+
|
15
|
+
/* Queue of callbacks; each one invoked on a ruby thread */
|
16
|
+
pthread_mutex_t az_proc_mutex = PTHREAD_MUTEX_INITIALIZER;
|
17
|
+
pthread_cond_t az_proc_cond = PTHREAD_COND_INITIALIZER;
|
18
|
+
archive_data_t* az_proc_queue = NULL;
|
19
|
+
|
20
|
+
/* Push new callback to front of the queue */
|
21
|
+
static void az_proc_queue_push(archive_data_t* adata)
|
22
|
+
{
|
23
|
+
adata->next = az_proc_queue;
|
24
|
+
az_proc_queue = adata;
|
25
|
+
}
|
26
|
+
|
27
|
+
/* Pop next callback from the queue; Returns NULL, when the queue is empty */
|
28
|
+
static archive_data_t* az_proc_queue_pop(void)
|
29
|
+
{
|
30
|
+
archive_data_t* adata = az_proc_queue;
|
31
|
+
if(adata)
|
32
|
+
{
|
33
|
+
az_proc_queue = adata->next;
|
34
|
+
}
|
35
|
+
|
36
|
+
return adata;
|
37
|
+
}
|
38
|
+
|
39
|
+
/* Callback executed by Ruby Thread */
|
40
|
+
static VALUE az_handle_proc(void *d)
|
41
|
+
{
|
42
|
+
archive_data_t* adata = (archive_data_t*)d;
|
43
|
+
|
44
|
+
// Invoke callback with task argument
|
45
|
+
VALUE proc = (VALUE)adata->proc;
|
46
|
+
|
47
|
+
int is_create = ((adata->zip_path && !adata->dst_path) ? 1 : 0);
|
48
|
+
|
49
|
+
VALUE task = rb_class_new_instance(0, NULL, cTask);
|
50
|
+
az_task_init(task, (is_create ? NULL : adata->zip_path), (is_create ? adata->zip_path : adata->dst_path), adata->err_str, adata->files_arr);
|
51
|
+
rb_funcall2(proc, rb_intern("call"), 1, &task);
|
52
|
+
rb_gc_unregister_address(&adata->proc);
|
53
|
+
|
54
|
+
az_free_archive_data(adata);
|
55
|
+
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
/* Wait until we have some callbacks to process */
|
61
|
+
static VALUE az_wait_for_adata(void* w)
|
62
|
+
{
|
63
|
+
adata_wait_t* waiter = (adata_wait_t*)w;
|
64
|
+
|
65
|
+
pthread_mutex_lock(&az_proc_mutex);
|
66
|
+
while (!waiter->abort && (waiter->adata = az_proc_queue_pop()) == NULL)
|
67
|
+
{
|
68
|
+
pthread_cond_wait(&az_proc_cond, &az_proc_mutex);
|
69
|
+
}
|
70
|
+
pthread_mutex_unlock(&az_proc_mutex);
|
71
|
+
|
72
|
+
return Qnil;
|
73
|
+
}
|
74
|
+
|
75
|
+
/* Stop waiting for callbacks */
|
76
|
+
static void az_stop_waiting_for_adata(void* w)
|
77
|
+
{
|
78
|
+
adata_wait_t* waiter = (adata_wait_t*)w;
|
79
|
+
|
80
|
+
pthread_mutex_lock(&az_proc_mutex);
|
81
|
+
waiter->abort = 1;
|
82
|
+
pthread_mutex_unlock(&az_proc_mutex);
|
83
|
+
pthread_cond_signal(&az_proc_cond);
|
84
|
+
}
|
85
|
+
|
86
|
+
|
87
|
+
/* ruby event thread, waiting for processed archives to invoke a callback */
|
88
|
+
static VALUE az_event_thread(void *unused)
|
89
|
+
{
|
90
|
+
adata_wait_t waiter = { .adata = NULL, .abort = 0 };
|
91
|
+
while (!waiter.abort)
|
92
|
+
{
|
93
|
+
rb_thread_blocking_region(az_wait_for_adata, &waiter, az_stop_waiting_for_adata, &waiter);
|
94
|
+
if (waiter.adata)
|
95
|
+
{
|
96
|
+
rb_thread_create(az_handle_proc, waiter.adata);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
return Qnil;
|
101
|
+
}
|
102
|
+
|
103
|
+
/* Initialize Ruby Event Thread for invokation of user-provider callbacks */
|
104
|
+
void az_create_event_thread(void)
|
105
|
+
{
|
106
|
+
rb_thread_create(az_event_thread, NULL);
|
107
|
+
}
|
108
|
+
|
109
|
+
/* Add the archive data to the event queue */
|
110
|
+
void az_add_to_event_qeueue(archive_data_t* adata)
|
111
|
+
{
|
112
|
+
pthread_mutex_lock(&az_proc_mutex);
|
113
|
+
az_proc_queue_push(adata);
|
114
|
+
pthread_mutex_unlock(&az_proc_mutex);
|
115
|
+
pthread_cond_signal(&az_proc_cond);
|
116
|
+
}
|
117
|
+
|
118
|
+
void init_async_zip_event_thread(void)
|
119
|
+
{
|
120
|
+
az_create_event_thread();
|
121
|
+
}
|