Mercurial > hg > orthanc
comparison OrthancServer/Sources/ServerContext.cpp @ 4796:94616af363ec filter-store-instance
added ReceivedCStoreInstanceFilter lua callback + OrthancPluginRegisterIncomingCStoreInstanceFilter in sdk
author | Alain Mazy <am@osimis.io> |
---|---|
date | Fri, 01 Oct 2021 18:36:45 +0200 |
parents | 51ec061516c9 |
children | 0bd98c52474b |
comparison
equal
deleted
inserted
replaced
4795:22d5b611dea7 | 4796:94616af363ec |
---|---|
55 #include "ServerJobs/OrthancJobUnserializer.h" | 55 #include "ServerJobs/OrthancJobUnserializer.h" |
56 #include "ServerToolbox.h" | 56 #include "ServerToolbox.h" |
57 #include "StorageCommitmentReports.h" | 57 #include "StorageCommitmentReports.h" |
58 | 58 |
59 #include <dcmtk/dcmdata/dcfilefo.h> | 59 #include <dcmtk/dcmdata/dcfilefo.h> |
60 #include <dcmtk/dcmnet/dimse.h> | |
60 | 61 |
61 | 62 |
62 static size_t DICOM_CACHE_SIZE = 128 * 1024 * 1024; // 128 MB | 63 static size_t DICOM_CACHE_SIZE = 128 * 1024 * 1024; // 128 MB |
63 | 64 |
64 | 65 |
96 transferSyntax != DicomTransferSyntax_HEVCMain10ProfileLevel5_1 && | 97 transferSyntax != DicomTransferSyntax_HEVCMain10ProfileLevel5_1 && |
97 | 98 |
98 // Do not try to transcode special transfer syntaxes | 99 // Do not try to transcode special transfer syntaxes |
99 transferSyntax != DicomTransferSyntax_RFC2557MimeEncapsulation && | 100 transferSyntax != DicomTransferSyntax_RFC2557MimeEncapsulation && |
100 transferSyntax != DicomTransferSyntax_XML); | 101 transferSyntax != DicomTransferSyntax_XML); |
102 } | |
103 | |
104 | |
105 ServerContext::StoreResult::StoreResult() : | |
106 status_(StoreStatus_Failure), | |
107 cstoreStatusCode_(0) | |
108 { | |
101 } | 109 } |
102 | 110 |
103 | 111 |
104 void ServerContext::ChangeThread(ServerContext* that, | 112 void ServerContext::ChangeThread(ServerContext* that, |
105 unsigned int sleepDelay) | 113 unsigned int sleepDelay) |
487 StorageAccessor accessor(area_, GetMetricsRegistry()); | 495 StorageAccessor accessor(area_, GetMetricsRegistry()); |
488 accessor.Remove(fileUuid, type); | 496 accessor.Remove(fileUuid, type); |
489 } | 497 } |
490 | 498 |
491 | 499 |
492 StoreStatus ServerContext::StoreAfterTranscoding(std::string& resultPublicId, | 500 ServerContext::StoreResult ServerContext::StoreAfterTranscoding(std::string& resultPublicId, |
493 DicomInstanceToStore& dicom, | 501 DicomInstanceToStore& dicom, |
494 StoreInstanceMode mode) | 502 StoreInstanceMode mode) |
495 { | 503 { |
496 bool overwrite; | 504 bool overwrite; |
497 switch (mode) | 505 switch (mode) |
498 { | 506 { |
499 case StoreInstanceMode_Default: | 507 case StoreInstanceMode_Default: |
536 | 544 |
537 Json::Value simplifiedTags; | 545 Json::Value simplifiedTags; |
538 Toolbox::SimplifyDicomAsJson(simplifiedTags, dicomAsJson, DicomToJsonFormat_Human); | 546 Toolbox::SimplifyDicomAsJson(simplifiedTags, dicomAsJson, DicomToJsonFormat_Human); |
539 | 547 |
540 // Test if the instance must be filtered out | 548 // Test if the instance must be filtered out |
541 bool accepted = true; | 549 StoreResult result; |
542 | 550 |
543 { | 551 { |
544 boost::shared_lock<boost::shared_mutex> lock(listenersMutex_); | 552 boost::shared_lock<boost::shared_mutex> lock(listenersMutex_); |
545 | 553 |
546 for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) | 554 for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) |
547 { | 555 { |
548 try | 556 try |
549 { | 557 { |
550 if (!it->GetListener().FilterIncomingInstance(dicom, simplifiedTags)) | 558 if (!it->GetListener().FilterIncomingInstance(dicom, simplifiedTags)) |
551 { | 559 { |
552 accepted = false; | 560 result.SetStatus(StoreStatus_FilteredOut); |
561 result.SetCStoreStatusCode(STATUS_Success); // to keep backward compatibility, we still return 'success' | |
553 break; | 562 break; |
554 } | 563 } |
564 | |
565 if (dicom.GetOrigin().GetRequestOrigin() == Orthanc::RequestOrigin_DicomProtocol) | |
566 { | |
567 uint16_t filterResult = it->GetListener().FilterIncomingCStoreInstance(dicom, simplifiedTags); | |
568 if (it->GetListener().FilterIncomingCStoreInstance(dicom, simplifiedTags) != 0x0000) | |
569 { | |
570 result.SetStatus(StoreStatus_FilteredOut); | |
571 result.SetCStoreStatusCode(filterResult); | |
572 break; | |
573 } | |
574 } | |
575 | |
555 } | 576 } |
556 catch (OrthancException& e) | 577 catch (OrthancException& e) |
557 { | 578 { |
558 LOG(ERROR) << "Error in the " << it->GetDescription() | 579 LOG(ERROR) << "Error in the " << it->GetDescription() |
559 << " callback while receiving an instance: " << e.What() | 580 << " callback while receiving an instance: " << e.What() |
561 throw; | 582 throw; |
562 } | 583 } |
563 } | 584 } |
564 } | 585 } |
565 | 586 |
566 if (!accepted) | 587 if (result.GetStatus() == StoreStatus_FilteredOut) |
567 { | 588 { |
568 LOG(INFO) << "An incoming instance has been discarded by the filter"; | 589 LOG(INFO) << "An incoming instance has been discarded by the filter"; |
569 return StoreStatus_FilteredOut; | 590 return result; |
570 } | 591 } |
571 | 592 |
572 // Remove the file from the DicomCache (useful if | 593 // Remove the file from the DicomCache (useful if |
573 // "OverwriteInstances" is set to "true") | 594 // "OverwriteInstances" is set to "true") |
574 dicomCache_.Invalidate(resultPublicId); | 595 dicomCache_.Invalidate(resultPublicId); |
593 attachments.push_back(dicomUntilPixelData); | 614 attachments.push_back(dicomUntilPixelData); |
594 } | 615 } |
595 | 616 |
596 typedef std::map<MetadataType, std::string> InstanceMetadata; | 617 typedef std::map<MetadataType, std::string> InstanceMetadata; |
597 InstanceMetadata instanceMetadata; | 618 InstanceMetadata instanceMetadata; |
598 StoreStatus status = index_.Store( | 619 result.SetStatus(index_.Store( |
599 instanceMetadata, summary, attachments, dicom.GetMetadata(), dicom.GetOrigin(), overwrite, | 620 instanceMetadata, summary, attachments, dicom.GetMetadata(), dicom.GetOrigin(), overwrite, |
600 hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset); | 621 hasTransferSyntax, transferSyntax, hasPixelDataOffset, pixelDataOffset)); |
601 | 622 |
602 // Only keep the metadata for the "instance" level | 623 // Only keep the metadata for the "instance" level |
603 dicom.ClearMetadata(); | 624 dicom.ClearMetadata(); |
604 | 625 |
605 for (InstanceMetadata::const_iterator it = instanceMetadata.begin(); | 626 for (InstanceMetadata::const_iterator it = instanceMetadata.begin(); |
606 it != instanceMetadata.end(); ++it) | 627 it != instanceMetadata.end(); ++it) |
607 { | 628 { |
608 dicom.AddMetadata(ResourceType_Instance, it->first, it->second); | 629 dicom.AddMetadata(ResourceType_Instance, it->first, it->second); |
609 } | 630 } |
610 | 631 |
611 if (status != StoreStatus_Success) | 632 if (result.GetStatus() != StoreStatus_Success) |
612 { | 633 { |
613 accessor.Remove(dicomInfo); | 634 accessor.Remove(dicomInfo); |
614 | 635 |
615 if (dicomUntilPixelData.IsValid()) | 636 if (dicomUntilPixelData.IsValid()) |
616 { | 637 { |
617 accessor.Remove(dicomUntilPixelData); | 638 accessor.Remove(dicomUntilPixelData); |
618 } | 639 } |
619 } | 640 } |
620 | 641 |
621 switch (status) | 642 switch (result.GetStatus()) |
622 { | 643 { |
623 case StoreStatus_Success: | 644 case StoreStatus_Success: |
624 LOG(INFO) << "New instance stored"; | 645 LOG(INFO) << "New instance stored"; |
625 break; | 646 break; |
626 | 647 |
635 default: | 656 default: |
636 // This should never happen | 657 // This should never happen |
637 break; | 658 break; |
638 } | 659 } |
639 | 660 |
640 if (status == StoreStatus_Success || | 661 if (result.GetStatus() == StoreStatus_Success || |
641 status == StoreStatus_AlreadyStored) | 662 result.GetStatus() == StoreStatus_AlreadyStored) |
642 { | 663 { |
643 boost::shared_lock<boost::shared_mutex> lock(listenersMutex_); | 664 boost::shared_lock<boost::shared_mutex> lock(listenersMutex_); |
644 | 665 |
645 for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) | 666 for (ServerListeners::iterator it = listeners_.begin(); it != listeners_.end(); ++it) |
646 { | 667 { |
655 << " (code " << e.GetErrorCode() << ")"; | 676 << " (code " << e.GetErrorCode() << ")"; |
656 } | 677 } |
657 } | 678 } |
658 } | 679 } |
659 | 680 |
660 return status; | 681 return result; |
661 } | 682 } |
662 catch (OrthancException& e) | 683 catch (OrthancException& e) |
663 { | 684 { |
664 if (e.GetErrorCode() == ErrorCode_InexistentTag) | 685 if (e.GetErrorCode() == ErrorCode_InexistentTag) |
665 { | 686 { |
669 throw; | 690 throw; |
670 } | 691 } |
671 } | 692 } |
672 | 693 |
673 | 694 |
674 StoreStatus ServerContext::Store(std::string& resultPublicId, | 695 ServerContext::StoreResult ServerContext::Store(std::string& resultPublicId, |
675 DicomInstanceToStore& dicom, | 696 DicomInstanceToStore& dicom, |
676 StoreInstanceMode mode) | 697 StoreInstanceMode mode) |
677 { | 698 { |
678 if (!isIngestTranscoding_) | 699 if (!isIngestTranscoding_) |
679 { | 700 { |
680 // No automated transcoding. This was the only path in Orthanc <= 1.6.1. | 701 // No automated transcoding. This was the only path in Orthanc <= 1.6.1. |
681 return StoreAfterTranscoding(resultPublicId, dicom, mode); | 702 return StoreAfterTranscoding(resultPublicId, dicom, mode); |
731 std::unique_ptr<ParsedDicomFile> tmp(transcoded.ReleaseAsParsedDicomFile()); | 752 std::unique_ptr<ParsedDicomFile> tmp(transcoded.ReleaseAsParsedDicomFile()); |
732 | 753 |
733 std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromParsedDicomFile(*tmp)); | 754 std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromParsedDicomFile(*tmp)); |
734 toStore->SetOrigin(dicom.GetOrigin()); | 755 toStore->SetOrigin(dicom.GetOrigin()); |
735 | 756 |
736 StoreStatus ok = StoreAfterTranscoding(resultPublicId, *toStore, mode); | 757 StoreResult result = StoreAfterTranscoding(resultPublicId, *toStore, mode); |
737 assert(resultPublicId == tmp->GetHasher().HashInstance()); | 758 assert(resultPublicId == tmp->GetHasher().HashInstance()); |
738 | 759 |
739 return ok; | 760 return result; |
740 } | 761 } |
741 else | 762 else |
742 { | 763 { |
743 // Cannot transcode => store the original file | 764 // Cannot transcode => store the original file |
744 return StoreAfterTranscoding(resultPublicId, dicom, mode); | 765 return StoreAfterTranscoding(resultPublicId, dicom, mode); |