├── .gitattributes ├── .gitignore ├── Example ├── NotLiteCode - Client │ ├── NotLiteCode - Client.csproj │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── app.config └── NotLiteCode - Server │ ├── NotLiteCode - Server.csproj │ ├── Program.cs │ ├── Properties │ └── AssemblyInfo.cs │ ├── SharedClass.cs │ └── app.config ├── LICENSE ├── NotLiteCode.Serialization.GroBuf ├── GroBufSerializationProvider.cs ├── NotLiteCode.Serialization.GroBuf.csproj └── NotLiteCode.Serialization.GroBuf.nuspec ├── NotLiteCode.sln ├── NotLiteCode ├── App.config ├── Client │ └── Client.cs ├── Misc │ └── Helpers.cs ├── Network │ ├── Network.cs │ └── NetworkEvents.cs ├── NotLiteCode.csproj ├── NotLiteCode.nuspec ├── Serializer │ ├── DefaultSerializationProvider.cs │ └── ISerializationProdiver.cs └── Server │ ├── Server.cs │ └── ServerEvents.cs ├── README.md └── appveyor.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Pp]ackages/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # Visual Studio code coverage results 115 | *.coverage 116 | *.coveragexml 117 | 118 | # NCrunch 119 | _NCrunch_* 120 | .*crunch*.local.xml 121 | nCrunchTemp_* 122 | 123 | # MightyMoose 124 | *.mm.* 125 | AutoTest.Net/ 126 | 127 | # Web workbench (sass) 128 | .sass-cache/ 129 | 130 | # Installshield output folder 131 | [Ee]xpress/ 132 | 133 | # DocProject is a documentation generator add-in 134 | DocProject/buildhelp/ 135 | DocProject/Help/*.HxT 136 | DocProject/Help/*.HxC 137 | DocProject/Help/*.hhc 138 | DocProject/Help/*.hhk 139 | DocProject/Help/*.hhp 140 | DocProject/Help/Html2 141 | DocProject/Help/html 142 | 143 | # Click-Once directory 144 | publish/ 145 | 146 | # Publish Web Output 147 | *.[Pp]ublish.xml 148 | *.azurePubxml 149 | # TODO: Comment the next line if you want to checkin your web deploy settings 150 | # but database connection strings (with potential passwords) will be unencrypted 151 | *.pubxml 152 | *.publishproj 153 | 154 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 155 | # checkin your Azure Web App publish settings, but sensitive information contained 156 | # in these scripts will be unencrypted 157 | PublishScripts/ 158 | 159 | # NuGet Packages 160 | *.nupkg 161 | # The packages folder can be ignored because of Package Restore 162 | **/packages/* 163 | # except build/, which is used as an MSBuild target. 164 | !**/packages/build/ 165 | # Uncomment if necessary however generally it will be regenerated when needed 166 | #!**/packages/repositories.config 167 | # NuGet v3's project.json files produces more ignoreable files 168 | *.nuget.props 169 | *.nuget.targets 170 | 171 | # Microsoft Azure Build Output 172 | csx/ 173 | *.build.csdef 174 | 175 | # Microsoft Azure Emulator 176 | ecf/ 177 | rcf/ 178 | 179 | # Windows Store app package directories and files 180 | AppPackages/ 181 | BundleArtifacts/ 182 | Package.StoreAssociation.xml 183 | _pkginfo.txt 184 | 185 | # Visual Studio cache files 186 | # files ending in .cache can be ignored 187 | *.[Cc]ache 188 | # but keep track of directories ending in .cache 189 | !*.[Cc]ache/ 190 | 191 | # Others 192 | ClientBin/ 193 | ~$* 194 | *~ 195 | *.dbmdl 196 | *.dbproj.schemaview 197 | *.jfm 198 | *.pfx 199 | *.publishsettings 200 | node_modules/ 201 | orleans.codegen.cs 202 | 203 | # Since there are multiple workflows, uncomment next line to ignore bower_components 204 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 205 | #bower_components/ 206 | 207 | # RIA/Silverlight projects 208 | Generated_Code/ 209 | 210 | # Backup & report files from converting an old project file 211 | # to a newer Visual Studio version. Backup files are not needed, 212 | # because we have git ;-) 213 | _UpgradeReport_Files/ 214 | Backup*/ 215 | UpgradeLog*.XML 216 | UpgradeLog*.htm 217 | 218 | # SQL Server files 219 | *.mdf 220 | *.ldf 221 | 222 | # Business Intelligence projects 223 | *.rdl.data 224 | *.bim.layout 225 | *.bim_*.settings 226 | 227 | # Microsoft Fakes 228 | FakesAssemblies/ 229 | 230 | # GhostDoc plugin setting file 231 | *.GhostDoc.xml 232 | 233 | # Node.js Tools for Visual Studio 234 | .ntvs_analysis.dat 235 | 236 | # Visual Studio 6 build log 237 | *.plg 238 | 239 | # Visual Studio 6 workspace options file 240 | *.opt 241 | 242 | # Visual Studio LightSwitch build output 243 | **/*.HTMLClient/GeneratedArtifacts 244 | **/*.DesktopClient/GeneratedArtifacts 245 | **/*.DesktopClient/ModelManifest.xml 246 | **/*.Server/GeneratedArtifacts 247 | **/*.Server/ModelManifest.xml 248 | _Pvt_Extensions 249 | 250 | # Paket dependency manager 251 | .paket/paket.exe 252 | paket-files/ 253 | 254 | # FAKE - F# Make 255 | .fake/ 256 | 257 | # JetBrains Rider 258 | .idea/ 259 | *.sln.iml 260 | 261 | # CodeRush 262 | .cr/ 263 | 264 | # Python Tools for Visual Studio (PTVS) 265 | __pycache__/ 266 | *.pyc -------------------------------------------------------------------------------- /Example/NotLiteCode - Client/NotLiteCode - Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F} 8 | Exe 9 | NotLiteCode___Client 10 | NotLiteCode - Client 11 | v4.7.2 12 | 512 13 | 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {38065060-bb2e-4f7c-ab8a-fbe953628931} 55 | NotLiteCode.Serialization.GroBuf 56 | 57 | 58 | {3c70272f-b54e-4b72-b913-ee2ae7432d66} 59 | NotLiteCode 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Example/NotLiteCode - Client/Program.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Client; 2 | using NotLiteCode.Network; 3 | using NotLiteCode.Serialization; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Threading.Tasks; 7 | 8 | namespace NotLiteCode___Client 9 | { 10 | internal class Program 11 | { 12 | #region Remote Methods 13 | 14 | // In here we have our prototypes for the methods that exist on the server 15 | 16 | private static async Task Test() => 17 | await Client.RemoteCall("JustATest"); 18 | 19 | private static async Task CombineTwoStringsAndReturn(string s1, string s2) => 20 | await Client.RemoteCall("Pinocchio", s1, s2); 21 | 22 | private static async Task SpeedTest() => 23 | await Client.RemoteCall("ThroughputTest"); 24 | 25 | #endregion Remote Methods 26 | 27 | private static Client Client = null; 28 | 29 | private static void Main(string[] args) 30 | { 31 | Main().Wait(); 32 | } 33 | 34 | private static async Task Main() 35 | { 36 | Console.Title = "NLC Client"; 37 | 38 | // Create a socket with encryption enabled 39 | var ClientSocket = new NLCSocket(new GroBufSerializationProvider(), UseSSL: true, AllowInsecureCerts: true); 40 | 41 | Client = new Client(ClientSocket); 42 | 43 | Client.Connect("localhost", 1337); 44 | 45 | // Invoke our first remote method 46 | await Test(); 47 | 48 | // Invoke a method that returns a string 49 | Console.WriteLine(await CombineTwoStringsAndReturn("I'm a ", "real boy!")); 50 | 51 | int l = 0; 52 | 53 | var t = Stopwatch.StartNew(); 54 | 55 | // Execute a method as many times as we can in 1 second 56 | while (t.ElapsedMilliseconds < 1000) 57 | { 58 | await SpeedTest(); 59 | l++; 60 | } 61 | 62 | t.Stop(); 63 | 64 | Console.WriteLine("{0} calls in 1 second!", l); 65 | 66 | Client.Stop(); 67 | Console.ReadLine(); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /Example/NotLiteCode - Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("NotLiteCode - Client")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("NotLiteCode - Client")] 12 | [assembly: AssemblyCopyright("Copyright © 2018")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("80a3f0d8-080b-430f-b4be-173a5ef9ab6f")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Example/NotLiteCode - Client/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Example/NotLiteCode - Server/NotLiteCode - Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4C4FB7AA-47C2-4717-9499-44EA91450A34} 8 | Exe 9 | Properties 10 | NotLiteCode___Server 11 | NotLiteCode - Server 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | true 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | false 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | {38065060-bb2e-4f7c-ab8a-fbe953628931} 57 | NotLiteCode.Serialization.GroBuf 58 | 59 | 60 | {3c70272f-b54e-4b72-b913-ee2ae7432d66} 61 | NotLiteCode 62 | 63 | 64 | 65 | 72 | -------------------------------------------------------------------------------- /Example/NotLiteCode - Server/Program.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Network; 2 | using NotLiteCode.Serialization; 3 | using NotLiteCode.Server; 4 | using System; 5 | using System.Diagnostics; 6 | using System.Security.Cryptography; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace NotLiteCode___Server 12 | { 13 | internal class Program 14 | { 15 | private static void Main(string[] args) 16 | { 17 | Console.Title = "NLC Server"; 18 | 19 | var ServerSocket = new NLCSocket(new GroBufSerializationProvider(), UseSSL: true, ServerCertificate: GenerateSelfSignedCert("NLC", "localhost")); 20 | 21 | var Server = new Server(ServerSocket); 22 | 23 | Server.OnServerClientConnected += (x, y) => Log($"Client {y.Client} connected!", ConsoleColor.Green); 24 | Server.OnServerClientDisconnected += (x, y) => Log($"Client {y.Client} disconnected!", ConsoleColor.Yellow); 25 | Server.OnServerExceptionOccurred += (x, y) => Log($"Exception Occured! {y.Exception}", ConsoleColor.Red); 26 | 27 | // This line intentionally left commented due to excessive lock contestion during performance testing (1000's of calls a second) which starves other performance critical threads thus skewing performance results 28 | //Server.OnServerMethodInvoked += (x, y) => Log($"Client {y.Client} {(y.WasErroneous ? "failed to invoke" : "invoked")} {y.Identifier} for {y.Duration.TotalMilliseconds}ms.", y.WasErroneous ? ConsoleColor.Yellow : ConsoleColor.Cyan); 29 | 30 | Server.Start(); 31 | 32 | Log("Server Started!", ConsoleColor.Green); 33 | 34 | Process.GetCurrentProcess().WaitForExit(); 35 | } 36 | 37 | private static X509Certificate2 GenerateSelfSignedCert(string CertificateName, string HostName) 38 | { 39 | SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder(); 40 | sanBuilder.AddDnsName(HostName); 41 | 42 | X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN={CertificateName}"); 43 | 44 | using (RSA rsa = RSA.Create(2048)) 45 | { 46 | var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); 47 | 48 | request.CertificateExtensions.Add( 49 | new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false)); 50 | 51 | request.CertificateExtensions.Add(sanBuilder.Build()); 52 | 53 | var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(3650))); 54 | certificate.FriendlyName = CertificateName; 55 | 56 | return new X509Certificate2(certificate.Export(X509ContentType.Pfx)); 57 | } 58 | } 59 | 60 | private static readonly SemaphoreSlim LogSem = new SemaphoreSlim(1, 1); 61 | 62 | private static async void Log(string message, ConsoleColor color) 63 | { 64 | await LogSem.WaitAsync(); 65 | 66 | Console.ForegroundColor = ConsoleColor.Cyan; 67 | Console.Write("[{0}] ", DateTime.Now.ToLongTimeString()); 68 | Console.ForegroundColor = color; 69 | Console.Write("{0}{1}", message, Environment.NewLine); 70 | Console.ResetColor(); 71 | 72 | LogSem.Release(); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Example/NotLiteCode - Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("NotLiteCode - Server")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("NotLiteCode - Server")] 12 | [assembly: AssemblyCopyright("Copyright © 2016")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("4c4fb7aa-47c2-4717-9499-44ea91450a34")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /Example/NotLiteCode - Server/SharedClass.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Server; 2 | using System; 3 | using System.Net; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | 7 | namespace NotLiteCode___Server 8 | { 9 | public class SharedClass : IDisposable 10 | { 11 | [NLCCall("Pinocchio")] 12 | public string CombineTwoStringsAndReturn(string s1, string s2) 13 | { 14 | return "Magical server says, s1 + s2 = " + s1 + s2; 15 | } 16 | 17 | [NLCCall("JustATest", true)] 18 | public void Test(EndPoint Context) 19 | { 20 | Console.WriteLine($"Hey! {Context} invoked me!"); 21 | } 22 | 23 | [NLCCall("ThroughputTest")] 24 | public async Task SpeedTest() 25 | { 26 | // Simulate asynchronous event 27 | await Task.CompletedTask; 28 | } 29 | 30 | public void Dispose() 31 | { 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Example/NotLiteCode - Server/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /NotLiteCode.Serialization.GroBuf/GroBufSerializationProvider.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Serializer; 2 | using GB = GroBuf; 3 | using GroBuf.DataMembersExtracters; 4 | using GroBuf; 5 | 6 | namespace NotLiteCode.Serialization 7 | { 8 | public class GroBufSerializationProvider : ISerializationProdiver 9 | { 10 | private GB.Serializer serializer = new GB.Serializer(new PropertiesExtractor(), options : GroBufOptions.WriteEmptyObjects); 11 | 12 | public T Deserialize(byte[] data) 13 | { 14 | return serializer.Deserialize(data); 15 | } 16 | 17 | public byte[] Serialize(T data) 18 | { 19 | return serializer.Serialize(data); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /NotLiteCode.Serialization.GroBuf/NotLiteCode.Serialization.GroBuf.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1;net452 5 | 6 | 7 | bin\Release\netcoreapp2.1\ 8 | 9 | 10 | bin\Release\net452\ 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /NotLiteCode.Serialization.GroBuf/NotLiteCode.Serialization.GroBuf.nuspec: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | NotLiteCode.Serialization.GroBuf 5 | 1.0 6 | NotLiteCode.Serialization.GroBuf 7 | V-X 8 | V-X 9 | https://github.com/ImVexed/NotLiteCode/blob/master/LICENSE 10 | https://github.com/ImVexed/NotLiteCode/NotLiteCode.Serialization.GroBuf 11 | false 12 | A GroBuf serialization provider for NotLiteCode 13 | rpc rmi remote 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /NotLiteCode.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.168 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotLiteCode", "NotLiteCode\NotLiteCode.csproj", "{3C70272F-B54E-4B72-B913-EE2AE7432D66}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Example", "Example", "{52CDB862-D9AE-4E26-9F4C-32E549D19EC3}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotLiteCode - Client", "Example\NotLiteCode - Client\NotLiteCode - Client.csproj", "{80A3F0D8-080B-430F-B4BE-173A5EF9AB6F}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotLiteCode - Server", "Example\NotLiteCode - Server\NotLiteCode - Server.csproj", "{4C4FB7AA-47C2-4717-9499-44EA91450A34}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotLiteCode.Serialization.GroBuf", "NotLiteCode.Serialization.GroBuf\NotLiteCode.Serialization.GroBuf.csproj", "{38065060-BB2E-4F7C-AB8A-FBE953628931}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {3C70272F-B54E-4B72-B913-EE2AE7432D66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {3C70272F-B54E-4B72-B913-EE2AE7432D66}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {3C70272F-B54E-4B72-B913-EE2AE7432D66}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {3C70272F-B54E-4B72-B913-EE2AE7432D66}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {4C4FB7AA-47C2-4717-9499-44EA91450A34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {4C4FB7AA-47C2-4717-9499-44EA91450A34}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {4C4FB7AA-47C2-4717-9499-44EA91450A34}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {4C4FB7AA-47C2-4717-9499-44EA91450A34}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {38065060-BB2E-4F7C-AB8A-FBE953628931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {38065060-BB2E-4F7C-AB8A-FBE953628931}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {38065060-BB2E-4F7C-AB8A-FBE953628931}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {38065060-BB2E-4F7C-AB8A-FBE953628931}.Release|Any CPU.Build.0 = Release|Any CPU 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | GlobalSection(NestedProjects) = preSolution 43 | {80A3F0D8-080B-430F-B4BE-173A5EF9AB6F} = {52CDB862-D9AE-4E26-9F4C-32E549D19EC3} 44 | {4C4FB7AA-47C2-4717-9499-44EA91450A34} = {52CDB862-D9AE-4E26-9F4C-32E549D19EC3} 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {903A5622-E077-422F-9D60-C9B3483DA87D} 48 | EndGlobalSection 49 | GlobalSection(Performance) = preSolution 50 | HasPerformanceSessions = true 51 | EndGlobalSection 52 | EndGlobal 53 | -------------------------------------------------------------------------------- /NotLiteCode/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /NotLiteCode/Client/Client.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Network; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using static NotLiteCode.Helpers; 7 | 8 | namespace NotLiteCode.Client 9 | { 10 | public class Client 11 | { 12 | public ConcurrentDictionary Callbacks = new ConcurrentDictionary(); 13 | public NLCSocket ClientSocket; 14 | public bool UseCallbacks; 15 | 16 | private readonly SemaphoreSlim CallSem = new SemaphoreSlim(1, 1); 17 | 18 | public Client() : this(new NLCSocket(), false) 19 | { } 20 | 21 | public Client(NLCSocket ClientSocket) : this(ClientSocket, false) 22 | { } 23 | 24 | public Client(bool UseCallbacks) : this(new NLCSocket(), UseCallbacks) 25 | { } 26 | 27 | public Client(NLCSocket ClientSocket, bool UseCallbacks) 28 | { 29 | this.ClientSocket = ClientSocket; 30 | this.UseCallbacks = UseCallbacks; 31 | 32 | if (UseCallbacks && ClientSocket.BaseSocket.Connected) 33 | { 34 | if (!ClientSocket.ContinueSubscribing) 35 | ClientSocket.ContinueSubscribing = true; 36 | 37 | ClientSocket.OnNetworkMessageReceived += OnCallbackMessageReceived; 38 | } 39 | } 40 | 41 | public bool Connect(string ServerAddress, int ServerPort) 42 | { 43 | ClientSocket.Connect(ServerAddress, ServerPort); 44 | 45 | if (UseCallbacks) 46 | { 47 | ClientSocket.OnNetworkMessageReceived += OnCallbackMessageReceived; 48 | ClientSocket.BeginAcceptMessages(); 49 | } 50 | 51 | return true; 52 | } 53 | 54 | private void OnCallbackMessageReceived(object sender, OnNetworkMessageReceivedEventArgs e) 55 | { 56 | if (e.Message.Header != NetworkHeader.HEADER_RETURN && e.Message.Header != NetworkHeader.HEADER_ERROR) 57 | throw new Exception("Invalid message type received!"); 58 | 59 | Callbacks[e.Message.CallbackGuid].Result = e.Message; 60 | Callbacks[e.Message.CallbackGuid].Event.Set(); 61 | } 62 | 63 | public void Stop() 64 | { 65 | ClientSocket.Close(); 66 | } 67 | 68 | public async Task RemoteCall(string identifier, params object[] param) 69 | { 70 | if (UseCallbacks) 71 | { 72 | var CallbackGuid = Guid.NewGuid().ToString(); 73 | 74 | Callbacks.TryAdd(CallbackGuid, new TiedEventWait()); 75 | 76 | var Event = new NetworkEvent(NetworkHeader.HEADER_MOVE, CallbackGuid, identifier, param); 77 | 78 | if (!await ClientSocket.BlockingSend(Event)) 79 | throw new Exception("Failed to sent request to server!"); 80 | 81 | Callbacks[CallbackGuid].Event.WaitOne(); 82 | 83 | var Result = Callbacks[CallbackGuid].Result; 84 | 85 | Callbacks.TryRemove(CallbackGuid, out _); 86 | 87 | return (T)Result.Data; 88 | } 89 | else 90 | { 91 | await CallSem.WaitAsync(); 92 | 93 | var Event = new NetworkEvent(NetworkHeader.HEADER_MOVE, identifier, param); 94 | 95 | if (!await ClientSocket.BlockingSend(Event)) 96 | throw new Exception("Failed to sent request to server!"); 97 | 98 | NetworkEvent Result; 99 | 100 | if ((Result = await ClientSocket.BlockingReceive()) == default(NetworkEvent)) 101 | throw new Exception("Failed to receive result from server!"); 102 | 103 | if (Result.Header == NetworkHeader.HEADER_ERROR) 104 | throw new Exception("An exception was caused on the server!"); 105 | else if (Result.Header != NetworkHeader.HEADER_RETURN) 106 | throw new Exception("Unexpected error"); 107 | 108 | CallSem.Release(); 109 | 110 | return (T)Result.Data; 111 | } 112 | } 113 | 114 | public async Task RemoteCall(string identifier, params object[] param) 115 | { 116 | if (UseCallbacks) 117 | { 118 | var CallbackID = Guid.NewGuid().ToString(); 119 | 120 | Callbacks.TryAdd(CallbackID, new TiedEventWait()); 121 | 122 | var Event = new NetworkEvent(NetworkHeader.HEADER_CALL, CallbackID, identifier, param); 123 | 124 | if (!await ClientSocket.BlockingSend(Event)) 125 | throw new Exception("Failed to sent request to server!"); 126 | 127 | Callbacks[CallbackID].Event.WaitOne(); 128 | 129 | Callbacks.TryRemove(CallbackID, out _); 130 | } 131 | else 132 | { 133 | await CallSem.WaitAsync(); 134 | 135 | var Event = new NetworkEvent(NetworkHeader.HEADER_CALL, identifier, param); 136 | 137 | if (!await ClientSocket.BlockingSend(Event)) 138 | throw new Exception("Failed to sent request to server!"); 139 | 140 | NetworkEvent ReturnEvent; 141 | 142 | if ((ReturnEvent = await ClientSocket.BlockingReceive()) == default(NetworkEvent)) 143 | throw new Exception("Failed to receive result from server!"); 144 | 145 | if (ReturnEvent.Header == NetworkHeader.HEADER_ERROR) 146 | throw new Exception("An exception was caused on the server!"); 147 | else if (ReturnEvent.Header != NetworkHeader.HEADER_RETURN) 148 | throw new Exception("Unexpected error"); 149 | 150 | CallSem.Release(); 151 | } 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /NotLiteCode/Misc/Helpers.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Network; 2 | using System; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace NotLiteCode 11 | { 12 | public static class Helpers 13 | { 14 | public static bool TryParseEnum(this object SourceObject, out T EnumValue) 15 | { 16 | if (!Enum.IsDefined(typeof(T), SourceObject)) 17 | { 18 | EnumValue = default(T); 19 | return false; 20 | } 21 | 22 | EnumValue = (T)Enum.Parse(typeof(T), SourceObject.ToString()); 23 | return true; 24 | } 25 | 26 | public static async Task InvokeWrapper(this Func Method, bool HasAsyncResult, object Target, params object[] Args) 27 | { 28 | var Result = Method(Target, Args); 29 | if (!(Result is Task task)) 30 | return Result; 31 | 32 | if (!task.IsCompleted) 33 | await task.ConfigureAwait(false); 34 | 35 | return HasAsyncResult ? task.GetType().GetProperty("Result")?.GetValue(task) : null; 36 | } 37 | 38 | public static Func CreateMethodWrapper(Type type, MethodInfo method) 39 | { 40 | var paramsExps = CreateParamsExpressions(method, out ParameterExpression argsExp); 41 | 42 | var targetExp = Expression.Parameter(typeof(object)); 43 | var castTargetExp = Expression.Convert(targetExp, type); 44 | var invokeExp = Expression.Call(castTargetExp, method, paramsExps); 45 | 46 | LambdaExpression lambdaExp; 47 | 48 | if (method.ReturnType != typeof(void)) 49 | { 50 | var resultExp = Expression.Convert(invokeExp, typeof(object)); 51 | lambdaExp = Expression.Lambda(resultExp, targetExp, argsExp); 52 | } 53 | else 54 | { 55 | var constExp = Expression.Constant(null, typeof(object)); 56 | var blockExp = Expression.Block(invokeExp, constExp); 57 | lambdaExp = Expression.Lambda(blockExp, targetExp, argsExp); 58 | } 59 | 60 | var lambda = lambdaExp.Compile(); 61 | return (Func)lambda; 62 | } 63 | 64 | private static Expression[] CreateParamsExpressions(MethodBase method, out ParameterExpression argsExp) 65 | { 66 | var parameters = method.GetParameters().Select(x => x.ParameterType).ToArray(); 67 | 68 | argsExp = Expression.Parameter(typeof(object[])); 69 | var paramsExps = new Expression[parameters.Count()]; 70 | 71 | for (var i = 0; i < parameters.Count(); i++) 72 | { 73 | var constExp = Expression.Constant(i, typeof(int)); 74 | var argExp = Expression.ArrayIndex(argsExp, constExp); 75 | paramsExps[i] = Expression.Convert(argExp, parameters[i]); 76 | } 77 | 78 | return paramsExps; 79 | } 80 | 81 | public static void Start(this EventHandler Event, object Source, T Data) 82 | { 83 | Task.Run(() => Event(Source, Data)); 84 | } 85 | 86 | public class TiedEventWait 87 | { 88 | public EventWaitHandle Event = new EventWaitHandle(false, EventResetMode.ManualReset); 89 | public NetworkEvent Result; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /NotLiteCode/Network/Network.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Serializer; 2 | using System; 3 | using System.Net; 4 | using System.Net.Security; 5 | using System.Net.Sockets; 6 | using System.Security.Authentication; 7 | using System.Security.Cryptography.X509Certificates; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace NotLiteCode.Network 12 | { 13 | public enum NetworkHeader 14 | { 15 | NONE, 16 | HEADER_HANDSHAKE, 17 | HEADER_CALL, 18 | HEADER_MOVE, 19 | HEADER_RETURN, 20 | HEADER_ERROR 21 | } 22 | 23 | public class NLCSocket 24 | { 25 | public event EventHandler OnNetworkClientDisconnected; 26 | 27 | public event EventHandler OnNetworkExceptionOccurred; 28 | 29 | public event EventHandler OnNetworkMessageReceived; 30 | 31 | public event EventHandler OnNetworkClientConnected; 32 | 33 | public event EventHandler OnNetworkDataReceived; 34 | 35 | public event EventHandler OnNetworkDataSent; 36 | 37 | private readonly SemaphoreSlim BaseSocketReadSem = new SemaphoreSlim(1, 1); 38 | private readonly SemaphoreSlim BaseSocketWriteSem = new SemaphoreSlim(1, 1); 39 | private byte[] NextBufferLength = new byte[4]; 40 | private bool Stopping = false; 41 | 42 | public readonly Socket BaseSocket; 43 | public readonly int BacklogLength; 44 | public readonly int ListenPort; 45 | 46 | private readonly ISerializationProdiver SerializationProdiver; 47 | private readonly X509Certificate2 ServerCertificate; 48 | private readonly bool AllowInsecureCerts; 49 | private SslStream SSLStream; 50 | 51 | public readonly bool UseSSL; 52 | public readonly bool UseCompression; 53 | public bool IsListening = false; 54 | 55 | /// 56 | /// Continue to BeginAccept messages 57 | /// 58 | public bool ContinueSubscribing = true; 59 | 60 | /// Option to enable encryption of data via SSL 61 | /// Don't attempt to validate the server's certificate client side 62 | /// Certificate to serve to the client while establishing an SSL connection 63 | public NLCSocket(bool UseSSL = false, bool AllowInsecureCerts = false, X509Certificate2 ServerCertificate = null) 64 | : this(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp), new DefaultSerializationProvider(), UseSSL, AllowInsecureCerts, ServerCertificate) 65 | { } 66 | 67 | /// Underlying socket to use 68 | /// Option to enable encryption of data via SSL 69 | /// Don't attempt to validate the server's certificate client side 70 | /// Certificate to serve to the client while establishing an SSL connection 71 | public NLCSocket(Socket Socket, bool UseSSL = false, bool AllowInsecureCerts = false, X509Certificate2 ServerCertificate = null) 72 | : this(Socket, new DefaultSerializationProvider(), UseSSL, AllowInsecureCerts, ServerCertificate) 73 | { } 74 | 75 | /// Serializer to serialize messages with 76 | /// Option to enable encryption of data via SSL 77 | /// Don't attempt to validate the server's certificate client side 78 | /// Certificate to serve to the client while establishing an SSL connection 79 | public NLCSocket(ISerializationProdiver Serializer, bool UseSSL = false, bool AllowInsecureCerts = false, X509Certificate2 ServerCertificate = null) 80 | : this(new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp), Serializer, UseSSL, AllowInsecureCerts, ServerCertificate) 81 | { } 82 | 83 | /// Underlying socket to use 84 | /// Serializer to serialize messages with 85 | /// Option to enable encryption of data via SSL 86 | /// Don't attempt to validate the server's certificate client side 87 | /// Certificate to serve to the client while establishing an SSL connection 88 | public NLCSocket(Socket Socket, ISerializationProdiver Serializer, bool UseSSL = false, bool AllowInsecureCerts = false, X509Certificate2 ServerCertificate = null) 89 | { 90 | BaseSocket = Socket; 91 | 92 | this.UseSSL = UseSSL; 93 | this.ServerCertificate = ServerCertificate; 94 | this.AllowInsecureCerts = AllowInsecureCerts; 95 | this.SerializationProdiver = Serializer; 96 | 97 | if (BaseSocket.Connected) 98 | { 99 | if (UseSSL) 100 | { 101 | SetupSSL(); 102 | 103 | SSLStream.AuthenticateAsServer(ServerCertificate, clientCertificateRequired: false, checkCertificateRevocation: true, enabledSslProtocols: SslProtocols.Tls12); 104 | } 105 | } 106 | } 107 | 108 | /// 109 | /// Close the socket 110 | /// 111 | public void Close() 112 | { 113 | Stopping = true; 114 | BaseSocket.Close(); 115 | } 116 | 117 | /// 118 | /// Send raw data over the underlying socket 119 | /// 120 | public int Send(byte[] Buffer, int Offset, int Size, SocketFlags Flags, out SocketError SocketError) 121 | { 122 | int Length = Size; 123 | 124 | SocketError = SocketError.Success; 125 | 126 | try 127 | { 128 | if (UseSSL) 129 | SSLStream.Write(Buffer, Offset, Size); 130 | else 131 | Length = BaseSocket.Send(Buffer, Offset, Size, Flags, out SocketError); 132 | } 133 | catch 134 | { 135 | SocketError = SocketError.SocketError; 136 | } 137 | 138 | OnNetworkDataSent?.Start(this, new OnNetworkDataSentEventArgs(Length)); 139 | 140 | return Length; 141 | } 142 | 143 | /// 144 | /// Reads raw data from the underlying socket 145 | /// 146 | public int Receive(byte[] Buffer, int Offset, int Size, SocketFlags Flags, out SocketError SocketError) 147 | { 148 | int Length = 0; 149 | 150 | SocketError = SocketError.Success; 151 | 152 | try 153 | { 154 | if (UseSSL) 155 | Length = SSLStream.Read(Buffer, Offset, Size); 156 | else 157 | Length = BaseSocket.Receive(Buffer, Offset, Size, Flags, out SocketError); 158 | } 159 | catch 160 | { 161 | SocketError = SocketError.SocketError; 162 | } 163 | 164 | OnNetworkDataReceived?.Start(this, new OnNetworkDataReceivedEventArgs(Length)); 165 | 166 | return Length; 167 | } 168 | 169 | /// 170 | /// Begin to listen for incoming connections 171 | /// 172 | /// Network port to listen on 173 | /// Maximum backlog length 174 | public void Listen(int ListenPort = 1337, int BacklogLength = 5) 175 | { 176 | // Don't re-bind the socket if it already has live connections 177 | if (!BaseSocket.IsBound) 178 | { 179 | BaseSocket.Bind(new IPEndPoint(IPAddress.Any, ListenPort)); 180 | BaseSocket.Listen(BacklogLength); 181 | } 182 | 183 | BaseSocket.BeginAccept(AcceptCallback, null); 184 | } 185 | 186 | /// 187 | /// Connect to another socket 188 | /// 189 | /// Remote socket address 190 | /// Remote socket port 191 | public void Connect(string Address = "localhost", int Port = 1337) 192 | { 193 | BaseSocket.Connect(Address, Port); 194 | 195 | if (UseSSL) 196 | { 197 | SetupSSL(); 198 | SSLStream.AuthenticateAsClient(Address, clientCertificates: null, enabledSslProtocols: SslProtocols.Tls12, checkCertificateRevocation: true); 199 | } 200 | } 201 | 202 | private void SetupSSL() 203 | { 204 | if (AllowInsecureCerts) 205 | SSLStream = new SslStream(new NetworkStream(BaseSocket), false, new RemoteCertificateValidationCallback((w, x, y, z) => true), null); 206 | else 207 | SSLStream = new SslStream(new NetworkStream(BaseSocket), false); 208 | } 209 | 210 | /// 211 | /// Accept new clients loop 212 | /// 213 | private void AcceptCallback(IAsyncResult iAR) 214 | { 215 | if (Stopping) 216 | return; 217 | 218 | var ConnectingClient = BaseSocket.EndAccept(iAR); 219 | 220 | OnNetworkClientConnected?.Start(this, new OnNetworkClientConnectedEventArgs(new NLCSocket(ConnectingClient, SerializationProdiver, UseSSL, AllowInsecureCerts, ServerCertificate))); 221 | 222 | BaseSocket.BeginAccept(AcceptCallback, null); 223 | } 224 | 225 | /// 226 | /// Begin accepting messages 227 | /// 228 | public void BeginAcceptMessages() 229 | { 230 | this.IsListening = true; 231 | 232 | if (UseSSL) 233 | SSLStream.BeginRead(NextBufferLength, 0, 4, MessageRetrieveCallback, null); 234 | else 235 | BaseSocket.BeginReceive(NextBufferLength, 0, 4, SocketFlags.None, MessageRetrieveCallback, null); 236 | } 237 | 238 | /// 239 | /// Main message received loop 240 | /// 241 | private void MessageRetrieveCallback(IAsyncResult AsyncResult) 242 | { 243 | if (Stopping) 244 | return; 245 | 246 | bool StatusOK; 247 | 248 | try 249 | { 250 | if (UseSSL) 251 | StatusOK = SSLStream.EndRead(AsyncResult) != 0; 252 | else 253 | StatusOK = BaseSocket.EndReceive(AsyncResult, out var ErrorCode) != 0 && ErrorCode == SocketError.Success; 254 | } 255 | catch 256 | { 257 | StatusOK = false; 258 | } 259 | 260 | // Check the message state to see if we've been disconnected 261 | if (!StatusOK) 262 | { 263 | OnNetworkClientDisconnected?.Start(this, new OnNetworkClientDisconnectedEventArgs(BaseSocket?.RemoteEndPoint)); 264 | 265 | this.Close(); 266 | this.IsListening = false; 267 | 268 | return; 269 | } 270 | 271 | // Take our initial first 4 bytes we've received so we know how large the actual message is 272 | var BufferLength = BitConverter.ToInt32(NextBufferLength, 0); 273 | NextBufferLength = new byte[4]; 274 | 275 | var Buffer = new byte[BufferLength]; 276 | 277 | var BytesReceived = 0; 278 | 279 | while (BytesReceived < BufferLength) 280 | { 281 | var BytesReceiving = this.Receive(Buffer, BytesReceived, BufferLength - BytesReceived, SocketFlags.None, out var ErrorCode); 282 | if (ErrorCode != SocketError.Success) 283 | { 284 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Invalid ammount of data received from Client! Expected {BufferLength} got {BytesReceived} with exception {ErrorCode}"))); 285 | BeginAcceptMessages(); 286 | return; 287 | } 288 | else 289 | BytesReceived += BytesReceiving; 290 | } 291 | 292 | // Deserialize the decrypted message into a raw object array 293 | NetworkEvent DeserializedEvent; 294 | 295 | try 296 | { 297 | DeserializedEvent = SerializationProdiver.Deserialize(Buffer); 298 | } 299 | catch 300 | { 301 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Corrupted data received!"))); 302 | BeginAcceptMessages(); 303 | return; 304 | } 305 | 306 | // Notify that we've received a network event 307 | OnNetworkMessageReceived?.Start(this, new OnNetworkMessageReceivedEventArgs(DeserializedEvent)); 308 | 309 | // Loop 310 | if (ContinueSubscribing) 311 | BeginAcceptMessages(); 312 | } 313 | 314 | /// 315 | /// Synchronously send a network event 316 | /// 317 | /// Event to send 318 | public async Task BlockingSend(NetworkEvent Event) 319 | { 320 | await BaseSocketWriteSem.WaitAsync(); 321 | 322 | var Buffer = SerializationProdiver.Serialize(Event); 323 | 324 | int BytesSent; 325 | 326 | if ((BytesSent = this.Send(BitConverter.GetBytes(Buffer.Length), 0, 4, SocketFlags.None, out var ErrorCode)) != 4 || ErrorCode != SocketError.Success) 327 | { 328 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Invalid ammount of data sent to Client! Expected {Buffer.Length} sent {BytesSent} with exception {ErrorCode}"))); 329 | return false; 330 | } 331 | 332 | if ((BytesSent = this.Send(Buffer, 0, Buffer.Length, SocketFlags.None, out ErrorCode)) != Buffer.Length || ErrorCode != SocketError.Success) 333 | { 334 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Invalid ammount of data sent to Client! Expected {Buffer.Length} sent {BytesSent} with exception {ErrorCode}"))); 335 | return false; 336 | } 337 | 338 | BaseSocketWriteSem.Release(); 339 | 340 | return true; 341 | } 342 | 343 | /// 344 | /// Synchronously receive a network event, note that this can interfeared with MessageRetrieveCallback if the base socket is already blocking 345 | /// 346 | public async Task BlockingReceive() 347 | { 348 | await BaseSocketReadSem.WaitAsync(); 349 | 350 | byte[] NewBufferLength = new byte[4]; 351 | 352 | int BytesReceived; 353 | if ((BytesReceived = this.Receive(NewBufferLength, 0, 4, SocketFlags.None, out var ErrorCode)) != 4 || ErrorCode != SocketError.Success) 354 | { 355 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Invalid ammount of data received from Client! Expected {4} got {BytesReceived} with exception {ErrorCode}"))); 356 | return default(NetworkEvent); 357 | } 358 | 359 | var BufferLength = BitConverter.ToInt32(NewBufferLength, 0); 360 | var Buffer = new byte[BufferLength]; 361 | 362 | BytesReceived = 0; 363 | while (BytesReceived < BufferLength) 364 | { 365 | var BytesReceiving = this.Receive(Buffer, BytesReceived, BufferLength - BytesReceived, SocketFlags.None, out ErrorCode); 366 | if (ErrorCode != SocketError.Success) 367 | { 368 | OnNetworkExceptionOccurred?.Start(this, new OnNetworkExceptionOccurredEventArgs(new Exception($"Invalid ammount of data received from Client! Expected {BufferLength} got {BytesReceived} with exception {ErrorCode}"))); 369 | return default(NetworkEvent); 370 | } 371 | else 372 | BytesReceived += BytesReceiving; 373 | } 374 | 375 | var Event = SerializationProdiver.Deserialize(Buffer); 376 | 377 | BaseSocketReadSem.Release(); 378 | 379 | return Event; 380 | } 381 | } 382 | } -------------------------------------------------------------------------------- /NotLiteCode/Network/NetworkEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Net; 4 | 5 | namespace NotLiteCode.Network 6 | { 7 | [Serializable] 8 | public class NetworkEvent 9 | { 10 | public NetworkHeader Header { get; set; } 11 | public string CallbackGuid { get; set; } 12 | public string Tag { get; set; } 13 | public object Data { get; set; } 14 | 15 | public NetworkEvent(NetworkHeader Header, string Tag, object Data) 16 | { 17 | this.Header = Header; 18 | this.CallbackGuid = null; 19 | this.Tag = Tag; 20 | this.Data = Data; 21 | } 22 | 23 | public NetworkEvent(NetworkHeader Header, string CallbackGuid, string Tag, object Data) 24 | { 25 | this.Header = Header; 26 | this.CallbackGuid = CallbackGuid; 27 | this.Tag = Tag; 28 | this.Data = Data; 29 | } 30 | } 31 | 32 | public class OnNetworkMessageReceivedEventArgs : AsyncCompletedEventArgs 33 | { 34 | public readonly NetworkEvent Message; 35 | 36 | public OnNetworkMessageReceivedEventArgs(NetworkEvent Message) : base(null, false, null) 37 | { 38 | this.Message = Message; 39 | } 40 | } 41 | 42 | public class OnNetworkClientConnectedEventArgs : EventArgs 43 | { 44 | public readonly NLCSocket Client; 45 | 46 | public OnNetworkClientConnectedEventArgs(NLCSocket Client) 47 | { 48 | this.Client = Client; 49 | } 50 | } 51 | 52 | public class OnNetworkClientDisconnectedEventArgs : EventArgs 53 | { 54 | public readonly EndPoint Client; 55 | 56 | public OnNetworkClientDisconnectedEventArgs(EndPoint Client) 57 | { 58 | this.Client = Client; 59 | } 60 | } 61 | 62 | public class OnNetworkExceptionOccurredEventArgs : EventArgs 63 | { 64 | public readonly Exception Exception; 65 | 66 | public OnNetworkExceptionOccurredEventArgs(Exception Exception) 67 | { 68 | this.Exception = Exception; 69 | } 70 | } 71 | 72 | public class OnNetworkDataReceivedEventArgs : EventArgs 73 | { 74 | public readonly int BytesReceived; 75 | 76 | public OnNetworkDataReceivedEventArgs(int BytesReceived) 77 | { 78 | this.BytesReceived = BytesReceived; 79 | } 80 | } 81 | 82 | public class OnNetworkDataSentEventArgs : EventArgs 83 | { 84 | public readonly int BytesSent; 85 | 86 | public OnNetworkDataSentEventArgs(int BytesSent) 87 | { 88 | this.BytesSent = BytesSent; 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /NotLiteCode/NotLiteCode.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.1;net452 5 | 6 | 7 | bin\Release\netcoreapp2.1\ 8 | 9 | 10 | bin\Release\net452\ 11 | 12 | 13 | 14 | 15 | 16 | 17 | ..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll 18 | 19 | 20 | -------------------------------------------------------------------------------- /NotLiteCode/NotLiteCode.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | NotLiteCode 5 | 1.5.2 6 | NotLiteCode 7 | V-X 8 | V-X 9 | https://github.com/ImVexed/NotLiteCode/blob/master/LICENSE 10 | https://github.com/ImVexed/NotLiteCode 11 | false 12 | A simple hackable remote code hosting platform. 13 | rpc rmi remote 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /NotLiteCode/Serializer/DefaultSerializationProvider.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Runtime.Serialization.Formatters.Binary; 3 | 4 | namespace NotLiteCode.Serializer 5 | { 6 | internal class DefaultSerializationProvider : ISerializationProdiver 7 | { 8 | private BinaryFormatter Serializer = new BinaryFormatter(); 9 | 10 | public byte[] Serialize(T data) 11 | { 12 | using (MemoryStream OutputStream = new MemoryStream()) 13 | { 14 | Serializer.Serialize(OutputStream, data); 15 | return OutputStream.ToArray(); 16 | } 17 | } 18 | 19 | public T Deserialize(byte[] MessageData) 20 | { 21 | using (MemoryStream OutputStream = new MemoryStream(MessageData)) 22 | return (T)Serializer.Deserialize(OutputStream); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /NotLiteCode/Serializer/ISerializationProdiver.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Network; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace NotLiteCode.Serializer 8 | { 9 | public interface ISerializationProdiver 10 | { 11 | byte[] Serialize(T data); 12 | T Deserialize(byte[] data); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /NotLiteCode/Server/Server.cs: -------------------------------------------------------------------------------- 1 | using NotLiteCode.Network; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Linq.Expressions; 7 | using System.Net; 8 | using System.Reflection; 9 | using System.Runtime.CompilerServices; 10 | using System.Threading.Tasks; 11 | 12 | namespace NotLiteCode.Server 13 | { 14 | public class Server where T : IDisposable, new() 15 | { 16 | private void NetworkClientDisconnected(object sender, OnNetworkClientDisconnectedEventArgs e) => 17 | OnServerClientDisconnected?.Start(this, new OnServerClientDisconnectedEventArgs(e.Client)); 18 | 19 | private void NetworkExceptionOccurred(object sender, OnNetworkExceptionOccurredEventArgs e) => 20 | OnServerExceptionOccurred?.Start(this, new OnServerExceptionOccurredEventArgs(e.Exception)); 21 | 22 | public event EventHandler OnServerClientDisconnected; 23 | 24 | public event EventHandler OnServerExceptionOccurred; 25 | 26 | public event EventHandler OnServerClientConnected; 27 | 28 | public event EventHandler OnServerMethodInvoked; 29 | 30 | private readonly Dictionary RemotingMethods = new Dictionary(); 31 | 32 | public Dictionary> Clients = new Dictionary>(); 33 | 34 | public NLCSocket ServerSocket; 35 | 36 | public Server() : this(new NLCSocket()) 37 | { } 38 | 39 | public Server(NLCSocket ServerSocket) 40 | { 41 | this.ServerSocket = ServerSocket; 42 | RegisterFunctions(); 43 | } 44 | 45 | private void RegisterFunctions() 46 | { 47 | foreach (MethodInfo SharedMethod in typeof(T).GetMethods()) 48 | { 49 | if (SharedMethod.GetCustomAttribute(typeof(NLCCall)) is NLCCall NLCAttribute) 50 | { 51 | if (RemotingMethods.ContainsKey(NLCAttribute.Identifier)) 52 | { 53 | OnServerExceptionOccurred?.Start(this, new OnServerExceptionOccurredEventArgs(new Exception($"Method with identifier {NLCAttribute.Identifier} already exists!"))); 54 | continue; 55 | } 56 | 57 | var IsAsync = SharedMethod.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) is AsyncStateMachineAttribute; 58 | var ReturnType = SharedMethod.ReturnType; 59 | var HasAsyncResult = ReturnType.IsGenericType && ReturnType.GetGenericTypeDefinition() == typeof(Task<>); 60 | 61 | if (!HasAsyncResult && IsAsync && ReturnType != typeof(Task)) 62 | throw new Exception($"Shared function {NLCAttribute.Identifier} is asynchronous but does not return a Task!"); 63 | 64 | RemotingMethods.Add(NLCAttribute.Identifier, new RemotingMethod() { 65 | Method = Helpers.CreateMethodWrapper(typeof(T), SharedMethod), 66 | WithContext = NLCAttribute.WithContext, 67 | HasAsyncResult = HasAsyncResult 68 | }); 69 | } 70 | } 71 | } 72 | 73 | public void Start(int Port = 1337) 74 | { 75 | ServerSocket.OnNetworkExceptionOccurred += (x, y) => OnServerExceptionOccurred?.Start(this, new OnServerExceptionOccurredEventArgs(y.Exception)); 76 | ServerSocket.OnNetworkClientConnected += OnNetworkClientConnected; 77 | 78 | ServerSocket.Listen(Port); 79 | } 80 | 81 | public void Stop() 82 | { 83 | ServerSocket.Close(); 84 | } 85 | 86 | public void ManuallyConnectSocket(NLCSocket Socket) 87 | { 88 | OnNetworkClientConnected(null, new OnNetworkClientConnectedEventArgs(Socket)); 89 | } 90 | 91 | private void OnNetworkClientConnected(object sender, OnNetworkClientConnectedEventArgs e) 92 | { 93 | var Client = new RemoteClient(e.Client); 94 | e.Client.OnNetworkClientDisconnected += NetworkClientDisconnected; 95 | e.Client.OnNetworkExceptionOccurred += NetworkExceptionOccurred; 96 | e.Client.OnNetworkMessageReceived += OnNetworkMessageReceived; 97 | 98 | Clients.Add(e.Client.BaseSocket.RemoteEndPoint, Client); 99 | 100 | if(!e.Client.IsListening) 101 | e.Client.BeginAcceptMessages(); 102 | 103 | OnServerClientConnected?.Start(this, new OnServerClientConnectedEventArgs(e.Client.BaseSocket.RemoteEndPoint)); 104 | } 105 | 106 | public void DetatchFromSocket(NLCSocket Socket) 107 | { 108 | Socket.OnNetworkClientDisconnected -= NetworkClientDisconnected; 109 | Socket.OnNetworkExceptionOccurred -= NetworkExceptionOccurred; 110 | Socket.OnNetworkMessageReceived -= OnNetworkMessageReceived; 111 | } 112 | 113 | private async void OnNetworkMessageReceived(object sender, OnNetworkMessageReceivedEventArgs e) 114 | { 115 | if (e.Message.Header != NetworkHeader.HEADER_CALL && e.Message.Header != NetworkHeader.HEADER_MOVE) 116 | return; 117 | 118 | var RemoteEndPoint = ((NLCSocket)sender).BaseSocket.RemoteEndPoint; 119 | 120 | object Result = null; 121 | NetworkHeader ResultHeader; 122 | 123 | if (!RemotingMethods.TryGetValue(e.Message.Tag, out var TargetMethod)) 124 | { 125 | OnServerExceptionOccurred?.Start(this, new OnServerExceptionOccurredEventArgs(new Exception("Client attempted to invoke invalid function!"))); 126 | ResultHeader = NetworkHeader.NONE; 127 | } 128 | else 129 | { 130 | var Parameters = new List(); 131 | 132 | if (TargetMethod.WithContext) 133 | Parameters.Add(RemoteEndPoint); 134 | 135 | Parameters.AddRange((object[])e.Message.Data); 136 | 137 | TimeSpan Duration = default(TimeSpan); 138 | 139 | try 140 | { 141 | var sw = Stopwatch.StartNew(); 142 | 143 | Result = await TargetMethod.Method.InvokeWrapper(TargetMethod.HasAsyncResult, Clients[RemoteEndPoint].SharedClass, Parameters.ToArray()); 144 | 145 | sw.Stop(); 146 | 147 | Duration = sw.Elapsed; 148 | 149 | ResultHeader = NetworkHeader.HEADER_RETURN; 150 | } 151 | catch (Exception ex) 152 | { 153 | OnServerExceptionOccurred?.Start(this, new OnServerExceptionOccurredEventArgs(ex)); 154 | ResultHeader = NetworkHeader.HEADER_ERROR; 155 | } 156 | 157 | OnServerMethodInvoked?.Start(this, new OnServerMethodInvokedEventArgs(RemoteEndPoint, e.Message.Tag, Duration, ResultHeader == NetworkHeader.HEADER_ERROR)); 158 | } 159 | 160 | var Event = new NetworkEvent(ResultHeader, e.Message.CallbackGuid, null, Result); 161 | 162 | await ((NLCSocket)sender).BlockingSend(Event); 163 | } 164 | } 165 | 166 | [AttributeUsage(AttributeTargets.Method)] 167 | public class NLCCall : Attribute 168 | { 169 | public readonly string Identifier; 170 | public readonly bool WithContext; 171 | 172 | public NLCCall(string Identifier, bool WithContext = false) 173 | { 174 | this.Identifier = Identifier; 175 | this.WithContext = WithContext; 176 | } 177 | } 178 | 179 | public struct RemotingMethod 180 | { 181 | public Func Method; 182 | public bool WithContext; 183 | public bool HasAsyncResult; 184 | } 185 | 186 | public class RemoteClient where T : IDisposable, new() 187 | { 188 | public NLCSocket Socket; 189 | public T SharedClass; 190 | 191 | public RemoteClient(NLCSocket Socket) 192 | { 193 | this.Socket = Socket; 194 | this.SharedClass = new T(); 195 | } 196 | } 197 | } -------------------------------------------------------------------------------- /NotLiteCode/Server/ServerEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace NotLiteCode.Server 5 | { 6 | public class OnServerClientConnectedEventArgs : EventArgs 7 | { 8 | public readonly EndPoint Client; 9 | 10 | public OnServerClientConnectedEventArgs(EndPoint Client) 11 | { 12 | this.Client = Client; 13 | } 14 | } 15 | 16 | public class OnServerClientDisconnectedEventArgs : EventArgs 17 | { 18 | public readonly EndPoint Client; 19 | 20 | public OnServerClientDisconnectedEventArgs(EndPoint Client) 21 | { 22 | this.Client = Client; 23 | } 24 | } 25 | 26 | public class OnServerMethodInvokedEventArgs : EventArgs 27 | { 28 | public readonly EndPoint Client; 29 | public readonly string Identifier; 30 | public readonly TimeSpan Duration; 31 | public readonly bool WasErroneous; 32 | 33 | public OnServerMethodInvokedEventArgs(EndPoint Client, string Identifier, TimeSpan Duration, bool WasErroneous) 34 | { 35 | this.Client = Client; 36 | this.Duration = Duration; 37 | this.Identifier = Identifier; 38 | this.WasErroneous = WasErroneous; 39 | } 40 | } 41 | 42 | public class OnServerExceptionOccurredEventArgs : EventArgs 43 | { 44 | public readonly Exception Exception; 45 | 46 | public OnServerExceptionOccurredEventArgs(Exception Exception) 47 | { 48 | this.Exception = Exception; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://ci.appveyor.com/api/projects/status/github/ImVexed/notlitecode?branch=master)](https://ci.appveyor.com/project/ImVexed/notlitecode?branch=master) 2 | [![Code Factor](https://www.codefactor.io/repository/github/imvexed/notlitecode/badge)](https://www.codefactor.io/repository/github/imvexed/notlitecode) 3 | [![GitHub license](https://img.shields.io/github/license/ImVexed/NotLiteCode.svg)](https://github.com/ImVexed/NotLiteCode/blob/master/LICENSE) 4 | [![NuGet](https://img.shields.io/nuget/v/Nuget.Core.svg)](https://www.nuget.org/packages/NotLiteCode) 5 | 6 | # NotLiteCode 7 | A simple, hackable, remote code hosting platform. 8 | 9 | ## What is? 10 | NLC (Not Lite Code) is a simplified version of LiteCode by *DragonHunter*, which provides native RPC and other useful features without any external dependencies. 11 | 12 | ## How does this differ from traditional RPC/RMI? 13 | Traditionally RPC/RMI implements a stub interface and is tightly coupled. NLC however can function without a stub interface by using `BinaryFormatter` to serialize & deserialize objects on the fly at runtime allowing it to be loosly coupled. NLC also allows communication over `SSLStream` for security. 14 | 15 | ## How is state handled? 16 | NLC creates a unique instance for every client allowing you to keep stateful data alongside their functions in the `SharedClass`. 17 | 18 | ## How is concurrency handled? 19 | As of 1.4 NLC's networking core is now asynchronous and will invoke calls in a new Task once the data is received. Thus any synchronization must either be ensured in the client invoking the methods or inside the SharedClass functions themselves. 20 | 21 | ## Sample Implementation 22 | ### Server Code: 23 | SharedClass.cs 24 | ```C# 25 | [NLCCall("MagicNumber")] 26 | public bool IsMagicNumber(int number) 27 | { 28 | return number == 7; 29 | } 30 | ``` 31 | Program.cs 32 | ```C# 33 | server = new Server(); 34 | server.Start(); 35 | ``` 36 | ### Client Code: 37 | Program.cs 38 | ```C# 39 | public static async Task IsMagicNumber(int number) => 40 | await client.RemoteCall("MagicNumber", number); 41 | 42 | client = new Client(); 43 | 44 | client.Connect("localhost", 1337); 45 | 46 | Console.WriteLine(await IsMagicNumber(-10)); // False 47 | Console.WriteLine(await IsMagicNumber(7)); // True 48 | ``` 49 | ## Sample Outputs 50 | 51 | 52 | ## Original 53 | [LiteCode](https://gitlab.com/Dergan/LiteCode) by *DragonHunter* 54 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2017 3 | configuration: 4 | - Release 5 | platform: Any CPU 6 | shallow_clone: true 7 | before_build: 8 | - nuget restore 9 | build: 10 | project: NotLiteCode.sln 11 | parallel: true 12 | verbosity: minimal 13 | after_build: 14 | - nuget pack NotLiteCode\NotLiteCode.nuspec 15 | - nuget pack NotLiteCode.Serialization.GroBuf\NotLiteCode.Serialization.GroBuf.nuspec 16 | deploy: 17 | provider: NuGet 18 | api_key: 19 | secure: UMw0wyrvQWsWSaXOJ///2NLwm9dhc8WRLXkUolngxDocRQJeuumghIsqayZpP5NM 20 | artifact: NLC-Package 21 | artifacts: 22 | - path: '*.nupkg' 23 | name: NLC-Package 24 | type: NuGetPackage 25 | --------------------------------------------------------------------------------