Skip to content

Commit

Permalink
RPC works
Browse files Browse the repository at this point in the history
  • Loading branch information
carl-andersson-at-westermo committed Jun 3, 2024
1 parent 9aa9dd1 commit aec7753
Show file tree
Hide file tree
Showing 14 changed files with 429 additions and 155 deletions.
52 changes: 51 additions & 1 deletion YangParser/Generator/YangGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ private void AddAttributesClass(IncrementalGeneratorPostInitializationContext co
var fileName = "YangModules/Attributes/Yang.Attributes.cs";
var contents = """
using System;
using System.Xml;
namespace Yang.Attributes;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class RevisionAttribute(string date) : Attribute
Expand Down Expand Up @@ -413,15 +414,64 @@ public class InstanceIdentifier(string path)
{
public string Path { get; } = path;
public static InstanceIdentifier Parse(string id) => new(id);
public override string ToString() => Path;
}
public interface IChannel
{
string Send(string xml);
Task<global::System.IO.Stream> Send(string xml);
}
public interface IXMLSource
{
string ToXML();
}
public static class SerializationHelper
{
public static XmlWriterSettings GetStandardWriterSettings()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = false;
settings.Async = true;
return settings;
}
public static XmlReaderSettings GetStandardReaderSettings()
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.Async = true;
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
settings.IgnoreProcessingInstructions = true;
return settings;
}
public static async Task ExpectOkRpcReply(XmlReader reader, int messageID)
{
await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.Element || reader.Name != "rpc-reply" || reader.NamespaceURI != "urn:ietf:params:xml:ns:netconf:base:1.0" || reader["message-id"] != messageID.ToString())
{
throw new Exception($"Expected stream to start with a <rpc-reply> element with message id {messageID} & \"urn:ietf:params:xml:ns:netconf:base:1.0\" but got {reader.NodeType}: {reader.Name} in {reader.NamespaceURI}");
}
await reader.ReadAsync();
while(reader.NodeType == XmlNodeType.Whitespace)
{
await reader.ReadAsync();
}
if(reader.NodeType != XmlNodeType.Element || reader.Name != "ok")
{
throw new Exception($"Expected <ok/> element {reader.NodeType}: {reader.Name}");
}
await reader.ReadAsync();
while(reader.NodeType == XmlNodeType.Whitespace)
{
await reader.ReadAsync();
}
if(reader.NodeType != XmlNodeType.EndElement)
{
throw new Exception($"Expected </rpc-reply> closing element {reader.NodeType}: {reader.Name}");
}
}
}
""";
context.AddSource(fileName, contents);

Expand Down
35 changes: 20 additions & 15 deletions YangParser/SemanticModel/Action.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,8 @@ public override string ToCode()
$"public async {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})");
builder.AppendLine("""
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
settings.Async = true;
StringBuilder stringBuilder = new StringBuilder();
using XmlWriter writer = XmlWriter.Create(stringBuilder, settings);
using XmlWriter writer = XmlWriter.Create(stringBuilder, SerializationHelper.GetStandardWriterSettings());
await writer.WriteStartElementAsync(null,"rpc","urn:ietf:params:xml:ns:netconf:base:1.0");
await writer.WriteAttributeStringAsync(null,"message-id",null,messageID.ToString());
await writer.WriteStartElementAsync(null,"action","urn:ietf:params:xml:ns:yang:1");
Expand All @@ -63,21 +58,31 @@ public override string ToCode()
builder.AppendLine("""
await WriteXMLAsync(writer);
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
var xml = stringBuilder.ToString();
var response = await channel.Send(stringBuilder.ToString());
""");
builder.AppendLine(returnType != "Task"
? "\tvar response = channel.Send(xml);"
: "\tchannel.Send(xml);");
builder.AppendLine(Ingoing is not null
? $"\tthis.{MakeName(Argument)}InputValue = null;"
: $"\tthis.{MakeName(Argument)}Active = false;");

if (returnType != "Task")
{
builder.AppendLine($"\treturn {outputType}.Parse(response);");
}
builder.AppendLine(returnType != "Task"
? $$"""
using XmlReader reader = XmlReader.Create(response,SerializationHelper.GetStandardReaderSettings());
await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.Element || reader.Name != "rpc-reply" || reader.NamespaceURI != "urn:ietf:params:xml:ns:netconf:base:1.0" || reader["message-id"] != messageID.ToString())
{
throw new Exception($"Expected stream to start with a <rpc-reply> element with message id {messageID} & \"urn:ietf:params:xml:ns:netconf:base:1.0\" but got {reader.NodeType}: {reader.Name} in {reader.NamespaceURI}");
}
var value = await {{outputType}}.ParseAsync(reader);
response.Dispose();
return value;
"""
: """
using XmlReader reader = XmlReader.Create(response,SerializationHelper.GetStandardReaderSettings());
await reader.ReadAsync();
await SerializationHelper.ExpectOkRpcReply(reader, messageID);
response.Dispose();
""");

builder.AppendLine("}");
if (Outgoing is not null)
Expand Down
16 changes: 12 additions & 4 deletions YangParser/SemanticModel/Builtins/BuiltinTypeReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,23 @@ public override string ToString()

private static string GetText(string argument) => $$"""
await reader.ReadAsync();
while(reader.NodeType == XmlNodeType.Whitespace) await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.Text)
{
throw new Exception($"Expected token in ParseCall for '{{argument}}' to be text, but was '{reader.NodeType}'");
}
""";

private static string EndElement(string argument) => $$"""
await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.EndElement)
if(!reader.IsEmptyElement)
{
throw new Exception($"Expected token in ParseCall for '{{argument}}' to be an element closure, but was '{reader.NodeType}'");
await reader.ReadAsync();
while(reader.NodeType == XmlNodeType.Whitespace) await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.EndElement)
{
throw new Exception($"Expected token in ParseCall for '{{argument}}' to be an element closure, but was '{reader.NodeType}'");
}
}
""";

Expand Down Expand Up @@ -273,7 +279,9 @@ public static string ValueParsing(Type type, string typeName)
var p = prefix.Contains('.') ? prefix : prefix + ":";
return $"return {p}Get{local}Value(value);";
}
Log.Write($"Specified typeName {typeName} did not match source type name {chosen.Name}, defaulting to .Parse");

Log.Write(
$"Specified typeName {typeName} did not match source type name {chosen.Name}, defaulting to .Parse");
return $"return {typeName}.Parse(value);";
default:
return $"return {typeName}.Parse(value);";
Expand Down
2 changes: 1 addition & 1 deletion YangParser/SemanticModel/Case.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class {{ClassName}}
{
{{Indent(string.Join("\n", nodes))}}
{{Indent(WriteFunctionInvisibleSelf())}}
{{Indent(ReadFunction())}}
{{Indent(ReadFunctionWithInvisibleSelf())}}
}
""";
}
Expand Down
2 changes: 1 addition & 1 deletion YangParser/SemanticModel/Choice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class {{TargetName}}Choice
{
{{string.Join("\n\t", nodes.Select(Indent))}}
{{Indent(WriteFunctionInvisibleSelf())}}
{{Indent(ReadFunction())}}
{{Indent(ReadFunctionWithInvisibleSelf())}}
}
""";
}
Expand Down
2 changes: 1 addition & 1 deletion YangParser/SemanticModel/Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public override string ToCode()
public class {{ClassName}}
{
{{string.Join("\n\t", Children.Select(child => Indent(child.ToCode())))}}
{{Indent(WriteFunction())}}
{{Indent(WriteFunctionInvisibleSelf())}}
{{Indent(ReadFunction())}}
}
""";
Expand Down
11 changes: 11 additions & 0 deletions YangParser/SemanticModel/Leaf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ public string WriteCall
""";
}

if (Type.GetBaseType(out _, out _) is "empty")
{
return $$"""
if({{TargetName}} != default)
{
await writer.WriteStartElementAsync({{xmlPrefix}},"{{Argument}}",{{xmlNs}});
await writer.WriteEndElementAsync();
}
""";
}

return $$"""
if({{TargetName}} != default)
{
Expand Down
13 changes: 2 additions & 11 deletions YangParser/SemanticModel/Notification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,8 @@ public class {{MakeName(Argument)}}
{{string.Join("\n\t", nodes.Select(Indent))}}
public async Task<string> ToXML()
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
settings.Async = true;
StringBuilder stringBuilder = new StringBuilder();
using XmlWriter writer = XmlWriter.Create(stringBuilder, settings);
using XmlWriter writer = XmlWriter.Create(stringBuilder, SerializationHelper.GetStandardWriterSettings());
await writer.WriteStartElementAsync(null,"notification","urn:ietf:params:xml:ns:netconf:notification:1.0");
await writer.WriteStartElementAsync(null,"eventTime",null);
await writer.WriteStringAsync(DateTime.UtcNow.ToString("yyyy-MM-ddThh:mm:ssZ"));
Expand All @@ -62,9 +57,7 @@ public async Task<string> ToXML()
}
public static async Task<{{MakeName(Argument)}}> ParseAsync(global::System.IO.Stream xmlStream)
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.Async = true;
using XmlReader reader = XmlReader.Create(xmlStream,settings);
using XmlReader reader = XmlReader.Create(xmlStream,SerializationHelper.GetStandardReaderSettings());
await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.Element || reader.Name != "notification" || reader.NamespaceURI != "urn:ietf:params:xml:ns:netconf:notification:1.0")
{
Expand Down Expand Up @@ -113,8 +106,6 @@ public async Task<string> ToXML()
throw new Exception($"Expected </notification> closing element {reader.NodeType}: {reader.Name}");
}
return value;
}
{{Indent(WriteFunction())}}
{{Indent(ReadFunction(MakeName(Argument)))}}
Expand Down
3 changes: 2 additions & 1 deletion YangParser/SemanticModel/Output.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ public Output(YangStatement statement) : base(statement)

public override string ToCode()
{
Argument = "rpc-reply";
return $$"""
public class {{ClassName}}
{
{{string.Join("\n\t", Children.Select(child => Indent(child.ToCode())))}}
public static {{ClassName}} Parse(string xml) => default!; //TODO
{{ReadFunction()}}
{{WriteFunctionInvisibleSelf()}}
}
""";
}
Expand Down
44 changes: 24 additions & 20 deletions YangParser/SemanticModel/Rpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,41 @@ public override string ToCode()
$"public static async {returnType} {MakeName(Argument)}(IChannel channel, int messageID{inputType})");
builder.AppendLine($$"""
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
settings.NewLineOnAttributes = true;
settings.Async = true;
StringBuilder stringBuilder = new StringBuilder();
using XmlWriter writer = XmlWriter.Create(stringBuilder, settings);
using XmlWriter writer = XmlWriter.Create(stringBuilder, SerializationHelper.GetStandardWriterSettings());
await writer.WriteStartElementAsync(null,"rpc","urn:ietf:params:xml:ns:netconf:base:1.0");
await writer.WriteAttributeStringAsync(null,"message-id",null,messageID.ToString());
await writer.WriteStartElementAsync("{{XmlNamespace?.Prefix}}","{{Argument}}","{{XmlNamespace?.Namespace}}");
await writer.WriteStartElementAsync("{{Prefix}}","{{Argument}}","{{Namespace}}");
""");
var ns = $"xmlns:{XmlNamespace?.Prefix}=\\\"" + XmlNamespace?.Namespace + "\\\"";
if (inputType != string.Empty)
{
builder.AppendLine("\tawait input.WriteXMLAsync(writer);");
}

builder.AppendLine($$"""
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
var xml = stringBuilder.ToString();
""");
builder.AppendLine("""
await writer.WriteEndElementAsync();
await writer.WriteEndElementAsync();
await writer.FlushAsync();
var response = await channel.Send(stringBuilder.ToString());
""");
builder.AppendLine(returnType != "Task"
? "\tvar response = channel.Send(xml);"
: "\tchannel.Send(xml);");
if (returnType != "Task")
{
builder.AppendLine($"\treturn {outputType}.Parse(response);");
}
? $$"""
using XmlReader reader = XmlReader.Create(response,SerializationHelper.GetStandardReaderSettings());
await reader.ReadAsync();
if(reader.NodeType != XmlNodeType.Element || reader.Name != "rpc-reply" || reader.NamespaceURI != "urn:ietf:params:xml:ns:netconf:base:1.0" || reader["message-id"] != messageID.ToString())
{
throw new Exception($"Expected stream to start with a <rpc-reply> element with message id {messageID} & \"urn:ietf:params:xml:ns:netconf:base:1.0\" but got {reader.NodeType}: {reader.Name} in {reader.NamespaceURI}");
}
var value = await {{outputType}}.ParseAsync(reader);
response.Dispose();
return value;
"""
: """
using XmlReader reader = XmlReader.Create(response,SerializationHelper.GetStandardReaderSettings());
await SerializationHelper.ExpectOkRpcReply(reader, messageID);
response.Dispose();
""");

builder.AppendLine("}");
if (Outgoing is not null)
Expand Down
Loading

0 comments on commit aec7753

Please sign in to comment.