Skip to content

Instantly share code, notes, and snippets.

@darkl

darkl/Caleee.cs Secret

Created June 5, 2021 03:54
Show Gist options
  • Save darkl/08e66ddf9b59fa684582365a774a019b to your computer and use it in GitHub Desktop.
Save darkl/08e66ddf9b59fa684582365a774a019b to your computer and use it in GitHub Desktop.
WampSharp dealer cache
using System;
using System.Threading.Tasks;
using WampSharp.V2;
using WampSharp.V2.Client;
using WampSharp.V2.Rpc;
namespace Callee
{
public interface IRandomService
{
[WampProcedure("com.arguments.random")]
int Random();
}
public class RandomService : IRandomService
{
public int Random()
{
Random random = new Random();
return random.Next();
}
}
class Program
{
public static async Task Main()
{
const string location = "ws://127.0.0.1:8080/ws";
DefaultWampChannelFactory channelFactory = new DefaultWampChannelFactory();
IWampChannel channel = channelFactory.CreateJsonChannel(location, "realm1");
await channel.Open().ConfigureAwait(false);
IRandomService instance = new RandomService();
IWampRealmProxy realm = channel.RealmProxy;
IAsyncDisposable disposable =
await realm.Services.RegisterCallee(instance).ConfigureAwait(false);
// This line is required in order to release the WebSocket thread, otherwise it will be blocked by the following Console.ReadLine() line.
await Task.Yield();
Console.WriteLine("Press enter to unregister");
Console.ReadLine();
await disposable.DisposeAsync().ConfigureAwait(false);
Console.WriteLine("Unregistered!");
}
}
}
using System;
using System.Threading.Tasks;
using WampSharp.V2;
using WampSharp.V2.Rpc;
namespace MyNamespace
{
public interface IRandomService
{
[WampProcedure("com.arguments.random")]
Task<int> RandomAsync();
}
internal class Program
{
public static async Task Main(string[] args)
{
DefaultWampChannelFactory factory =
new DefaultWampChannelFactory();
const string serverAddress = "ws://127.0.0.1:8080/ws";
IWampChannel channel =
factory.CreateJsonChannel(serverAddress, "realm1");
await channel.Open().ConfigureAwait(false);
IRandomService proxy =
channel.RealmProxy.Services.GetCalleeProxy<IRandomService>();
int value = await proxy.RandomAsync().ConfigureAwait(false);
Console.WriteLine("Random value: " + value);
Console.ReadLine();
}
}
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using WampSharp.Binding;
using WampSharp.Core.Serialization;
using WampSharp.Fleck;
using WampSharp.V2;
using WampSharp.V2.Core;
using WampSharp.V2.Core.Contracts;
using WampSharp.V2.PubSub;
using WampSharp.V2.Realm;
using WampSharp.V2.Rpc;
namespace RpcCacheRouter
{
class Program
{
static void Main(string[] args)
{
WampHost host = new WampHost(new RpcCacheWampRealmContainer());
host.RegisterTransport(new FleckWebSocketTransport("ws://127.0.0.1:8080/ws"),
new JTokenJsonBinding());
host.Open();
Console.ReadLine();
}
}
public class RpcCacheWampRealmContainer : IWampRealmContainer
{
private readonly IWampRealmContainer mContainer;
public RpcCacheWampRealmContainer() : this(new WampRealmContainer())
{
}
public RpcCacheWampRealmContainer(IWampRealmContainer container)
{
mContainer = container;
}
public IWampRealm GetRealmByName(string name)
{
IWampRealm realm = mContainer.GetRealmByName(name);
RpcCacheWampRealm wrapped = new RpcCacheWampRealm(realm);
return wrapped;
}
}
public class RpcCacheWampRealm : IWampRealm
{
private readonly IWampRealm mRealm;
private readonly IWampRpcOperationCatalog mRpcCacheOperationCatalog;
public RpcCacheWampRealm(IWampRealm realm)
{
mRealm = realm;
mRpcCacheOperationCatalog = new RpcCacheWampRpcOperationCatalog(mRealm.RpcCatalog);
}
public string Name => mRealm.Name;
public IWampRpcOperationCatalog RpcCatalog => mRpcCacheOperationCatalog;
public IWampTopicContainer TopicContainer => mRealm.TopicContainer;
}
public class RpcCacheWampRpcOperationCatalog : IWampRpcOperationCatalog
{
private readonly IWampRpcOperationCatalog mRpcOperationCatalog;
private readonly IRpcInvocationCache mInvocationCache = new LocalRpcInvocationCache();
public RpcCacheWampRpcOperationCatalog(IWampRpcOperationCatalog rpcOperationCatalog)
{
mRpcOperationCatalog = rpcOperationCatalog;
}
public IWampCancellableInvocation Invoke<TMessage>(IWampRawRpcOperationRouterCallback caller, IWampFormatter<TMessage> formatter,
InvocationDetails details, string procedure)
{
if (mRpcOperationCatalog.GetMatchingOperation(procedure) != null)
{
return mRpcOperationCatalog.Invoke(new RpcCacheWampRawOperationRouterCallback(caller, procedure, mInvocationCache),
formatter, details, procedure);
}
else
{
if (!mInvocationCache.TryGetInvocationResult(procedure, out ResultArguments resultArguments))
{
// Call "base" to throw an exception.
return mRpcOperationCatalog.Invoke(caller, formatter, details, procedure);
}
else
{
if (resultArguments.ArgumentsKeywords != null)
{
caller.Result(WampObjectFormatter.Value, resultArguments.YieldOptions,
resultArguments.Arguments, resultArguments.ArgumentsKeywords);
}
else if (resultArguments.Arguments != null)
{
caller.Result(WampObjectFormatter.Value, resultArguments.YieldOptions,
resultArguments.Arguments);
}
else
{
caller.Result(WampObjectFormatter.Value, resultArguments.YieldOptions);
}
return null;
}
}
}
public IWampCancellableInvocation Invoke<TMessage>(IWampRawRpcOperationRouterCallback caller, IWampFormatter<TMessage> formatter,
InvocationDetails details, string procedure, TMessage[] arguments)
{
if (arguments.Length == 0)
{
return Invoke(caller, formatter, details, procedure);
}
return mRpcOperationCatalog.Invoke(caller, formatter, details, procedure, arguments);
}
public IWampCancellableInvocation Invoke<TMessage>(IWampRawRpcOperationRouterCallback caller, IWampFormatter<TMessage> formatter,
InvocationDetails details, string procedure, TMessage[] arguments,
IDictionary<string, TMessage> argumentsKeywords)
{
return mRpcOperationCatalog.Invoke(caller, formatter, details, procedure, arguments, argumentsKeywords);
}
public IWampRegistrationSubscriptionToken Register(IWampRpcOperation operation, RegisterOptions options)
{
return mRpcOperationCatalog.Register(operation, options);
}
public event EventHandler<WampProcedureRegisterEventArgs> RegistrationAdded
{
add => mRpcOperationCatalog.RegistrationAdded += value;
remove => mRpcOperationCatalog.RegistrationAdded -= value;
}
public event EventHandler<WampProcedureRegisterEventArgs> RegistrationRemoved
{
add => mRpcOperationCatalog.RegistrationRemoved += value;
remove => mRpcOperationCatalog.RegistrationRemoved -= value;
}
public IWampRpcOperation GetMatchingOperation(string criteria)
{
return mRpcOperationCatalog.GetMatchingOperation(criteria);
}
private class RpcCacheWampRawOperationRouterCallback : IWampRawRpcOperationRouterCallback
{
private readonly IWampRawRpcOperationRouterCallback mCallback;
private readonly string mProcedureName;
private readonly IRpcInvocationCache mInvocationCache;
public RpcCacheWampRawOperationRouterCallback(
IWampRawRpcOperationRouterCallback callback, string procedureName,
IRpcInvocationCache invocationCache)
{
mCallback = callback;
mProcedureName = procedureName;
mInvocationCache = invocationCache;
}
public void Result<TMessage>(IWampFormatter<TMessage> formatter, YieldOptions options)
{
mInvocationCache.MapInvocationToResult(mProcedureName, new ResultArguments(options));
mCallback.Result(formatter, options);
}
public void Result<TMessage>(IWampFormatter<TMessage> formatter, YieldOptions options, TMessage[] arguments)
{
mInvocationCache.MapInvocationToResult(mProcedureName, ResultArguments.FromArguments(options, arguments));
mCallback.Result(formatter, options, arguments);
}
public void Result<TMessage>(IWampFormatter<TMessage> formatter, YieldOptions options, TMessage[] arguments,
IDictionary<string, TMessage> argumentsKeywords)
{
mInvocationCache.MapInvocationToResult(mProcedureName, ResultArguments.FromArguments(options, arguments, argumentsKeywords));
mCallback.Result(formatter, options, arguments, argumentsKeywords);
}
public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error)
{
mCallback.Error(formatter, details, error);
}
public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error, TMessage[] arguments)
{
mCallback.Error(formatter, details, error, arguments);
}
public void Error<TMessage>(IWampFormatter<TMessage> formatter, TMessage details, string error, TMessage[] arguments,
TMessage argumentsKeywords)
{
mCallback.Error(formatter, details, error, arguments, argumentsKeywords);
}
}
}
public class ResultArguments
{
public YieldOptions YieldOptions { get; }
public object[] Arguments { get; }
public IDictionary<string, object> ArgumentsKeywords { get; }
public ResultArguments(YieldOptions yieldOptions,
object[] arguments = null,
IDictionary<string, object> argumentsKeywords = null)
{
YieldOptions = yieldOptions;
Arguments = arguments;
ArgumentsKeywords = argumentsKeywords;
}
public static ResultArguments FromArguments<TMessage>
(YieldOptions yieldOptions,
TMessage[] arguments = null,
IDictionary<string, TMessage> argumentsKeywords = null)
{
return new ResultArguments(yieldOptions,
arguments?.Cast<object>().ToArray(),
argumentsKeywords?.ToDictionary(x => x.Key,
x => (object)x.Value));
}
}
public interface IRpcInvocationCache
{
void MapInvocationToResult(string procedure,
ResultArguments resultArguments);
bool TryGetInvocationResult(string procedure,
out ResultArguments value);
}
public class LocalRpcInvocationCache : IRpcInvocationCache
{
private readonly ConcurrentDictionary<string, ResultArguments> mProcedureUriToResult =
new ConcurrentDictionary<string, ResultArguments>();
public void MapInvocationToResult(string procedure, ResultArguments resultArguments)
{
mProcedureUriToResult[procedure] = resultArguments;
}
public bool TryGetInvocationResult(string procedure, out ResultArguments value)
{
return mProcedureUriToResult.TryGetValue(procedure, out value);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment