2023-09-25 09:01:51 +02:00

337 lines
13 KiB
VB.net

Imports System.Net.Http
Imports Newtonsoft.Json
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.Base.ModuleExtensions
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Imports Connectors.Common.slt.Constants
Imports Connectors.Common.slt.Responses
Imports Connectors.Common.slt.Entities
Imports System.Threading.Tasks
Imports System.IO
Namespace slt
Public Class sltSync
Inherits BaseModule
Implements ISync
Private ReadOnly MimeEx As MimeEx
Public Overrides Property Name As String = "slt Sync"
Public Overrides Property IsLoggedIn As Boolean = False
Public SessionId As String = Nothing
Public AvailableSystems As New List(Of sltAvailableSystem)
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pConfig As Config)
MyBase.New(pLogConfig, pDatabase, pConfig)
MimeEx = New MimeEx(pLogConfig)
End Sub
Public Overrides Async Function Run() As Threading.Tasks.Task Implements ISync.Run
Try
AddInfoEntry("Starting sltSync.")
AddDivider()
EnsureOutputDirectoryExists()
RefreshDirectoryGuid()
Dim oExtDocIds = Await FetchDocIds()
If oExtDocIds Is Nothing Then
Throw New ApplicationException($"Document Ids could not be fetched!")
End If
AddInfoEntry("Logging in..")
Await GetAvailableSystems()
Await Login(Config.sltConfiguration.SystemId)
For Each oDocId As String In oExtDocIds
Try
Logger.Debug("Fetching document from API..")
Dim oDocument As sltDocument = Await GetDocumentContent(oDocId)
oDocument = Await GetDocumentDetails(oDocument)
Logger.Debug("Document fetched!")
AddInfoEntry("Document: [{0}]", oDocument.Name)
Logger.Info("ExtDocId: [{0}]", oDocument.ExtDocId)
Dim oFileName = oDocument.GetUniqueFilename()
If oFileName Is Nothing Then
Throw New ApplicationException($"Filename or extension for ExDocId [{oDocId}] could not be determined!")
End If
Dim oFilePath = GetFinalFilePath(oFileName)
If CopyFileToOutputPath(oDocument.Data, oFilePath) = False Then
Throw New ApplicationException("File could not be created in output path!")
End If
Dim oSQL = String.Format(Config.SQLQueryExport, oDocument.ExtDocId, oFileName)
If Await Database.ExecuteNonQueryAsync(oSQL) = True Then
RaiseFileProcessed(oFilePath)
Else
Throw New ApplicationException("Database entry could not be written!")
End If
Catch ex As Exception
RaiseFileError(oDocId)
Logger.Error(ex)
AddWarnEntry("Error while running Sync: " & ex.Message)
End Try
Next
Catch ex As Exception
Logger.Error(ex)
AddWarnEntry("Error while running Sync: " & ex.Message)
End Try
Try
AddInfoEntry("Finished Sync.")
AddInfoEntry("Logging Out..")
Await Logout()
Catch ex As Exception
Logger.Error(ex)
AddWarnEntry("Error while logging out: " & ex.Message)
Finally
AddDivider()
End Try
End Function
Public Overrides Async Function Cleanup() As Task Implements ISync.Cleanup
Await Logout()
End Function
Public Overrides Function TestConfigIsComplete() As Boolean Implements ISync.TestConfigIsComplete
Dim oComplete = TestConfigIsCompleteBase()
If Config.sltConfiguration.Hostname = String.Empty Then
AddWarnEntry("Configuration for 'Hostname' is empty.")
oComplete = False
End If
If Config.sltConfiguration.Port = String.Empty Then
AddWarnEntry("Configuration for 'Port' is empty.")
oComplete = False
End If
If Config.sltConfiguration.Username = String.Empty Then
AddWarnEntry("Configuration for 'Username' is empty.")
oComplete = False
End If
If Config.sltConfiguration.Password = String.Empty Then
AddWarnEntry("Configuration for 'Password' is empty.")
oComplete = False
End If
If Config.sltConfiguration.sltDatabase = String.Empty Then
AddWarnEntry("Configuration for 'sltDatabase' is empty.")
oComplete = False
End If
Return oComplete
End Function
Private Function GetFilenameWithExtensionFromMimeType(pFilename As String, pMimetype As String) As String
Try
If pMimetype = "application/outlook" Then
pMimetype = "application/vnd.ms-outlook"
End If
Dim oExtension = MimeEx.GetExtension(pMimetype)
Return StringEx.ConvertTextToSlug(pFilename) & oExtension
Catch ex As ArgumentException
Logger.Error(ex)
Logger.Warn("File [{0}] does not have a valid mimetype [{1}]. Returning null.", pFilename, pMimetype)
Return Nothing
Catch ex As Exception
Logger.Error(ex)
AddWarnEntry("Unexpected error while getting extension. Returning original filename.", pFilename, pMimetype)
Return pFilename
End Try
End Function
Private Async Function GetAvailableSystems() As Threading.Tasks.Task
Try
Logger.Debug("Fetching available systems..")
Dim oUrl = "/slt/External/System/Authentication/Json/AvailableSystems"
Dim oJson As String = Await SendRequest(oUrl)
Dim oResponse = JsonConvert.DeserializeObject(Of sltAvailableSystemResponse)(oJson)
TestRequestSuccessful(oUrl, oResponse, ErrorType.AvailableSystemError)
AvailableSystems = oResponse.Value
Logger.Debug("Fetched [{0}] available systems!", oResponse.Value.Count)
Catch ex As Exception
Logger.Error(ex)
Throw New sltException(ErrorType.AvailableSystemError, ex.Message)
End Try
End Function
Private Async Function Login(pSystemId As String) As Threading.Tasks.Task
Try
Logger.Debug("Logging in..")
If AvailableSystems.Any(Function(s) s.SystemId = pSystemId) = False Then
Dim oMessage = String.Format("SystemId [{0}] does not match any System returned from API.", pSystemId)
Logger.Warn(oMessage)
Throw New sltException(ErrorType.LoginError, oMessage)
End If
Dim oUrl = "/slt/External/System/Authentication/Json/Login"
Dim oParams = New Dictionary(Of String, String) From {
{"systemid", pSystemId},
{"user", Config.sltConfiguration.Username},
{"password", Config.sltConfiguration.Password}
}
Logger.Debug("Username: [{0}]", Config.sltConfiguration.Username)
Logger.Debug("SystemId: [{0}]", pSystemId)
Dim oJson As String = Await SendRequest(oUrl, oParams)
Dim oResponse = JsonConvert.DeserializeObject(Of sltLoginResponse)(oJson)
TestRequestSuccessful(oUrl, oResponse, ErrorType.LoginError)
SessionId = oResponse.Value
IsLoggedIn = True
Logger.Debug("Login successful!")
Catch ex As Exception
Logger.Error(ex)
Throw New sltException(ErrorType.LoginError, ex.Message)
End Try
End Function
Private Async Function Logout() As Threading.Tasks.Task
If Not IsLoggedIn Then
Throw New sltException(ErrorType.NotLoggedInError, "No session found")
End If
Logger.Debug("Logging out..")
Try
Dim oUrl = "/slt/External/System/Authentication/Json/Logout"
Dim oParams = New Dictionary(Of String, String) From {
{"SessionId", SessionId}
}
Dim oJson As String = Await SendRequest(oUrl, oParams)
Dim oResponse = JsonConvert.DeserializeObject(Of sltLogoutResponse)(oJson)
TestRequestSuccessful(oUrl, oResponse, ErrorType.LogoutError)
SessionId = Nothing
IsLoggedIn = False
Logger.Debug("Login successful!")
Catch ex As Exception
Logger.Error(ex)
Throw New sltException(ErrorType.LogoutError, ex.Message)
End Try
End Function
Private Async Function GetDocumentDetails(pDocument As sltDocument) As Task(Of sltDocument)
If Not IsLoggedIn Then
Throw New sltException(ErrorType.NotLoggedInError, "No session found")
End If
Try
Logger.Debug("Fetching document details with ExtDocId [{0}]", pDocument.ExtDocId)
Dim oSQL = $"SELECT DOCORIGINALNAME
FROM {Config.sltConfiguration.sltDatabase}.[EXTDOCS]
WHERE EXTDOCID = '{pDocument.ExtDocId}'"
Dim oResult As Object = Await Database.GetScalarValueAsync(oSQL)
Dim oFileNameOriginal As String = ObjectEx.NotNull(Of String)(oResult.ToString, "")
If Not String.IsNullOrEmpty(oFileNameOriginal) Then
pDocument.DocOriginalFilename = oFileNameOriginal
End If
Return pDocument
Catch ex As Exception
Logger.Error(ex)
Return pDocument
End Try
End Function
Private Async Function GetDocumentContent(pExternalDocumentId As String) As Threading.Tasks.Task(Of slt.Entities.sltDocument)
If Not IsLoggedIn Then
Throw New sltException(ErrorType.NotLoggedInError, "No session found")
End If
Try
Logger.Debug("Fetching document with ExtDocId [{0}]", pExternalDocumentId)
Dim oUrl = "/slt/External/Services/Allgemein/ExtDocs/JSon/GetDocument"
Dim oParams As New Dictionary(Of String, String) From {
{"extdocid", pExternalDocumentId},
{"sessionid", SessionId}
}
Dim oJson = Await SendRequest(oUrl, oParams)
Dim oResponse = JsonConvert.DeserializeObject(Of sltDocumentResponse)(oJson)
Logger.Debug("Document Fetched!")
Return oResponse.Value
Catch ex As Exception
Logger.Error(ex)
Throw New sltException(ErrorType.GetDocumentError, ex.Message)
End Try
End Function
Private Async Function SendRequest(pUrl As String) As Threading.Tasks.Task(Of String)
Return Await SendRequest(pUrl, New Dictionary(Of String, String))
End Function
Private Async Function SendRequest(pUrl As String, pQueryParams As Dictionary(Of String, String)) As Threading.Tasks.Task(Of String)
Try
Dim oUrl = GetUrl(pUrl, pQueryParams)
Logger.Debug("Preparing request to: [{0}]", oUrl)
Using oClient As New HttpClient()
oClient.DefaultRequestHeaders.Accept.Clear()
oClient.DefaultRequestHeaders.Accept.Add(New Headers.MediaTypeWithQualityHeaderValue("application/json"))
oClient.DefaultRequestHeaders.Add("User-Agent", "Digital Data sltSync")
Logger.Debug("Sending request.")
Return Await oClient.GetStringAsync(oUrl)
End Using
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Private Function GetUrl(pPath As String, pQueryParams As Dictionary(Of String, String)) As String
Dim oUrl As String = $"http://{Config.sltConfiguration.Hostname}:{Config.sltConfiguration.Port}"
If Not pPath.StartsWith("/") Then pPath &= "/"
Dim queryString = pQueryParams.ToURLQueryString()
Return $"{oUrl}{pPath}?{queryString}"
End Function
Private Sub TestRequestSuccessful(pUrl As String, pResponse As Responses.sltResponse, pErrorType As Constants.ErrorType)
If pResponse.State = False Then
Logger.Warn("Request to Url [{0}] returned error.", pUrl)
Logger.Error(pResponse.Message)
Throw New sltException(pErrorType, pResponse.Message)
End If
End Sub
End Class
End Namespace