gRPC StarLink Router .Net - c#

New Info:
I thought I would paste this in full as I can not seem to find any samples on the web of a c# solution for StarLink so hopefully anyone else looking for something may find this helpful and may contribute.
My New Proto File - (partial) - I took the advise of Yuri below. Thanks for the direction here. I was able to I have been using this tool and it has brought a lot of insight but I am still stuck on the c# side of the solution. I am an old VB.Net developer though I have done a bunch in c# I am by no means savvy in it and am probably missing something so simple. Again, any insight would be awesome. I can not post the full proto here as stack has char limit on posts. this is the first bit with messages etc. I can post more if it helps but trying to keep it to the important part.
syntax = "proto3";
option csharp_namespace = "SpaceX.API.Device";
package SpaceX.API.Device;
service Device {
//rpc Handle (.SpaceX.API.Device.Request) returns (.SpaceX.API.Device.Response) {}
//rpc Stream (stream .SpaceX.API.Device.ToDevice) returns (stream .SpaceX.API.Device.FromDevice) {}
rpc Handle (Request) returns (Response);
rpc Stream (Request) returns (Response);
}
message ToDevice {
string message = 1;
}
message Request {
uint64 id = 1;
string target_id = 13;
uint64 epoch_id = 14;
oneof request {
SignedData signed_request = 15;
RebootRequest reboot = 1001;
SpeedTestRequest speed_test = 1003;
GetStatusRequest get_status = 1004;
AuthenticateRequest authenticate = 1005;
GetNextIdRequest get_next_id = 1006;
GetHistoryRequest get_history = 1007;
GetDeviceInfoRequest get_device_info = 1008;
GetPingRequest get_ping = 1009;
SetTrustedKeysRequest set_trusted_keys = 1010;
FactoryResetRequest factory_reset = 1011;
GetLogRequest get_log = 1012;
SetSkuRequest set_sku = 1013;
UpdateRequest update = 1014;
GetNetworkInterfacesRequest get_network_interfaces = 1015;
PingHostRequest ping_host = 1016;
GetLocationRequest get_location = 1017;
EnableFlowRequest enable_flow = 1018;
GetHeapDumpRequest get_heap_dump = 1019;
RestartControlRequest restart_control = 1020;
FuseRequest fuse = 1021;
GetPersistentStatsRequest get_persistent_stats = 1022;
GetConnectionsRequest get_connections = 1023;
FlushTelemRequest flush_telem = 1026;
StartSpeedtestRequest start_speedtest = 1027;
GetSpeedtestStatusRequest get_speedtest_status = 1028;
ReportClientSpeedtestRequest report_client_speedtest = 1029;
InitiateRemoteSshRequest initiate_remote_ssh = 1030;
SelfTestRequest self_test = 1031;
SetTestModeRequest set_test_mode = 1032;
DishStowRequest dish_stow = 2002;
DishGetContextRequest dish_get_context = 2003;
DishSetEmcRequest dish_set_emc = 2007;
DishGetObstructionMapRequest dish_get_obstruction_map = 2008;
DishGetEmcRequest dish_get_emc = 2009;
DishSetConfigRequest dish_set_config = 2010;
DishGetConfigRequest dish_get_config = 2011;
StartDishSelfTestRequest start_dish_self_test = 2012;
WifiSetConfigRequest wifi_set_config = 3001;
WifiGetClientsRequest wifi_get_clients = 3002;
WifiSetupRequest wifi_setup = 3003;
WifiGetPingMetricsRequest wifi_get_ping_metrics = 3007;
WifiGetDiagnosticsRequest wifi_get_diagnostics = 3008;
WifiGetConfigRequest wifi_get_config = 3009;
WifiSetMeshDeviceTrustRequest wifi_set_mesh_device_trust = 3012;
WifiSetMeshConfigRequest wifi_set_mesh_config = 3013;
WifiGetClientHistoryRequest wifi_get_client_history = 3015;
TransceiverIFLoopbackTestRequest transceiver_if_loopback_test = 4001;
TransceiverGetStatusRequest transceiver_get_status = 4003;
TransceiverGetTelemetryRequest transceiver_get_telemetry = 4004;
}
reserved 1025, 3011, 3014;
}
message SignedData {
bytes data = 1;
bytes signature = 2;
}
My New .cs
I have tried many things from Microsoft's examples to thing I can gather from other samples. I simply can not get it to work and am lost. Again, any insight would be amazing and hopefully helpful to others looking for a solution in c#. You will see my commented code of this I have been playing with. Basically I am attempting to achieve three things and have made some movement in one of them.
Goals:
1 - Use Server Reflection to discover services.
I think I got this one resolved with dot-net grpc.
2 - Simply want to check available methods under a service and potentially either check or generate a new .proto file in case things change. StaLink does not publish its proto schema so I assume it could change anytime without warning.
3 - Just run any one of the available methods. I have tried the GetDeviceInfoRequest but can not seem to construct the request message properly. I have not been able to get this accomplishe in the gRPCurl tool either. I can do it on the basic service shown by Microsoft of course but these methods seem to be more complex and I simply get all kinds of errors.
Again, any insight or assistance would be amazing. Thanks to any and all in advance.
New .cs File
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Grpc.Core;
using Grpc.Net.Client;
using Grpc.Reflection.V1Alpha;
using ServerReflectionClient = Grpc.Reflection.V1Alpha.ServerReflection.ServerReflectionClient;
using SpaceX.API.Device;
public class Program
{
static async Task Main(string[] args)
{
//SETUP CHANNEL AND CLIENT
using var channel = GrpcChannel.ForAddress("http://192.168.100.1:9200");
var client = new ServerReflectionClient(channel);
var StarLinkClient = new Device.DeviceClient(channel);
//using var call = StarLinkClient.StreamAsync(new ToDevice { Request = GetDeviceInfoRequest });
//await foreach (var response in call.ResponseStream.ReadAllAsync())
//var request = Device.GetDeviceInfoRequest;
//var reply = await StarLinkClient.HandleAsync(
// new Request {'"getDeviceInfo" : {} '});
//Console.WriteLine(reply.Message);
//=============================================SERVER REFLECTION=============================================================
Console.WriteLine("Calling reflection service:");
var response = await SingleRequestAsync(client, new ServerReflectionRequest
{
ListServices = "" // Get all services
});
Console.WriteLine("Services:");
foreach (var item in response.ListServicesResponse.Service)
{
Console.WriteLine("- " + item.Name);
Console.WriteLine();
var StarLink = item.Name;
//Console.WriteLine(StarLink.getStatus());
}
//=============================================SERVER REFLECTION=============================================================
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
void setupchannel()
{
}
private static Task SingleRequestAsync(ServerReflectionClient client, Metadata metadata)
{
throw new NotImplementedException();
}
private static async Task<ServerReflectionResponse> SingleRequestAsync(ServerReflectionClient client, ServerReflectionRequest request)
{
using var call = client.ServerReflectionInfo();
await call.RequestStream.WriteAsync(request);
Debug.Assert(await call.ResponseStream.MoveNext());
var response = call.ResponseStream.Current;
await call.RequestStream.CompleteAsync();
return response;
}
}
Again, thanks in advance to anyone willing to assist here. Hopefully this helps others as well.

Related

Nethereuem SendTransactionAsync from my C# Web API fails with transaction type not supported: eth_sendRawTransaction

I'm working on integrating Nethereum into my .NET 5 C# API and can do read queries against my chosen blockchain (BSC), but cannot get a SendTransactionAsync or SendRequestAsync to successfully execute. I'm consistently getting the following exception:
Nethereum.JsonRpc.Client.RpcResponseException: 'transaction type not supported: eth_sendRawTransaction'.
Here are code snippets of what I have tried:
// Setup
var account = new Account(privateKey, chainId);
var rpcUrl = "https://data-seed-prebsc-2-s2.binance.org:8545/";
var client = new RpcClient(new Uri(rpcUrl));
var web3 = new Web3(account, client);
var mediaTokenAddress = "0x1E4d1BFDa5d55C2176E9E3e8367BAe720525a8e0";
var mtSvc = new MediaTokenService(web3, mediaTokenAddress);
var mintMsg = new MintNftFunction
{
FromAddress = account.Address,
Recipient = "REDACTED",
MetadataHash = "TestMetaDataHash",
MediaHash = "TestMediaHash",
SeasonId = 1
};
// Attempt #1: Using C# classes generated by the Nethereum CodeGen library
var txReceipt = await mtSvc.MintNftRequestAndWaitForReceiptAsync(mintMsg);
// Attempt #2
var txHandler = web3.Eth.GetContractTransactionHandler<MintNftFunction>();
var signedTx = await txHandler.SignTransactionAsync(mediaTokenAddress, mintMsg);
var txReceipt = await web3.Eth.Transactions.SendTransaction.SendRequestAsync(signedTx);
// Attempt #3
var txInput = mintMsg.CreateTransactionInput(mediaTokenAddress);
var txReceipt = await web3.Eth.TransactionManager.SendTransactionAsync(txInput);
Is there a configuration step I'm missing? Any help is appreciated!
EDIT: I want to call a contract method that will change values within the contract, rather than sending currency. So I need help figuring out how to do that.
For those that come across this issue, I resolved it by setting the following flag on my web3 instance:
web3.TransactionManager.UseLegacyAsDefault = true;
If there is a way to do what I need without setting this flag, please feel free to leave a comment.
Here is an example of how I do this with Nethereum
var web3 = new Nethereum.Web3.Web3("YOUR_NODE_ADDRESS");
var privateKey = "someprivatekey";
var senderAddress = "0x..."; // put actual sender address
var receiveAddress = "0x..."; //put actual receiver address
var txCount = await web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(senderAddress);
double sendAmount = 5.09540000; //this is ETH
var amountInWei = Web3.Convert.ToWei(sendAmount);
//600 GWEI = 0.000000600
//60 GWEI = 0.000000060
var gwei = 147; // this is 0.000000147 ETH. You will want to calculate this based on network fees
var gasPrice = Web3.Convert.ToWei(0.000000001 * gwei);
var gasLimit = Web3.Convert.ToWei(0.000000000000021);
var encoded = Web3.OfflineTransactionSigner.SignTransaction(privateKey, receiveAddress, amountInWei, txCount.Value, gasPrice, gasLimit);
//This is what prompts the transactions
Web3.OfflineTransactionSigner.GetSenderAddress(encoded).Dump();
//TX Returns from this action
var txId = await web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encoded);
//Dump out the TX if successful
txId.Dump();
I've used this many times and it has worked for me just fine.

Reflection in gRPC \ Protobuf in C#

Due to the lack of examples in C#, I can't get reflection in gRPC\Protobuf working. One application would be supplying a version of all interfaces and messages.
syntax = "proto3";
import "google/protobuf/descriptor.proto";
option csharp_namespace = "Addressbook.Services";
extend google.protobuf.FileOptions {
string version = 50000;
}
option (version) = "1.2.3.0";
service AddressBookService {
...
Is it possible that a client parses the connected server with reflection? Is the version supplied to all interfaces and messages? How to I do that in C#?
Thanks for any help...
If I understand the question correctly, you want to see if client and server are in sync with all .proto files.
Here's a solution that will have to be tweaked but otherwise will work.
This only works if server has reflection enabled - maybe not an option everywhere.
In ServiceName.Descriptor.File ServiceName refers to class generated by protoc.
using var channel = _channelFactory.GetChannel();
var client = new ServerReflection.ServerReflectionClient(channel);
using var call = client.ServerReflectionInfo();
// To get all service names on the server, you can use this:
// await call.RequestStream.WriteAsync(new ServerReflectionRequest{ ListServices = ""});
// await call.ResponseStream.MoveNext(CancellationToken.None);
// foreach (var serviceResponse in call.ResponseStream.Current.ListServicesResponse.Service)
// {
// _logger.LogInformation("Service name on server: {ServiceName}", serviceResponse.Name);
// }
await call.RequestStream.WriteAsync(new ServerReflectionRequest{FileContainingSymbol = "name.space.service_name"});
await call.ResponseStream.MoveNext(CancellationToken.None);
var descriptorResponse = call.ResponseStream.Current;
// This list has to be reversed. Check `.BuildFromByteStrings` docstring for more info.
var fileDescriptors = FileDescriptor.BuildFromByteStrings(descriptorResponse.FileDescriptorResponse.FileDescriptorProto.Reverse());
var localDescriptor = ServiceName.Descriptor.File;
var relevantFileDescriptor = fileDescriptors.Single(descriptor => descriptor.Name == localDescriptor.Name);
if (relevantFileDescriptor.SerializedData != localDescriptor.SerializedData)
{
_logger.LogWarning("Remote .proto differs from local copy. Please update.");
}
else
{
_logger.LogInformation(".proto definition matches between client and server.");
}
await call.RequestStream.CompleteAsync();

creating a github issue in octokit.net

I am trying to write a script that will open an issue typed in the console.
For some reason the issue variable comes back empty in the debugger.
class Program
{
public async static Task Main()
{
var client = new GitHubClient(new ProductHeaderValue("test-app"));
var user = await client.User.Get("medic17");
var tokenAuth = new Credentials(APIKeys.GithubPersinalAccessToken);
client.Credentials = tokenAuth;
var exampleIssue = new NewIssue("test body");
var issue = await client.Issue.Create("owner","name", exampleIssue);
}
}
APIKeys holds my token.
Thanks
I found a solution hope this helps someone else as well.
class Program
{
public async static Task Main()
{
// client initialization and authentication
var client = new GitHubClient(new ProductHeaderValue("<anything>"));
var user = await client.User.Get("<user>");
var tokenAuth = new Credentials(APIKeys.GithubPersinalAccessToken);
client.Credentials = tokenAuth;
// user input
Console.WriteLine("Give a title for your issue: ");
string userIssueTitle = Console.ReadLine().Trim();
Console.WriteLine("Describe your issue:", Environment.NewLine);
string userIssue = Console.ReadLine().Trim();
// input validation
while (string.IsNullOrEmpty(userIssue) || string.IsNullOrEmpty(userIssueTitle))
{
Console.WriteLine("ERROR: Both fields must contain text");
Console.ReadLine();
break;
}
var newIssue = new NewIssue(userIssueTitle) { Body = userIssue };
var issue = await client.Issue.Create(<owner>, <repo> newIssue);
var issueId = issue.Id;
Console.WriteLine($"SUCCESS: your issue id is {issueId} ");
Console.ReadLine();
}
}
Note
You need to store your keys in a separate file and write a class for it so your authentication flow might be different.
Note 2
You must replace all text with real values.
Still a little confused the app is OpenSource for transport since it deals with HIPPA data, users who want to use it need GitHub account if they want to do any error reporting. I assume I don’t share the authToken in the source of the project but the desktop Binary needs it plus the users GitHub login and password. Any pointers? I have tried just using username password that gets entered when creating issue but that fails with “not found”. It seems like any secret that gets deployed with binary app is potentially an issue.

Sabre Web Services .NET API Examples that aren't MVC?

This is pretty general, but I'm having a hell of a time figuring out how to consume some of the more complicated Sabre APIs.
I have built working .NET proxy classes in C# using the WSDL for the basic APIs (CreateSession, CloseSession) but for the more complicated APIs I have a really hard time parsing out the complicated XML schema to figure out which methods to call in my program.
Are there any other .NET resources/examples out there that aren't wrapped up in MVC like the code example that Sabre posted on GitHub?
I'm trying to figure out how to use APIs like OTA_AirPriceLLSRQ and TravelItineraryReadRQ.
Thanks in advance for any help!
As I mentioned on the comments, you should not focus on the actual MVC wrapping, as you'll be mainly putting stuff in the Model, or actually you'll put this somewhere else and consume it in the model.
Anyway, just for you to have as example, here's a VERY generic BFM (BargianFinderMax) class. With this approach it's required to create an instance, and after calling the Execute method it stores the response in the instance.
I hope it helps.
using BargainFinderMaxRQv310Srvc;
using System;
using System.IO;
namespace ServicesMethods
{
public class BFM_v310
{
private BargainFinderMaxService service;
private OTA_AirLowFareSearchRQ request;
public OTA_AirLowFareSearchRS response;
public BFM_v310(string token, string pcc, string convId, string endpoint)
{
//MessageHeader
MessageHeader mHeader = new MessageHeader();
PartyId[] pId = { new PartyId() };
pId[0].Value = "SWS";
From from = new From();
from.PartyId = pId;
To to = new To();
to.PartyId = pId;
mHeader.Action = "BargainFinderMaxRQ";
mHeader.Service = new Service()
{
Value = mHeader.Action
};
mHeader.ConversationId = convId;
mHeader.CPAId = pcc;
mHeader.From = from;
mHeader.To = to;
mHeader.MessageData = new MessageData()
{
Timestamp = DateTime.UtcNow.ToString()
};
//Security
Security security = new Security();
security.BinarySecurityToken = token;
//Service
service = new BargainFinderMaxService();
service.MessageHeaderValue = mHeader;
service.SecurityValue = security;
service.SoapVersion = System.Web.Services.Protocols.SoapProtocolVersion.Soap11;
service.Url = endpoint;
createRequest(pcc);
}
private void createRequest(string pcc)
{
request = new BargainFinderMaxRQv310Srvc.OTA_AirLowFareSearchRQ();
request.AvailableFlightsOnly = true;
request.Version = "3.1.0";
request.POS = new SourceType[1];
SourceType source = new SourceType();
source.PseudoCityCode = pcc;
source.RequestorID = new UniqueID_Type();
source.RequestorID.ID = "1";
source.RequestorID.Type = "1";
source.RequestorID.CompanyName = new CompanyNameType();
source.RequestorID.CompanyName.Code = "TN";
source.RequestorID.CompanyName.CodeContext = "Context";
request.POS[0] = source;
OTA_AirLowFareSearchRQOriginDestinationInformation originDestination = new OTA_AirLowFareSearchRQOriginDestinationInformation();
originDestination.OriginLocation = new OriginDestinationInformationTypeOriginLocation();
originDestination.OriginLocation.LocationCode = "BCN";
originDestination.DestinationLocation = new OriginDestinationInformationTypeDestinationLocation();
originDestination.DestinationLocation.LocationCode = "MAD";
originDestination.ItemElementName = ItemChoiceType.DepartureDateTime;
originDestination.Item = "2017-09-10T12:00:00";
originDestination.RPH = "1";
request.OriginDestinationInformation = new OTA_AirLowFareSearchRQOriginDestinationInformation[1] { originDestination };
request.TravelerInfoSummary = new TravelerInfoSummaryType()
{
AirTravelerAvail = new TravelerInformationType[1]
};
request.TravelerInfoSummary.AirTravelerAvail[0] = new TravelerInformationType()
{
PassengerTypeQuantity = new PassengerTypeQuantityType[1]
};
PassengerTypeQuantityType passenger = new PassengerTypeQuantityType()
{
Quantity = "1",
Code = "ADT"
};
request.TravelerInfoSummary.AirTravelerAvail[0].PassengerTypeQuantity[0] = passenger;
request.TravelerInfoSummary.PriceRequestInformation = new PriceRequestInformationType();
request.TravelerInfoSummary.PriceRequestInformation.CurrencyCode = "USD";
//PriceRequestInformationTypeNegotiatedFareCode nego = new PriceRequestInformationTypeNegotiatedFareCode();
//nego.Code = "ABC";
//request.TravelerInfoSummary.PriceRequestInformation.Items = new object[1] { nego };
request.TPA_Extensions = new OTA_AirLowFareSearchRQTPA_Extensions();
request.TPA_Extensions.IntelliSellTransaction = new TransactionType();
request.TPA_Extensions.IntelliSellTransaction.RequestType = new TransactionTypeRequestType();
request.TPA_Extensions.IntelliSellTransaction.RequestType.Name = "50ITIN";
}
public bool Execute()
{
response = service.BargainFinderMaxRQ(request);
return response.PricedItinCount > 0;
}
}
}
My advice is you should add separate models which are built based on Sabre models, and which flatten the whole structure.
For example, TravelItineraryReadRS is a quite complicated document. Using it properties in your program is a real "pain", because every time you need to remember the whole path that leads to to specific information (like, "what is passenger type for PersonName of NameNumber 01.01?").
I suggest you have dedicated model (let's name it Reservation), which have all information that you will need later in your application, extracted from TravelItineraryReadRs.
In order to achieve this you need a dedicated converter which will make convert TravelItineraryReadRs model into Reservation model. Now, inside Reservation model you could have list of Passenger models, which have in on place all important information (NameNumber, PassengerType, SSR codes, etc).
This improves readability and as a bonus you decouple your application from Sabre (imagine, one day someone asks "can we switch from Sabre to Amadeus?" - if you use dedicated models the answer is "yes". If you don't have, then the answer is "probably yes, but it will take 6-9 months).

ServiceNow - Getting all records

In ServiceNow, I am able to get only a maximum of 250 records in a SOAP request. How to get all the records?
Web Reference Url = https://*****.service-now.com/rm_story.do?WSDL
Code:
var url = "https://*****.service-now.com/rm_story.do?SOAP";
var userName = *****;
var password = *****;
var proxy = new ServiceNow_rm_story
{
Url = url,
Credentials = new NetworkCredential(userName, password)
};
try
{
var objRecord = new Namespace.WebReference.getRecords
{
// filters..
};
var recordResults = proxy.getRecords(objRecord);
}
catch (Exception ex)
{
}
In recordResults, I am getting only 250 records. How to get all the records ?
Also see this stack overflow answer which provides info.
Get ServiceNow Records Powershell - More than 250
Note that returning a large number of records can affect performance of the response and it may be more efficient to process your query in batches using offsets (i.e., get 1-100, then 101-200, ...). This can be achieved by using a sort order and offset. The ServiceNow REST Table API actually returns link headers from Get requests providing you links for the first, next and last set of records making it easy to know the url to query the next batch of records.
See: http://wiki.servicenow.com/index.php?title=Table_API#Methods
and look under 'Response Header'.
Have u tried to pass/override __limit parameter?
Google / wiki / Users manual / Release notes are always helpful
In your code snippet in line where it says //filter you should define __limit (and potentially __first_row and __last_row as explained in the example bellow)
int Skip = 0;
int Take = 250;
while (true)
{
using (var soapClient = new ServiceNowLocations.ServiceNow_cmn_location())
{
var cred = new System.Net.NetworkCredential(_user, _pass);
soapClient.Credentials = cred;
soapClient.Url = _apiUrl + "cmn_location.do?SOAP";
var getParams = new ServiceNowLocations.getRecords()
{
__first_row = Skip.ToString(),
__last_row = (Skip + Take).ToString(),
__limit = Take.ToString()
};
var records = soapClient.getRecords(getParams);
if (records != null)
{
if (records.Count() == 0)
{
break;
}
Skip += records.Count();
if (records.Count() != Take)
{
// last batch or everything in first batch
break;
}
}
else
{
// service now web service endpoint not configured correctly
break;
}
}
}
I made an library that handles interacting with ServiceNow Rest API much easier
https://emersonbottero.github.io/ServiceNow.Core/

Categories