Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
036897ecab | |||
bc19a315da | |||
4465c62163 | |||
fea830b295 | |||
7bc9adebaa |
42
JsonRPC.sln
Normal file
42
JsonRPC.sln
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.002.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "templates", "templates", "{ECEBC2A1-9382-44B5-94A6-305DC8235859}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharp", "templates\CSharp\CSharp.csproj", "{16231421-DB23-46D0-AFA8-81099E3CF97A}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{B6AB75C7-58FC-4F62-AFAA-ED8FEEBF2E1C}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CSharp", "CSharp", "{833192BE-67E8-425F-9AA7-23532485682A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CSharp_Example", "examples\CSharp\Example\CSharp_Example.csproj", "{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{16231421-DB23-46D0-AFA8-81099E3CF97A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{16231421-DB23-46D0-AFA8-81099E3CF97A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{16231421-DB23-46D0-AFA8-81099E3CF97A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{16231421-DB23-46D0-AFA8-81099E3CF97A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{16231421-DB23-46D0-AFA8-81099E3CF97A} = {ECEBC2A1-9382-44B5-94A6-305DC8235859}
|
||||||
|
{833192BE-67E8-425F-9AA7-23532485682A} = {B6AB75C7-58FC-4F62-AFAA-ED8FEEBF2E1C}
|
||||||
|
{3BD8D8BF-46ED-4F52-BD78-8B22FF3A77A2} = {833192BE-67E8-425F-9AA7-23532485682A}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {ED59162F-B7E7-4EA2-91D4-7F6D1BFBB820}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -41,6 +41,10 @@ class TestSrvimpl : Example.TestServiceServer<int>
|
|||||||
throw new Exception("This is a remote error :)");
|
throw new Exception("This is a remote error :)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override Task<double> FunctionWithKeywords(double type, double static_, double event_, int ctx)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CopyTransportS2 : Example.JRpcTransport
|
class CopyTransportS2 : Example.JRpcTransport
|
||||||
|
@ -52,6 +52,8 @@ service TestService {
|
|||||||
|
|
||||||
|
|
||||||
FunctionWithArrayAsParamAndReturn(values1: float[], values2: float[]): float[];
|
FunctionWithArrayAsParamAndReturn(values1: float[], values2: float[]): float[];
|
||||||
|
|
||||||
|
FunctionWithKeywords(type: float, static: float, event: float): float;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Test2 {
|
type Test2 {
|
||||||
@ -59,6 +61,12 @@ type Test2 {
|
|||||||
age: int;
|
age: int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TestKeywords {
|
||||||
|
type: float;
|
||||||
|
static: float;
|
||||||
|
event: float;
|
||||||
|
}
|
||||||
|
|
||||||
service SimpleTestService {
|
service SimpleTestService {
|
||||||
@Description("asdasdasd")
|
@Description("asdasdasd")
|
||||||
GetTest(name: string, age: int): Test2;
|
GetTest(name: string, age: int): Test2;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@hibas123/jrpcgen",
|
"name": "@hibas123/jrpcgen",
|
||||||
"version": "1.2.16",
|
"version": "1.2.20",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "yarn@3.1.1",
|
"packageManager": "yarn@3.1.1",
|
||||||
|
@ -115,8 +115,8 @@ export default function parse(tokens: Token[], file: string): Parsed {
|
|||||||
return idx;
|
return idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
const eatText = (): [string, number] => {
|
const eatText = (allowKeyword?: boolean): [string, number] => {
|
||||||
checkTypes("text");
|
checkTypes(...(allowKeyword ? ["text", "keyword"] : ["text"]));
|
||||||
let val = currentToken.value;
|
let val = currentToken.value;
|
||||||
let idx = currentToken.startIdx;
|
let idx = currentToken.startIdx;
|
||||||
eatToken();
|
eatToken();
|
||||||
@ -351,7 +351,7 @@ export default function parse(tokens: Token[], file: string): Parsed {
|
|||||||
|
|
||||||
if (currentToken.value !== ")") {
|
if (currentToken.value !== ")") {
|
||||||
while (true) {
|
while (true) {
|
||||||
const [name] = eatText();
|
const [name] = eatText(true);
|
||||||
eatToken(":");
|
eatToken(":");
|
||||||
const [type] = eatText();
|
const [type] = eatText();
|
||||||
let array = false;
|
let array = false;
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
|
|
||||||
import { CompileTarget } from "../compile";
|
import { CompileTarget } from "../compile";
|
||||||
import { LineAppender } from "../utils";
|
import { LineAppender } from "../utils";
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
const conversion = {
|
const conversion = {
|
||||||
boolean: "bool",
|
boolean: "bool",
|
||||||
@ -22,6 +23,16 @@ function toCSharpType(type: string): string {
|
|||||||
return (conversion as any)[type] || type;
|
return (conversion as any)[type] || type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add other keywords as well!
|
||||||
|
const keywords = new Set(["event", "internal", "public", "private", "static"]);
|
||||||
|
|
||||||
|
const fixKeywordName = (name: string) => {
|
||||||
|
if (keywords.has(name)) {
|
||||||
|
return `${name}_`;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
||||||
name: string = "c#";
|
name: string = "c#";
|
||||||
|
|
||||||
@ -61,11 +72,20 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
|||||||
a(0, ``);
|
a(0, ``);
|
||||||
a(0, `public class ${definition.name} {`);
|
a(0, `public class ${definition.name} {`);
|
||||||
for (const field of definition.fields) {
|
for (const field of definition.fields) {
|
||||||
|
let fn = field.name;
|
||||||
|
if (keywords.has(field.name)) {
|
||||||
|
console.log(
|
||||||
|
chalk.yellow("[RUST] WARNING:"),
|
||||||
|
`Field name '${fn}' is not allowed in C#. Renaming to '${fn}_'`
|
||||||
|
);
|
||||||
|
fn = fixKeywordName(fn);
|
||||||
|
a(1, `[JsonPropertyName("${fn}")]`);
|
||||||
|
}
|
||||||
|
|
||||||
if (field.array) {
|
if (field.array) {
|
||||||
a(
|
a(
|
||||||
1,
|
1,
|
||||||
`public IList<${toCSharpType(field.type)}>? ${
|
`public IList<${toCSharpType(field.type)}>? ${fn
|
||||||
field.name
|
|
||||||
} { get; set; }`
|
} { get; set; }`
|
||||||
);
|
);
|
||||||
} else if (field.map) {
|
} else if (field.map) {
|
||||||
@ -73,12 +93,12 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
|||||||
1,
|
1,
|
||||||
`public Dictionary<${toCSharpType(field.map)}, ${toCSharpType(
|
`public Dictionary<${toCSharpType(field.map)}, ${toCSharpType(
|
||||||
field.type
|
field.type
|
||||||
)}>? ${field.name} { get; set; }`
|
)}>? ${fn} { get; set; }`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
a(
|
a(
|
||||||
1,
|
1,
|
||||||
`public ${toCSharpType(field.type)}? ${field.name} { get; set; }`
|
`public ${toCSharpType(field.type)}? ${fn} { get; set; }`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,10 +147,12 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
|||||||
for (const fnc of definition.functions) {
|
for (const fnc of definition.functions) {
|
||||||
let params = fnc.inputs
|
let params = fnc.inputs
|
||||||
.map((inp) => {
|
.map((inp) => {
|
||||||
|
let name = fixKeywordName(inp.name);
|
||||||
|
|
||||||
if (inp.array) {
|
if (inp.array) {
|
||||||
return `List<${toCSharpType(inp.type)}> ${inp.name}`;
|
return `List<${toCSharpType(inp.type)}> ${name}`;
|
||||||
} else {
|
} else {
|
||||||
return `${toCSharpType(inp.type)} ${inp.name}`;
|
return `${toCSharpType(inp.type)} ${name}`;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(", ");
|
.join(", ");
|
||||||
@ -139,7 +161,7 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
|||||||
a(
|
a(
|
||||||
2,
|
2,
|
||||||
`var param = new JsonArray(${fnc.inputs
|
`var param = new JsonArray(${fnc.inputs
|
||||||
.map((e) => `JsonSerializer.SerializeToNode(${e.name})`)
|
.map((e) => `JsonSerializer.SerializeToNode(${fixKeywordName(e.name)})`)
|
||||||
.join(", ")});`
|
.join(", ")});`
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -219,10 +241,11 @@ export class CSharpTarget extends CompileTarget<{ csharp_namespace: string }> {
|
|||||||
for (const fnc of definition.functions) {
|
for (const fnc of definition.functions) {
|
||||||
let params = [
|
let params = [
|
||||||
...fnc.inputs.map((inp) => {
|
...fnc.inputs.map((inp) => {
|
||||||
|
let name = fixKeywordName(inp.name)
|
||||||
if (inp.array) {
|
if (inp.array) {
|
||||||
return `List<${toCSharpType(inp.type)}> ${inp.name}`;
|
return `List<${toCSharpType(inp.type)}> ${name}`;
|
||||||
} else {
|
} else {
|
||||||
return `${toCSharpType(inp.type)} ${inp.name}`;
|
return `${toCSharpType(inp.type)} ${name}`;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
"TContext ctx",
|
"TContext ctx",
|
||||||
|
@ -23,6 +23,16 @@ function toSnake(input: string) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add other keywords as well!
|
||||||
|
const keywords = new Set(["type", "static"]);
|
||||||
|
|
||||||
|
const fixKeywordName = (name: string) => {
|
||||||
|
if (keywords.has(name)) {
|
||||||
|
return `${name}_`;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
||||||
name: string = "rust";
|
name: string = "rust";
|
||||||
|
|
||||||
@ -74,14 +84,14 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
|||||||
a(1, `#[allow(non_snake_case)]`);
|
a(1, `#[allow(non_snake_case)]`);
|
||||||
|
|
||||||
let fn = `pub ${field.name}:`;
|
let fn = `pub ${field.name}:`;
|
||||||
if (field.name == "type") {
|
if (keywords.has(field.name)) {
|
||||||
// TODO: Add other keywords as well!
|
// TODO: Add other keywords as well!
|
||||||
console.log(
|
console.log(
|
||||||
chalk.yellow("[RUST] WARNING:"),
|
chalk.yellow("[RUST] WARNING:"),
|
||||||
"Field name 'type' is not allowed in Rust. Renaming to 'type_'"
|
`Field name '${field.name}' is not allowed in Rust. Renaming to '${field.name}_'`
|
||||||
);
|
);
|
||||||
fn = `pub type_:`;
|
fn = `pub ${fixKeywordName(field.name)}:`;
|
||||||
a(1, `#[serde(rename = "type")]`);
|
a(1, `#[serde(rename = "${field.name}")]`);
|
||||||
}
|
}
|
||||||
let opts = "";
|
let opts = "";
|
||||||
let opte = "";
|
let opte = "";
|
||||||
@ -156,7 +166,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
|||||||
a(0, ``);
|
a(0, ``);
|
||||||
for (const fnc of definition.functions) {
|
for (const fnc of definition.functions) {
|
||||||
let params = fnc.inputs
|
let params = fnc.inputs
|
||||||
.map((i) => i.name + ": " + typeToRust(i.type, i.array))
|
.map((i) => fixKeywordName(i.name) + ": " + typeToRust(i.type, i.array))
|
||||||
.join(", ");
|
.join(", ");
|
||||||
let ret = fnc.return
|
let ret = fnc.return
|
||||||
? typeToRust(fnc.return.type, fnc.return.array)
|
? typeToRust(fnc.return.type, fnc.return.array)
|
||||||
@ -167,7 +177,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
|||||||
a(3, `jsonrpc: "2.0".to_owned(),`);
|
a(3, `jsonrpc: "2.0".to_owned(),`);
|
||||||
a(3, `id: None, // 'id' will be set by the send_request function`);
|
a(3, `id: None, // 'id' will be set by the send_request function`);
|
||||||
a(3, `method: "${definition.name}.${fnc.name}".to_owned(),`);
|
a(3, `method: "${definition.name}.${fnc.name}".to_owned(),`);
|
||||||
a(3, `params: json!([${fnc.inputs.map((e) => e.name)}])`);
|
a(3, `params: json!([${fnc.inputs.map((e) => fixKeywordName(e.name))}])`);
|
||||||
a(2, `};`);
|
a(2, `};`);
|
||||||
a(2, ``);
|
a(2, ``);
|
||||||
if (fnc.return) {
|
if (fnc.return) {
|
||||||
@ -220,7 +230,7 @@ export class RustTarget extends CompileTarget<{ rust_crate: string }> {
|
|||||||
let params =
|
let params =
|
||||||
fnc.inputs.length > 0
|
fnc.inputs.length > 0
|
||||||
? fnc.inputs
|
? fnc.inputs
|
||||||
.map((i) => i.name + ": " + typeToRust(i.type, i.array))
|
.map((i) => fixKeywordName(i.name) + ": " + typeToRust(i.type, i.array))
|
||||||
.join(", ")
|
.join(", ")
|
||||||
: "";
|
: "";
|
||||||
let ret = fnc.return
|
let ret = fnc.return
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>10.0</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -11,10 +11,12 @@ public class JRpcClient
|
|||||||
{
|
{
|
||||||
private JRpcTransport Transport;
|
private JRpcTransport Transport;
|
||||||
private IDictionary<string, TaskCompletionSource<JsonNode?>> Requests;
|
private IDictionary<string, TaskCompletionSource<JsonNode?>> Requests;
|
||||||
|
private int? Timeout = null;
|
||||||
|
|
||||||
public JRpcClient(JRpcTransport transport)
|
public JRpcClient(JRpcTransport transport, int? timeout = null)
|
||||||
{
|
{
|
||||||
this.Transport = transport;
|
this.Transport = transport;
|
||||||
|
this.Timeout = timeout;
|
||||||
this.Requests = new Dictionary<string, TaskCompletionSource<JsonNode?>>();
|
this.Requests = new Dictionary<string, TaskCompletionSource<JsonNode?>>();
|
||||||
|
|
||||||
this.Transport.OnPacket += this.HandlePacket;
|
this.Transport.OnPacket += this.HandlePacket;
|
||||||
@ -87,10 +89,43 @@ public class JRpcClient
|
|||||||
|
|
||||||
var task = new TaskCompletionSource<JsonNode?>();
|
var task = new TaskCompletionSource<JsonNode?>();
|
||||||
this.Requests.Add(id, task);
|
this.Requests.Add(id, task);
|
||||||
await this.Transport.Write(request.ToJsonString());
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await this.Transport.Write(request.ToJsonString());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
task.SetException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.Timeout.HasValue)
|
||||||
|
{
|
||||||
|
if (await Task.WhenAny(task.Task, Task.Delay(this.Timeout.Value)) == task.Task)
|
||||||
|
{
|
||||||
return await task.Task;
|
return await task.Task;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new JRpcTimeoutException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return await task.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.Requests.Remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TResult?> SendRequest<TResult>(string method, JsonArray param)
|
public async Task<TResult?> SendRequest<TResult>(string method, JsonArray param)
|
||||||
{
|
{
|
||||||
@ -128,3 +163,8 @@ public class JRpcException : Exception
|
|||||||
{
|
{
|
||||||
public JRpcException(string message) : base(message) { }
|
public JRpcException(string message) : base(message) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class JRpcTimeoutException : JRpcException
|
||||||
|
{
|
||||||
|
public JRpcTimeoutException() : base("Request Timeout") { }
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//@template-ignore
|
//@template-ignore
|
||||||
import { VerificationError } from "./ts_base";
|
import { VerificationError } from "./ts_base";
|
||||||
//@template-ignore
|
//@template-ignore
|
||||||
import { RequestObject, ResponseObject, ErrorCodes, Logging } from "./ts_service_base";
|
import { type RequestObject, type ResponseObject, ErrorCodes, Logging } from "./ts_service_base";
|
||||||
|
|
||||||
|
|
||||||
export type IMessageCallback = (data: any) => void;
|
export type IMessageCallback = (data: any) => void;
|
||||||
|
Reference in New Issue
Block a user