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.
Files changed (46) hide show
  1. data/README.md +45 -0
  2. data/Rakefile +9 -0
  3. data/app/controllers/dcm4chee/api/v1/application_entities_controller.rb +178 -0
  4. data/app/controllers/dcm4chee/api/v1/base_controller.rb +15 -0
  5. data/app/controllers/dcm4chee/api/v1/dicom_objects_controller.rb +58 -0
  6. data/app/controllers/dcm4chee/api/v1/file_systems_controller.rb +37 -0
  7. data/app/controllers/dcm4chee/api/v1/instances_controller.rb +68 -0
  8. data/app/controllers/dcm4chee/api/v1/modalities_controller.rb +29 -0
  9. data/app/controllers/dcm4chee/api/v1/patients_controller.rb +77 -0
  10. data/app/controllers/dcm4chee/api/v1/series_controller.rb +69 -0
  11. data/app/controllers/dcm4chee/api/v1/source_aets_controller.rb +29 -0
  12. data/app/controllers/dcm4chee/api/v1/studies_controller.rb +69 -0
  13. data/app/controllers/dcm4chee/api/v1/trashed_instances_controller.rb +82 -0
  14. data/app/controllers/dcm4chee/api/v1/trashed_patients_controller.rb +84 -0
  15. data/app/controllers/dcm4chee/api/v1/trashed_series_controller.rb +81 -0
  16. data/app/controllers/dcm4chee/api/v1/trashed_studies_controller.rb +81 -0
  17. data/app/controllers/dcm4chee/api/v1/trashes_controller.rb +23 -0
  18. data/app/controllers/dcm4chee/application_controller.rb +4 -0
  19. data/app/models/dcm4chee/application_entity.rb +129 -0
  20. data/app/models/dcm4chee/dicom_file.rb +62 -0
  21. data/app/models/dcm4chee/file_system.rb +95 -0
  22. data/app/models/dcm4chee/instance.rb +69 -0
  23. data/app/models/dcm4chee/modality.rb +17 -0
  24. data/app/models/dcm4chee/patient.rb +42 -0
  25. data/app/models/dcm4chee/series.rb +78 -0
  26. data/app/models/dcm4chee/source_aet.rb +17 -0
  27. data/app/models/dcm4chee/study.rb +60 -0
  28. data/app/models/dcm4chee/trashed_dicom_file.rb +58 -0
  29. data/app/models/dcm4chee/trashed_instance.rb +56 -0
  30. data/app/models/dcm4chee/trashed_patient.rb +40 -0
  31. data/app/models/dcm4chee/trashed_series.rb +50 -0
  32. data/app/models/dcm4chee/trashed_study.rb +40 -0
  33. data/config/routes.rb +27 -0
  34. data/lib/dcm4chee.rb +58 -0
  35. data/lib/dcm4chee/api_constraints.rb +12 -0
  36. data/lib/dcm4chee/dicom_object_manager.rb +48 -0
  37. data/lib/dcm4chee/engine.rb +5 -0
  38. data/lib/dcm4chee/models/has_dicom_object.rb +71 -0
  39. data/lib/dcm4chee/services/application_entity_service.rb +113 -0
  40. data/lib/dcm4chee/services/content_edit_service.rb +37 -0
  41. data/lib/dcm4chee/services/file_system_management.rb +16 -0
  42. data/lib/dcm4chee/services/mbean.rb +11 -0
  43. data/lib/dcm4chee/services/move_scu_service.rb +54 -0
  44. data/lib/dcm4chee/version.rb +3 -0
  45. data/lib/tasks/dcm4chee_tasks.rake +4 -0
  46. 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,4 @@
1
+ module Dcm4chee
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ 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