Skip to content

Commit

Permalink
Added IO for global library functions (#284)
Browse files Browse the repository at this point in the history
new Trait HasSAPRfcLibrary<RT> with RfcLibraryIO
  • Loading branch information
fw2568 authored Mar 21, 2024
1 parent f53cfd5 commit 8b8aba2
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 4 deletions.
1 change: 1 addition & 0 deletions YaNco.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=BAPI/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=BAPIRET/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Configurer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cpic/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Dbosoft/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=IDOC/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Interopt/@EntryIndexedValue">True</s:Boolean>
Expand Down
1 change: 1 addition & 0 deletions src/YaNco.Abstractions/SAPRfcRuntimeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,5 @@ public SAPRfcRuntimeSettings(ILogger logger, IFieldMapper fieldMapper, RfcRuntim
public SAPRfcFunctionIO RfcFunctionIO { get; set; }
public SAPRfcConnectionIO RfcConnectionIO { get; set; }
public SAPRfcServerIO RfcServerIO { get; set; }
public SAPRfcLibraryIO RfcLibraryIO { get; set; }
}
13 changes: 13 additions & 0 deletions src/YaNco.Abstractions/Traits/HasSAPRfcLibrary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using JetBrains.Annotations;
using LanguageExt;

namespace Dbosoft.YaNco.Traits;

[PublicAPI]
// ReSharper disable once InconsistentNaming
public interface HasSAPRfcLibrary<RT> : IHasEnvRuntimeSettings
where RT : struct
{
Eff<RT, SAPRfcLibraryIO> RfcLibraryEff { get; }

}
17 changes: 17 additions & 0 deletions src/YaNco.Abstractions/Traits/SAPRfcLibraryIO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using LanguageExt;

namespace Dbosoft.YaNco.Traits;

// ReSharper disable once InconsistentNaming
public interface SAPRfcLibraryIO
{
Either<RfcError, System.Version> GetVersion();
Either<RfcError, Unit> SetTraceDirectory(string traceDirectory);
Either<RfcError, Unit> SetMaximumTraceFiles(int traceFiles);
Either<RfcError, Unit> SetCpicTraceLevel(int traceLevel);

Either<RfcError, Unit> LoadCryptoLibrary(string libraryPath);
Either<RfcError, Unit> SetIniDirectory(string iniDirectory);
Either<RfcError, Unit> ReloadRfcIni();

}
36 changes: 35 additions & 1 deletion src/YaNco.Core/Internal/Api.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,41 @@ namespace Dbosoft.YaNco.Internal;
[ExcludeFromCodeCoverage]
public static class Api
{

public static Version GetVersion()
{
_ = Interopt.RfcGetVersion(out var major, out var minor, out var patch);
return new Version((int) major, (int) minor, (int) patch);
}

public static RfcRc SetTraceDirectory(string traceDirectory, out RfcErrorInfo errorInfo)
{
return Interopt.RfcSetTraceDir(traceDirectory, out errorInfo);
}
public static RfcRc SetMaximumTraceFiles(int maxTraceFiles, out RfcErrorInfo errorInfo)
{
return Interopt.RfcSetMaximumStoredTraceFiles(maxTraceFiles, out errorInfo);
}

public static RfcRc SetCpicTraceLevel(int traceLevel, out RfcErrorInfo errorInfo)
{
return Interopt.RfcSetCpicTraceLevel((uint) traceLevel, out errorInfo);
}

public static RfcRc SetIniDirectory(string iniDirectory, out RfcErrorInfo errorInfo)
{
return Interopt.RfcSetIniPath(iniDirectory, out errorInfo);
}

public static RfcRc ReloadIniFile(out RfcErrorInfo errorInfo)
{
return Interopt.RfcReloadIniFile(out errorInfo);
}

public static RfcRc LoadCryptoLibrary(string libraryPath, out RfcErrorInfo errorInfo)
{
return Interopt.RfcLoadCryptoLibrary(libraryPath, out errorInfo);
}

public static ConnectionHandle OpenConnection(IDictionary<string, string> connectionParams,
out RfcErrorInfo errorInfo)
{
Expand Down
26 changes: 25 additions & 1 deletion src/YaNco.Core/Internal/Interopt.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

// ReSharper disable IdentifierTypo
// ReSharper disable CommentTypo
// ReSharper disable InconsistentNaming

namespace Dbosoft.YaNco.Internal;

Expand All @@ -12,9 +16,29 @@ internal static class Interopt
private const string SapNwRfcName = "sapnwrfc";

[DllImport(SapNwRfcName)]
public static extern RfcRc RfcGetVersion(out uint majorVersion, out uint minorVersion, out uint patchLevel);
public static extern IntPtr RfcGetVersion(out uint majorVersion, out uint minorVersion, out uint patchLevel);

[DllImport(SapNwRfcName, CharSet = CharSet.Unicode)]
public static extern RfcRc RfcSetTraceDir(string traceDir, out RfcErrorInfo errorInfo);


[DllImport(SapNwRfcName)]
public static extern RfcRc RfcSetMaximumStoredTraceFiles(int numberOfFiles, out RfcErrorInfo errorInfo);


[DllImport(SapNwRfcName)]
public static extern RfcRc RfcSetCpicTraceLevel(uint traceLevel, out RfcErrorInfo errorInfo);


[DllImport(SapNwRfcName, CharSet = CharSet.Unicode)]
public static extern RfcRc RfcLoadCryptoLibrary(string pathToLibrary, out RfcErrorInfo errorInfo);

[DllImport(SapNwRfcName, CharSet = CharSet.Unicode)]
public static extern RfcRc RfcSetIniPath(string pathName, out RfcErrorInfo errorInfo);

[DllImport(SapNwRfcName)]
public static extern RfcRc RfcReloadIniFile(out RfcErrorInfo errorInfo);

[DllImport(SapNwRfcName, CharSet = CharSet.Unicode)]
public static extern IntPtr RfcOpenConnection(RfcConnectionParameter[] connectionParams, uint paramCount, out RfcErrorInfo errorInfo);

Expand Down
15 changes: 15 additions & 0 deletions src/YaNco.Core/Live/IOResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,19 @@ public static Either<RfcError, TResult> ResultOrError<TResult>(
logger.IfSome(l => l.LogTrace("received result value from rfc call", result));
return result;
}

public static Either<RfcError, TResult> ResultOrError<TResult>(
Option<ILogger> logger,
TResult result, RfcRc rc)
{
if (rc != RfcRc.RFC_OK)
{
logger.IfSome(l => l.LogDebug("received error from rfc call",
rc));
return RfcError.Error(rc);
}

logger.IfSome(l => l.LogTrace("received result value from rfc call", result));
return result;
}
}
59 changes: 59 additions & 0 deletions src/YaNco.Core/Live/LiveSAPRfcLibraryIO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using Dbosoft.YaNco.Internal;
using Dbosoft.YaNco.Traits;
using LanguageExt;

namespace Dbosoft.YaNco.Live;

public readonly struct LiveSAPRfcLibraryIO : SAPRfcLibraryIO
{
private readonly Option<ILogger> _logger;

public LiveSAPRfcLibraryIO(Option<ILogger> logger)
{
_logger = logger;
}

public Either<RfcError, Version> GetVersion()
{
return Prelude.Try(Api.GetVersion).ToEither(f => RfcError.New(f));

}

public Either<RfcError, Unit> SetTraceDirectory(string traceDirectory)
{
var rc = Api.SetTraceDirectory(traceDirectory, out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

public Either<RfcError, Unit> SetMaximumTraceFiles(int traceFiles)
{
var rc = Api.SetMaximumTraceFiles(traceFiles, out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

public Either<RfcError, Unit> SetCpicTraceLevel(int traceLevel)
{
var rc = Api.SetCpicTraceLevel(traceLevel, out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

public Either<RfcError, Unit> LoadCryptoLibrary(string libraryPath)
{
var rc = Api.LoadCryptoLibrary(libraryPath, out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

public Either<RfcError, Unit> SetIniDirectory(string iniDirectory)
{
var rc = Api.SetIniDirectory(iniDirectory, out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

public Either<RfcError, Unit> ReloadRfcIni()
{
var rc = Api.ReloadIniFile(out var errorInfo);
return IOResult.ResultOrError(_logger, Unit.Default, rc, errorInfo);
}

}
1 change: 0 additions & 1 deletion src/YaNco.Core/Live/LiveSAPRfcServerIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

namespace Dbosoft.YaNco.Live;


public readonly struct LiveSAPRfcServerIO : SAPRfcServerIO
{
private readonly Option<ILogger> _logger;
Expand Down
7 changes: 6 additions & 1 deletion src/YaNco.Core/Live/SAPRfcRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace Dbosoft.YaNco.Live;
/// </summary>
public readonly struct SAPRfcRuntime

: HasSAPRfc<SAPRfcRuntime>,
: HasSAPRfc<SAPRfcRuntime>,
HasSAPRfcLibrary<SAPRfcRuntime>,
HasSAPRfcServer<SAPRfcRuntime>,
HasCancel<SAPRfcRuntime>

Expand Down Expand Up @@ -84,6 +85,7 @@ public static SAPRfcRuntime New(CancellationTokenSource cancellationTokenSource,
private SAPRfcFunctionIO FunctionIO => Env.Settings.RfcFunctionIO ?? new LiveSAPRfcFunctionIO(Logger, DataIO);
private SAPRfcConnectionIO ConnectionIO => Env.Settings.RfcConnectionIO ?? new LiveSAPRfcConnectionIO(Logger);
private SAPRfcServerIO ServerIO => Env.Settings.RfcServerIO ?? new LiveSAPRfcServerIO(Logger);
private SAPRfcLibraryIO LibraryIO => Env.Settings.RfcLibraryIO ?? new LiveSAPRfcLibraryIO(Logger);


public Eff<SAPRfcRuntime, Option<ILogger>> RfcLoggerEff => Prelude.Eff<SAPRfcRuntime, Option<ILogger>>(rt => rt.Logger);
Expand All @@ -102,4 +104,7 @@ public static SAPRfcRuntime New(CancellationTokenSource cancellationTokenSource,

public Eff<SAPRfcRuntime, IFieldMapper> FieldMapperEff => Prelude.Eff < SAPRfcRuntime, IFieldMapper>(
rt => rt.Env.Settings.FieldMapper);

public Eff<SAPRfcRuntime, SAPRfcLibraryIO> RfcLibraryEff => Prelude.Eff<SAPRfcRuntime, SAPRfcLibraryIO>(
rt => rt.LibraryIO);
}
4 changes: 4 additions & 0 deletions src/YaNco.Core/Test/TestSAPRfcRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public readonly struct TestSAPRfcRuntime

: HasSAPRfcServer<TestSAPRfcRuntime>,
HasSAPRfc<TestSAPRfcRuntime>,
HasSAPRfcLibrary<TestSAPRfcRuntime>,
HasCancel<TestSAPRfcRuntime>
{
private readonly SAPRfcRuntimeEnv<SAPRfcRuntimeSettings> _env;
Expand Down Expand Up @@ -84,4 +85,7 @@ public static TestSAPRfcRuntime New(Action<SAPRfcRuntimeSettings> configure)

public Eff<TestSAPRfcRuntime, IFieldMapper> FieldMapperEff => Prelude.Eff<TestSAPRfcRuntime, IFieldMapper>(
rt => rt.Env.Settings.FieldMapper);

public Eff<TestSAPRfcRuntime, SAPRfcLibraryIO> RfcLibraryEff => Prelude.Eff<TestSAPRfcRuntime, SAPRfcLibraryIO>(
rt => rt.Env.Settings.RfcLibraryIO);
}
12 changes: 12 additions & 0 deletions test/SAPSystemTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ from call in invokeFunction(c, "ZYANCO_IT_3")

// functional style Tests:

// library tests
var libVersion = SAPRfcRuntime.Default.RfcLibraryEff.Bind(io =>
{
return (
from _ in io.SetTraceDirectory(AppDomain.CurrentDomain.BaseDirectory)
from version in io.GetVersion()
select version).ToEff(l => l);
})
.Run(SAPRfcRuntime.Default);

Console.WriteLine("Library Version: " + libVersion);

var connectionEffect = new ConnectionBuilder(settings)
.ConfigureRuntime(c=>c.WithLogger(new SimpleConsoleLogger()))
.BuildIO();
Expand Down

2 comments on commit 8b8aba2

@xmbozkir
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, We're using your library for listening the IDOC gateway. We implemented for two system, when the program is starting to run, it connects two system.
But when we send IDOCs from ERP to our solution, there is an error (sometimes) as System.ArgumentException: 'The key already existed in the dictionary.' on CachingConverterResolver.cs

`using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;

namespace Digitanol.YaNco.TypeMapping
{
public class CachingConverterResolver : IRfcConverterResolver
{
private readonly IRfcConverterResolver _decoratedResolver;

    public CachingConverterResolver(IRfcConverterResolver decoratedResolver)
    {
        _decoratedResolver = decoratedResolver;
    }

    private readonly IDictionary<string, object> _fromRfcConverters = new ConcurrentDictionary<string, object>();
    private readonly IDictionary<string, object> _toRfcConverters = new ConcurrentDictionary<string, object>();

    public IEnumerable<IToAbapValueConverter<T>> GetToRfcConverters<T>(RfcType rfcType)
    {
        var sourceType = typeof(T);
        var key = $"{rfcType}_{sourceType}";

        if (!_toRfcConverters.ContainsKey(key))
        {
            var converters = _decoratedResolver.GetToRfcConverters<T>(rfcType).ToArray();
            _toRfcConverters.Add(key, converters.Length == 0 ? null : converters);

        }

        var entry = _toRfcConverters[key];

        if (entry != null)
            return (IEnumerable<IToAbapValueConverter<T>>)entry;
        return new IToAbapValueConverter<T>[0];


    }

    public IEnumerable<IFromAbapValueConverter<T>> GetFromRfcConverters<T>(RfcType rfcType, Type abapValueType)
    {
        var targetType = typeof(T);
        var key = $"{rfcType}_{targetType}";

        if (!_fromRfcConverters.ContainsKey(key))
        {
            var converters = _decoratedResolver.GetFromRfcConverters<T>(rfcType, abapValueType).ToArray();
            _fromRfcConverters.Add(key, converters.Length == 0 ? null : converters);
        }

        var entry = _fromRfcConverters[key];

        if (entry != null)
            return (IEnumerable<IFromAbapValueConverter<T>>)entry;
        return new IFromAbapValueConverter<T>[0];
    }
}

}`

Do you have any solution about this problem? How can we solve this issue, please let us know.

Thanks a lot!

@fw2568
Copy link
Contributor Author

@fw2568 fw2568 commented on 8b8aba2 Apr 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please create a issue or a discussion instead of a comment to a single commit. These are very difficult to find for anyone.

Please sign in to comment.