dcm4chee 0.1.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/README.md +45 -0
- data/Rakefile +9 -0
- data/app/controllers/dcm4chee/api/v1/application_entities_controller.rb +178 -0
- data/app/controllers/dcm4chee/api/v1/base_controller.rb +15 -0
- data/app/controllers/dcm4chee/api/v1/dicom_objects_controller.rb +58 -0
- data/app/controllers/dcm4chee/api/v1/file_systems_controller.rb +37 -0
- data/app/controllers/dcm4chee/api/v1/instances_controller.rb +68 -0
- data/app/controllers/dcm4chee/api/v1/modalities_controller.rb +29 -0
- data/app/controllers/dcm4chee/api/v1/patients_controller.rb +77 -0
- data/app/controllers/dcm4chee/api/v1/series_controller.rb +69 -0
- data/app/controllers/dcm4chee/api/v1/source_aets_controller.rb +29 -0
- data/app/controllers/dcm4chee/api/v1/studies_controller.rb +69 -0
- data/app/controllers/dcm4chee/api/v1/trashed_instances_controller.rb +82 -0
- data/app/controllers/dcm4chee/api/v1/trashed_patients_controller.rb +84 -0
- data/app/controllers/dcm4chee/api/v1/trashed_series_controller.rb +81 -0
- data/app/controllers/dcm4chee/api/v1/trashed_studies_controller.rb +81 -0
- data/app/controllers/dcm4chee/api/v1/trashes_controller.rb +23 -0
- data/app/controllers/dcm4chee/application_controller.rb +4 -0
- data/app/models/dcm4chee/application_entity.rb +129 -0
- data/app/models/dcm4chee/dicom_file.rb +62 -0
- data/app/models/dcm4chee/file_system.rb +95 -0
- data/app/models/dcm4chee/instance.rb +69 -0
- data/app/models/dcm4chee/modality.rb +17 -0
- data/app/models/dcm4chee/patient.rb +42 -0
- data/app/models/dcm4chee/series.rb +78 -0
- data/app/models/dcm4chee/source_aet.rb +17 -0
- data/app/models/dcm4chee/study.rb +60 -0
- data/app/models/dcm4chee/trashed_dicom_file.rb +58 -0
- data/app/models/dcm4chee/trashed_instance.rb +56 -0
- data/app/models/dcm4chee/trashed_patient.rb +40 -0
- data/app/models/dcm4chee/trashed_series.rb +50 -0
- data/app/models/dcm4chee/trashed_study.rb +40 -0
- data/config/routes.rb +27 -0
- data/lib/dcm4chee.rb +58 -0
- data/lib/dcm4chee/api_constraints.rb +12 -0
- data/lib/dcm4chee/dicom_object_manager.rb +48 -0
- data/lib/dcm4chee/engine.rb +5 -0
- data/lib/dcm4chee/models/has_dicom_object.rb +71 -0
- data/lib/dcm4chee/services/application_entity_service.rb +113 -0
- data/lib/dcm4chee/services/content_edit_service.rb +37 -0
- data/lib/dcm4chee/services/file_system_management.rb +16 -0
- data/lib/dcm4chee/services/mbean.rb +11 -0
- data/lib/dcm4chee/services/move_scu_service.rb +54 -0
- data/lib/dcm4chee/version.rb +3 -0
- data/lib/tasks/dcm4chee_tasks.rake +4 -0
- metadata +241 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class TrashedStudiesController < BaseController
|
6
|
+
respond_to :json
|
7
|
+
|
8
|
+
# Search for studies from the trash. Supported querying
|
9
|
+
# conditions:
|
10
|
+
# trashed_patient_id
|
11
|
+
#
|
12
|
+
# Check {DataMapper::Searcher::ClassMethods} for supported
|
13
|
+
# querying operators.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# # Request
|
17
|
+
# GET /api/trashed_studies?q[trashed_patient_id]=... HTTP/1.1
|
18
|
+
# Accept: application/vnd.menglifang.org; version=1
|
19
|
+
#
|
20
|
+
# # Response
|
21
|
+
# HTTP/1.1 200 OK
|
22
|
+
# {
|
23
|
+
# "trashed_studies": [{
|
24
|
+
# "id": ...,
|
25
|
+
# "trashed_patient_id": ...,
|
26
|
+
# "study_iuid": ...,
|
27
|
+
# "accession_no": ...,
|
28
|
+
# "dcm_elements": [{
|
29
|
+
# "name": ...,
|
30
|
+
# "value": ...,
|
31
|
+
# "tag": ...,
|
32
|
+
# "value_representation": ...,
|
33
|
+
# "length": ...
|
34
|
+
# }, ...]
|
35
|
+
# }, ...]
|
36
|
+
# }
|
37
|
+
def index
|
38
|
+
studies = TrashedStudy.search(params[:q])
|
39
|
+
|
40
|
+
respond_with trashed_studies: studies
|
41
|
+
end
|
42
|
+
|
43
|
+
# Move a study to the trash including the related series, instances and files.
|
44
|
+
#
|
45
|
+
# @example
|
46
|
+
# # Request
|
47
|
+
# POST /api/trashed_studies HTTP/1.1
|
48
|
+
# Accept: application/vnd.menglifang.org; version=1
|
49
|
+
# Content-Type: application/json
|
50
|
+
#
|
51
|
+
# { "study_id": ... }
|
52
|
+
#
|
53
|
+
# # Response
|
54
|
+
# HTTP/1.1 201 Created
|
55
|
+
def create
|
56
|
+
study = Study.get!(params[:study_id])
|
57
|
+
study.move_to_trash
|
58
|
+
|
59
|
+
head :created
|
60
|
+
end
|
61
|
+
|
62
|
+
# Delete a study from the trash.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# # Request
|
66
|
+
# DELETE /api/trashed_studies/... HTTP/1.1
|
67
|
+
# Accept: application/vnd.menglifang.org; version=1
|
68
|
+
#
|
69
|
+
# # Response
|
70
|
+
# HTTP/1.1 200 OK
|
71
|
+
def destroy
|
72
|
+
study = TrashedStudy.get!(params[:id])
|
73
|
+
study.remove_from_trash
|
74
|
+
|
75
|
+
head :ok
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
module Api
|
4
|
+
module V1
|
5
|
+
class TrashesController < BaseController
|
6
|
+
# Clean up the trash.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # Request
|
10
|
+
# DELETE /api/trash HTTP/1.1
|
11
|
+
# Accept: application/vnd.menglifang.org; version=1
|
12
|
+
#
|
13
|
+
# # Response
|
14
|
+
# HTTP/1.1 200 OK
|
15
|
+
def destroy
|
16
|
+
Dcm4chee.content_edit_service.empty_trash
|
17
|
+
|
18
|
+
head :ok
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
class ApplicationEntity
|
4
|
+
include DataMapper::Resource
|
5
|
+
|
6
|
+
storage_names[Dcm4chee.config.repository_name] = 'ae'
|
7
|
+
|
8
|
+
# @return [Integer] primary key
|
9
|
+
property :id, Serial, field: 'pk'
|
10
|
+
|
11
|
+
# @return [String] name
|
12
|
+
property :title, String, field: 'aet'
|
13
|
+
|
14
|
+
# @return [String] hostname or ip address
|
15
|
+
property :host, String, field: 'hostname'
|
16
|
+
|
17
|
+
# @return [Integer] port
|
18
|
+
property :port, Integer, field: 'port'
|
19
|
+
|
20
|
+
# @return [String] cipher_suites, available values:SSL_RSA_WITH_NULL_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA
|
21
|
+
# Multi-suites should be specified in comma-separated format.
|
22
|
+
property :cipher_suites, String, field: 'cipher_suites'
|
23
|
+
|
24
|
+
# @return [String] issuer of the patient id
|
25
|
+
property :patient_id_issuer, String, field: 'pat_id_issuer'
|
26
|
+
|
27
|
+
# @return [String] issuer of the accession number
|
28
|
+
property :accession_number_issuer, String, field: 'acc_no_issuer'
|
29
|
+
|
30
|
+
# @return [String] username
|
31
|
+
property :username, String, field: 'user_id'
|
32
|
+
|
33
|
+
# @return [String] password
|
34
|
+
property :password, String, field: 'passwd'
|
35
|
+
|
36
|
+
# @return [String] group of the file system
|
37
|
+
property :fs_group, String, field: 'fs_group_id', default: 'ONLINE_STORAGE'
|
38
|
+
|
39
|
+
# @return [String] group of the application entity
|
40
|
+
property :group, String, field: 'ae_group'
|
41
|
+
|
42
|
+
# @return [String] description
|
43
|
+
property :description, String, field: 'ae_desc'
|
44
|
+
|
45
|
+
# @return [String] url of WADO
|
46
|
+
property :wado_url, String, field: 'wado_url'
|
47
|
+
|
48
|
+
# @return [String] station name
|
49
|
+
property :station_name, String, field: 'station_name'
|
50
|
+
|
51
|
+
# @return [String] institution
|
52
|
+
property :institution, String, field: 'institution'
|
53
|
+
|
54
|
+
# @return [String] department
|
55
|
+
property :department, String, field: 'department'
|
56
|
+
|
57
|
+
# @return [String] installed or not
|
58
|
+
property :installed, String, field: 'installed'
|
59
|
+
|
60
|
+
# Update an application entity through AEService of dcm4chee.
|
61
|
+
#
|
62
|
+
# @param [Hash] attrs Attributes of the application entity
|
63
|
+
def update_by_service(attrs = {})
|
64
|
+
params = [
|
65
|
+
id,
|
66
|
+
attrs[:title] || title,
|
67
|
+
attrs[:host] || host,
|
68
|
+
attrs[:port] || port,
|
69
|
+
attrs[:cipher_suites] || cipher_suites,
|
70
|
+
attrs[:patient_id_issuer] || patient_id_issuer,
|
71
|
+
attrs[:accession_number_issuer] || accession_number_issuer,
|
72
|
+
attrs[:username] || username,
|
73
|
+
attrs[:password] || password,
|
74
|
+
attrs[:fs_group] || fs_group,
|
75
|
+
attrs[:group] || group,
|
76
|
+
attrs[:description] || description,
|
77
|
+
attrs[:wado_url] || wado_url,
|
78
|
+
attrs[:station_name] || station_name,
|
79
|
+
attrs[:institution] || institution,
|
80
|
+
attrs[:department] || department,
|
81
|
+
attrs[:installed] || installed,
|
82
|
+
true
|
83
|
+
]
|
84
|
+
Dcm4chee.application_entity_service.update_ae(params)
|
85
|
+
reload
|
86
|
+
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
# Delete an application entity through AEService of dcm4chee
|
91
|
+
def destroy_by_service
|
92
|
+
Dcm4chee.application_entity_service.remove_ae(title)
|
93
|
+
end
|
94
|
+
|
95
|
+
class << self
|
96
|
+
# Create an application entity through AEService of dcm4chee.
|
97
|
+
#
|
98
|
+
# @param [Hash] attrs Attributes of the new application entity
|
99
|
+
def create_by_service(attrs = {})
|
100
|
+
params = [
|
101
|
+
attrs[:title],
|
102
|
+
attrs[:host],
|
103
|
+
attrs[:port],
|
104
|
+
attrs[:cipher_suites],
|
105
|
+
attrs[:patient_id_issuer],
|
106
|
+
attrs[:accession_number_issuer],
|
107
|
+
attrs[:username],
|
108
|
+
attrs[:password],
|
109
|
+
attrs[:fs_group],
|
110
|
+
attrs[:group],
|
111
|
+
attrs[:description],
|
112
|
+
attrs[:wado_url],
|
113
|
+
attrs[:station_name],
|
114
|
+
attrs[:institution],
|
115
|
+
attrs[:department],
|
116
|
+
!!(attrs[:installed]),
|
117
|
+
true
|
118
|
+
]
|
119
|
+
Dcm4chee.application_entity_service.add_ae(params)
|
120
|
+
|
121
|
+
first(title: attrs[:title])
|
122
|
+
end
|
123
|
+
|
124
|
+
def repository(name = nil, &block)
|
125
|
+
super(Dcm4chee.config.repository_name, &block)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
class DicomFile
|
4
|
+
include DataMapper::Resource
|
5
|
+
include HasDicomObject
|
6
|
+
|
7
|
+
storage_names[Dcm4chee.config.repository_name] = 'files'
|
8
|
+
|
9
|
+
# @return [Integer] primary key
|
10
|
+
property :id, Serial, field: 'pk'
|
11
|
+
|
12
|
+
# @return [Integer] foreign key of {Instance}
|
13
|
+
property :instance_id, Integer, field: 'instance_fk'
|
14
|
+
|
15
|
+
# @return [Integer] foreign key of {FileSystem}
|
16
|
+
property :file_system_id, Integer, field: 'filesystem_fk'
|
17
|
+
|
18
|
+
# @return [String] path
|
19
|
+
property :path, Text, field: 'filepath'
|
20
|
+
|
21
|
+
# @return [String] DICOM transfer syntax UID(0002,0010)
|
22
|
+
property :transfer_syntax_uid, Text, field: 'file_tsuid'
|
23
|
+
|
24
|
+
# @return [String] MD5 of the file
|
25
|
+
property :md5, String, field: 'file_md5'
|
26
|
+
|
27
|
+
# @return [Integer] file size
|
28
|
+
property :size, Integer, field: 'file_size'
|
29
|
+
|
30
|
+
# Available values:
|
31
|
+
# -4: QUERY_HSM_FAILED
|
32
|
+
# -3: MD5_CHECK_FAILED
|
33
|
+
# -2: VERIFY_COMPRESS_FAILED
|
34
|
+
# -1: COMPRESS_FAILED
|
35
|
+
# 0: DEFAULT
|
36
|
+
# 1: TO_ARCHIVE
|
37
|
+
# 2: ARCHIVED
|
38
|
+
# 3: COMPRESSING
|
39
|
+
#
|
40
|
+
# @return [Integer] file status
|
41
|
+
property :availability, Enum[-4, -3, -2, -1, 0, 1, 2, 3], field: 'file_status'
|
42
|
+
|
43
|
+
# @return [DateTime] last MD5 checking time of the file
|
44
|
+
property :md5_checked_at, DateTime, field: 'md5_check_time'
|
45
|
+
|
46
|
+
# @return [DateTime] created time
|
47
|
+
property :created_at, DateTime, field: 'created_time'
|
48
|
+
|
49
|
+
belongs_to :instance, 'Dcm4chee::Instance'
|
50
|
+
belongs_to :file_system, 'Dcm4chee::FileSystem'
|
51
|
+
|
52
|
+
# Load the dicom object
|
53
|
+
# @return [DICOM::DObject] DICOM object
|
54
|
+
def dcm
|
55
|
+
@dcm ||= DICOM::DObject.read(File.join(file_system.path, path))
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.repository(name = nil, &block)
|
59
|
+
super(Dcm4chee.config.repository_name, &block)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
class FileSystem
|
4
|
+
include DataMapper::Resource
|
5
|
+
|
6
|
+
storage_names[Dcm4chee.config.repository_name] = 'filesystem'
|
7
|
+
|
8
|
+
# @return [Integer] primary key
|
9
|
+
property :id, Serial, field: 'pk'
|
10
|
+
|
11
|
+
# @return [String] path of the directory
|
12
|
+
property :path, String, field: 'dirpath'
|
13
|
+
|
14
|
+
# @return [Integer] type of the file system
|
15
|
+
# 0: ONLINE
|
16
|
+
# 1: NEARLINE
|
17
|
+
# 2: OFFLINE
|
18
|
+
property :availability, Integer, field: 'availability'
|
19
|
+
|
20
|
+
has n, :dicom_files, 'Dcm4chee::DicomFile'
|
21
|
+
has n, :trashed_dicom_files, 'Dcm4chee::TrashedDicomFile'
|
22
|
+
|
23
|
+
# Check whether the path is relative or absolute. The default path of the relative one is `#{Dcm4chee.config.server_home}/server/default`
|
24
|
+
def path
|
25
|
+
p = self[:path]
|
26
|
+
|
27
|
+
return p if p.start_with?('/')
|
28
|
+
|
29
|
+
raise 'Home of dcm4chee must be set' unless Dcm4chee.config.server_home
|
30
|
+
|
31
|
+
File.join(Dcm4chee.config.server_home, 'server/default', p)
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Integer] Total space of the file system(in bytes)
|
35
|
+
def total_space
|
36
|
+
status.block_size * status.blocks
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Integer] Available space of the file system(in bytes)
|
40
|
+
def free_space
|
41
|
+
status.block_size * status.blocks_available
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Integer] Used space of the file system(in bytes)
|
45
|
+
def used_space
|
46
|
+
total_space - free_space
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Integer] Minimum free space of the file system. If the free space is under the limit, dcm4chee will use the next one instead.
|
50
|
+
def min_free_space
|
51
|
+
@min_free_space ||= Dcm4chee.file_system_management.minimum_free_disk_space_bytes
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Integer] Expected space per day(in bytes)
|
55
|
+
def expected_space_per_day
|
56
|
+
@expected_space_per_day ||= Dcm4chee.file_system_management.expected_data_volume_per_day_bytes
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Integer] Remaining days of the file system
|
60
|
+
def remaining_days
|
61
|
+
@remaining_days ||= (free_space - min_free_space) / expected_space_per_day
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [Hash] Serialized data
|
65
|
+
def as_json(opts = {})
|
66
|
+
opts[:exclude] ||= []
|
67
|
+
opts[:exclude] << :availability
|
68
|
+
|
69
|
+
opts[:methods] ||= []
|
70
|
+
opts[:methods].concat([:path, :total_space, :free_space,
|
71
|
+
:used_space, :min_free_space,
|
72
|
+
:expected_space_per_day, :remaining_days])
|
73
|
+
|
74
|
+
super(opts)
|
75
|
+
end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
# @return [DataMapper::Collection] All online file systems
|
79
|
+
def online
|
80
|
+
all(availability: 0)
|
81
|
+
end
|
82
|
+
|
83
|
+
def repository(name = nil, &block)
|
84
|
+
super(Dcm4chee.config.repository_name, &block)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
# @return [Sys::Filesystem] Status of the file system
|
91
|
+
def status
|
92
|
+
@status ||= Sys::Filesystem.stat(path)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module Dcm4chee
|
3
|
+
class Instance
|
4
|
+
include DataMapper::Resource
|
5
|
+
include DataMapper::Searcher
|
6
|
+
|
7
|
+
include HasDicomObject
|
8
|
+
|
9
|
+
storage_names[Dcm4chee.config.repository_name] = 'instance'
|
10
|
+
|
11
|
+
# @return [Integer] primary key
|
12
|
+
property :id, Serial, field: 'pk'
|
13
|
+
|
14
|
+
# @return [Integer] foreign key of {Series}
|
15
|
+
property :series_id, Integer, field: 'series_fk'
|
16
|
+
|
17
|
+
# @return [DateTime] created time
|
18
|
+
property :created_at, DateTime, field: 'created_time'
|
19
|
+
|
20
|
+
# @return [String] DICOM Instance NO(0020,0013)
|
21
|
+
property :instance_no, String, field: 'inst_no'
|
22
|
+
|
23
|
+
# @return [String] DICOM SOP Instance UID(0008,0018)
|
24
|
+
property :sop_iuid, Text, field: 'sop_iuid'
|
25
|
+
|
26
|
+
# @return [String] DICOM SOP Class UID(0008,0016)
|
27
|
+
property :sop_cuid, Text, field: 'sop_cuid'
|
28
|
+
|
29
|
+
# DICOM Instance Availability(0008,0056)
|
30
|
+
# 0: ONLINE
|
31
|
+
# 1: NEARLINE
|
32
|
+
# 2: OFFLINE
|
33
|
+
# 3: UNAVAILABLE
|
34
|
+
#
|
35
|
+
# @return [Integer] DICOM Integer Availability
|
36
|
+
property :availability, Enum[0, 1, 2, 3], field: 'availability'
|
37
|
+
|
38
|
+
# TODO Added description
|
39
|
+
|
40
|
+
dicom_field 'inst_attrs'
|
41
|
+
|
42
|
+
belongs_to :series, 'Dcm4chee::Series'
|
43
|
+
has n, :dicom_files, 'Dcm4chee::DicomFile'
|
44
|
+
|
45
|
+
def study_iuid
|
46
|
+
series.study.study_iuid
|
47
|
+
end
|
48
|
+
|
49
|
+
def series_iuid
|
50
|
+
series.series_iuid
|
51
|
+
end
|
52
|
+
|
53
|
+
def move_to_trash
|
54
|
+
Dcm4chee.content_edit_service.move_instance_to_trash(id)
|
55
|
+
end
|
56
|
+
|
57
|
+
def as_json(opts = {})
|
58
|
+
opts[:methods] ||= []
|
59
|
+
opts[:methods] << :series_iuid
|
60
|
+
opts[:methods] << :study_iuid
|
61
|
+
|
62
|
+
super(opts)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.repository(name = nil, &block)
|
66
|
+
super(Dcm4chee.config.repository_name, &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|