Shadow Network Framework  0.0.1-alpha
.NET Client Library for Shadow Network Framework
Loading...
Searching...
No Matches
Tutorials

Welcome to the Tutorials, here you can learn how to use certain aspects of this Library

Note
As this is an alpha release, there is bound to be unstable, barely useable, bugy experience.

Connections

This shows you how to handle anything related to connections You can jump to Practical Example for a practical and proper way to Start a new connection.

For the Proper use and setup of the Connection Ìnstances you have to go through 5 steps:

Instantiate a new Connection object

Never call new Connection() to get a new object instance instead there is 2 methods you can use (Depending On your use case)

In case of a Single Connection

Then preferably Use the global instantiator and always use the Global Instance for sending/receiving requests

Connection.Instantiate()
.SetHost("<URL>")
.SetPort(<PORT>);

In case of multiple Connections

Then create instances using the Instantiate(string, int) Method

Connection cnx = Connection.Instantiate(
/// SNF Host's URL
"<URL>",
/// SNF Host's port
<PORT>
);
Note
Using Method 1 or 2 is purely personal choice, however for the Sake of this tutorial we'll be using the Method 1 for the following examples

Set Event CallBacks

SNF Connections currenty has 5 Event Callbacks each serving a purpose

Warning
Never Set any Event Callback after(if it connected) and/or while Connecting

OnConnection

When is it Called?: This Event will raise it's call back when a connection was established between the Client and Server and the SNF Protocol has finished the initial handshake
Type of CallBack: SimpleCB
How to Set: SetOnConnection(SimpleCB)
Method 1:

  • Define the callback
    void OnConnectCallBack() {
    ...
    /// The Callback Content
    ...
    }
  • Set the CallBack
    /// Assume this is the isntantiated `Connection` object
    /// TIP:
    /// If it a Globaly Instantiated Object,
    /// 'cnx' 's value equals Connection.get()
    /// or use Connection.get() directly
    Connection cnx;
    ...
    cnx.SetOnConnection(OnConnectCallBack);
    ...

Method 2:

  • Define the callback and Set it directly
    ...
    cnx.SetOnConnection(
    () => {
    ...
    /// The Callback Content
    ...
    }
    );
    ...

OnException

When is it Called?: This Event will raise a certain(and possibly unknown) exception was called and wasn't handled properly by SNFClient
Type of CallBack: ExceptionCB
How to Set: SetOnException(ExceptionCB)
Method 1:

  • Define the callback
    void OnExceptionCallBack(Exception ex) {
    ...
    /// The Callback Content
    ...
    }
  • Set the CallBack
    /// Assume this is the isntantiated `Connection` object
    /// TIP:
    /// If it a Globaly Instantiated Object,
    /// 'cnx' 's value equals Connection.get()
    /// or use Connection.get() directly
    Connection cnx;
    ...
    cnx.SetOnException(OnExceptionCallBack);
    ...

Method 2:

  • Define the callback and Set it directly
    ...
    cnx.SetOnException(
    (Exception ex) => {
    ...
    /// The Callback Content
    ...
    }
    );
    ...

OnSNFFail

When is it Called?: This Event will be raised when SNF Protocol has failed the initial handshake
Type of CallBack: SimpleCB
How to Set: SetOnSNFFail(SimpleCB)
Method 1:

  • Define the callback
    void OnSNFFailCallBack() {
    ...
    /// The Callback Content
    ...
    }
  • Set the CallBack
    /// Assume this is the isntantiated `Connection` object
    /// TIP:
    /// If it a Globaly Instantiated Object,
    /// 'cnx' 's value equals Connection.get()
    /// or use Connection.get() directly
    Connection cnx;
    ...
    cnx.SetOnSNFFail(OnSNFFailCallBack);
    ...

Method 2:

  • Define the callback and Set it directly
    ...
    cnx.SetOnSNFFail(
    () => {
    ...
    /// The Callback Content
    ...
    }
    );
    ...

OnSocketFail

When is it Called?: This Event will be raised when the Socket Connection between the client and the Server has raised a SocketException
Type of CallBack: SocketExceptionCB
How to Set: SetOnSocketFail(SocketExceptionCB)
Method 1:

  • Define the callback
    void OnSocketFailCallBack(SocketException ex) {
    ...
    /// The Callback Content
    ...
    }
  • Set the CallBack
    /// Assume this is the isntantiated `Connection` object
    /// TIP:
    /// If it a Globaly Instantiated Object,
    /// 'cnx' 's value equals Connection.get()
    /// or use Connection.get() directly
    Connection cnx;
    ...
    cnx.SetOnSocketFail(OnSocketFailCallBack);
    ...

Method 2:

  • Define the callback and Set it directly
    ...
    cnx.SetOnSNFFail(
    (SocketException ex) => {
    ...
    /// The Callback Content
    ...
    }
    );
    ...

OnTimeout

When is it Called?: This Event will be raised when the Connection between the client and the Server has exceeded the timeout limit set by AwaitConnection(..)
Type of CallBack: SimpleCB
How to Set: SetOnTimeout(SimpleCB)
Method 1:

  • Define the callback
    void OnSocketFailCallBack(SocketException ex) {
    ...
    /// The Callback Content
    ...
    }
  • Set the CallBack
    /// Assume this is the isntantiated `Connection` object
    /// TIP:
    /// If it a Globaly Instantiated Object,
    /// 'cnx' 's value equals Connection.get()
    /// or use Connection.get() directly
    Connection cnx;
    ...
    cnx.SetOnSocketFail(OnSocketFailCallBack);
    ...

Method 2:

  • Define the callback and Set it directly
    ...
    cnx.SetOnSNFFail(
    (SocketException ex) => {
    ...
    /// The Callback Content
    ...
    }
    );
    ...

Connect

To Connect is pretty Simple you, just call Connect

Note
Always configure the Connection and the event Callback before calling Connect
Warning
Connect May Return null so be Aware
...
cnx.Connect();
...

Wait for the Connection

To Connect is pretty Simple you, just call AwaitConnection(int) Which Counts in Miliseconds AwaitConnection(TimeSpan) that uses TimeSpan . I will only give an example of the former

Warning
Always wait for the connection after calling Connect
...
/// Timeout of 5 Seconds
cnx.AwaitConenction(5000);
...

Send Requests

Remarks
Follow This tutorial to know how to generate your Request object

Assuming you have instantiated a new Request Object and Set it properly, we can send it according to your use case

Note
Preferably Always Send after the Connection Instance has Connected (eg isConnected returns true )

In case of a non-Global Instance

For this case (Assuming cnx is your Connection Instance and that Rqst is your Request instance that you want to send ) you can use Send(Request)

...
cnx.Send(Rqst);
...

In case of a Global Instance

For this case you can use the same Method as the In case of a non-Global Instance( Method 1 ) or the Function Specefic to Global Instances (Method 2) (Assuming that Rqst is your Request instance that you want to Send )
Method 1 Using Send(Request)

...
Connection cnx = Connection.get();
cnx.Send(Rqst)
/// Or
Connection.get().Send(Rqst);
...

Method 2 Using InstanceSend(Request)

...
Connection.InstanceSend(Rqst);
...

Practical Example

In this Example I'm gonna create a Console that created a Global Connection instance that connects into a Server Hosted in the same machine on Port 9114

using SNFClient;
namespace Example
{
public class Program
{
public static void Main(string[] args)
{
/// Always Initialize OPCode.Base before anything
/// Instanstiate a Global instance
/// Set the Host
.SetHost("localhost")
/// Set the Port
.SetPort(9114)
/// Set the OnConnection Event Callback
() => {
Console.WriteLine("Connected");
}
)
/// Set the OnSocketFail Event Callback
.SetOnSocketFail(
(ex) => {
Console.WriteLine("SocketFailed: " + ex.ToString());
}
)
/// Set the OnSNFFail Event Callback
.SetOnSNFFail(
() => {
Console.WriteLine("SNF HandShake Failed");
}
)
/// Set the OnException Event Callback
.SetOnException(
(ex) =>
{
Console.WriteLine("Unknown Exception" + ex.ToString());
}
)
/// Attempt To Connect
.Connect()?
/// if Connect Returned the Connection Instance
/// Properly It will wait until it Connects or 10s Passes
.AwaitConnection(10000);
...
}
}
}
Objects of this class are what controls and handles Connections to the Host.
Definition Connection.cs:14
Connection SetPort(int Port)
Sets the connection host's port for this instance.
Definition Connection.cs:250
Connection SetOnConnection(SimpleCB OnConnect)
Sets The callbackto be called Upon Connection.
Definition Connection.cs:268
Connection SetHost(string Host)
Set's the connection host for this instance.
Definition Connection.cs:230
Connection AwaitConnection(TimeSpan timeout)
Block Until the instance is Connected.
Definition Connection.cs:361
static Connection Instantiate(string host, int Port)
Instantiates a new Global Connection Instance.
Definition Connection.cs:45
This Class Defined THe Base OPCode Structure for Basic SNF Functioning.
Definition OPCode.cs:749
static void Initialize()
Initializes OPCode.Base.
Definition OPCode.cs:824
Objects of this class Define the action to do to the host.
Definition OPCode.cs:11
Definition Callbacks.cs:5

OPCodes

Setting up new OPCodes

Warning
Although you can define new opcode, the current version of SNF Server doesnt let you make use of user-defined Commands as of 0.0.1-alpha

One thing to note is that you do not define whole OPCodes but you define each part of the OPCode one by one with a String definitoin of each Member, which means you define the Category, then the Sub-Category and so on

Warning
Never Add/Modify Base OPCode Members!
Note
Every OPCode Member that is of Command Rank, it will have always by default a Detail 0 called DET_UNDETAILED

Example Let's Say we have to define this hierachy

  • Category 1 its definition is "Category for Vehicle Commands"
    • Sub Category 1 "Subcategory for Vehicle Screen Commands"
      • Command 1 "Change Vehicle Screen Bightness Command"
        • Detail 1 "Maximum Brightness"
        • Detail 2 "Minimum Brightness"
      • Command 2 "Toggle Vehicle Screen Command"
using SNFClient;
/*
* Used Instead of writing OPCode.Base and OPCode.Member Multiple Times
*/
using static SNFClient.OPCode;
namespace Example
{
public class Program
{
public static void Main(string[] args)
{
/// Always Initialize OPCode.Base before anything
Base.Initialize();
/// Define The Category
/// Always Start Categories from 0x01 as 0x00
/// is reserved for the Base OPCode Category
Member Category = new Member(
/// Rank Must be appropriate to where you
/// are going to insert it in
Member.Rank.Category,
/// The byte that represents this Category
0x01,
/// String Definition for this OPCode Command
/// *Not Mandatory, you can put "" fine
"Category for Vehicle Commands"
);
/// Insert it Into the OPCode Structure
Member.AddCategory( Category );
/// Define The subcategory,
/// here you can start from 0x00
Member SubCategory1 = new Member(
Member.Rank.SubCategory,
0x00,
"Subcategory for Vehicle Screen Commands"
);
/// Insert the Subcategory into
/// the Category we defined earlier
Member.AddSubCategory(
Category,
SubCategory1
);
/// Define the Command 1
Member Command1 = new Member(
Member.Rank.Command,
0x00,
"Change Vehicle Screen Bightness Command"
);
/// Define the details and Since we won't need to add
/// anything beneith the details we can just add
/// them Directly to the command
/// Note Details Start with 0x00 as there is by default
/// detail with value 0x00 to each command
Member.AddDetail(
Command1,
new Member(
Member.Rank.Detail,
0x01,
"Maximum Brightness"
)
);
Member.AddDetail(
Command1,
new Member(
Member.Rank.Detail,
0x02,
"Minimum Brightness"
)
);
/// Define the Command 2 and add it directly
Member.AddCommand(
SubCategory1,
new Member(
Member.Rank.Command,
0x01,
"Toggle Vehicle Screen Command"
)
);
...
}
}
}
Warning
I did not check the returns of functions and their exception for the sake of simplicity, See the returns of each function and their exceptions

Generating an OPCode

OPCodes are a Set of bytes who's sole purpose is defining the action to perform on the server side which are mandaroty to generate new Request Instances

Generating a Base OPCode

Note
You can Generate Base OPCodes using the same Method as Generating a User-defined OPCode but the The defining Byte for Base Category and Base Subcategory is 0x00

For Base OPCodes there is 2 Methods (Each having 2 Overloads)

1- Getting any base Command

/*Overload 1: In case you want to Include a detail */
/// Defining byte for the base command
/// Defining byte for the base Command
);
/*Overload 2: In case you want an undetailed OPCode */
/// Defining byte for the base command
);
static OPCode get(byte Command)
Gets an OPCode using a Base Command without any detail.
static byte CMD_SNF_VER
When client requests SNF version of the Server.
Definition OPCode.cs:780
static byte DET_UNDETAILED
Default Detail for every Command.
Definition OPCode.cs:762

2- Getting the Invalid Command

/*Overload 1: In case you want to Include a detail */
/// A Defining byte for an Invalid Command Detail
)
/*Overload 2: In case you want an undetailed 'Invalid' OPCode */
static byte DET_INVALID_ERROR_PROTOCOL
Protocol used is invalid.
Definition OPCode.cs:806
static OPCode getInvalid()
Gets an OPCode using a 'Invalid' Command without any detail.

Generating a User-defined OPCode

There is 2 Methods To Generate an OPCode

1- Using The defining byte of it's Members

...
/// Never Forget to Initialize the Base OPCodes
/// once before doing anything
OPCode.Base.Initialize();
...
OPCode opcode = OPCode.get(
/// Defining Byte for the Category
0x01,
/// Defining Byte for the Subcategory
0x00,
/// Defining Byte for the Command
0x02,
/// Defining Byte for the Command's Detail
/// OPTIONAL
0x05
);
static OPCode get(byte Category, byte SubCategory, byte Command, byte Detail=0)
Generates an OPCode Instnce Depending on the Registred Parameters.
Definition OPCode.cs:56

2- Using OPCode.Member Instances of it's Members

See Also:

...
/// Never Forget to Initialized the Base OPCodes
/// once before doing anything
OPCode.Base.Initialize();
...
OPCode.Member Category;
OPCode.Member SubCategory;
OPCode.Member Command;
...
OPCode opcode = OPCode.get(
/// OPCode.Member instance of the Category
Category,
/// Defining Byte for the Subcategory
SubCategory,
/// Defining Byte for the Command
Command,
/// Defining Byte for the Command's Detail
/// OPTIONAL
Detail
);
Objects of this class Defines every OPCode instance.
Definition OPCode.cs:193
Note
If you want Undetailed OPCodes using Method 1 and/or 2 you can put in the OPTIONAL Parameter with a value of 0x00 and/or null respectively, or not write that parameter to begin with

Getting an OPCode Member

In case you want to fetch a Base OPCode Member for some reason, use one of the Following

Note
During all of these Examples below we use this using
using static SNFClient.OPCode;

Getting a Category

In case you want a specefic Category, you must use their defining byte

Member C = Member.getCategory(
/// Category's defining byte
0x00
);

or if you want the base Category

Member C = Base.getCategory();

Getting a Subcategory

In case you want a specefic subcategory, you must use their defining byte and the parent Category's defining byte or the category Member instance.

/* Method 1*/
Member C = Member.getSubcategory(
/// Category's defining byte
0x00,
/// SubCategory's defining byte
0x00
);
/* Method 2*/
Member C = Member.getSubcategory(
/// Category's object instance
Category,
/// SubCategory's defining byte
0x00
);

or if you want the base SubCategory

Member C = Base.getSubCategory();

Getting a Command

In case you want a specefic command, you must use their defining byte and the parent Category and Subcategory's defining Byte or the Subcategory's Member Instance,

/* Method 1*/
Member C = Member.getCommand(
/// Category's defining byte
0x00,
/// SubCategory's defining byte
0x00,
/// The Command's defining byte
0x01
);
/* Method 2*/
Member C = Member.getCommand(
/// SubCategory's Member instance
Subategory,
0x00
);

or if you want a base command

Member C = Base.getCommand(
/// The Command's defining byte
0x01
);

Getting a Command's Detail

In case you want a specefic command's detail, you must use their defining byte and the parent Category, Subcategory and Command's defining byte or the Command's Member Instance,

/* Method 1*/
Member C = Member.getCommand(
/// Category's defining byte
0x00,
/// SubCategory's defining byte
0x00,
/// The Command's defining byte
0x01,
/// The Detail's defining byte
0x01,
);
/* Method 2*/
Member C = Member.getDetail(
/// Command's Member instance
Command,
/// The Detail's defining byte
0x00
);

or if you want a base command's detail

Member C = Base.getDetail(
/// The Command's defining byte
0x01,
/// The Detail's defining byte
0x01
);

Requests

Note
Always makesure your opcodes and the server is up and running and connected before sending any request !

Generating a Request

There is X different overload to create a new Request for different usecases

Generating a Request with just an OPCode and doesnt await a response

Request req = new Request(
<OPCODE Object>
);
"Request" Members are the object that are sent through SNF.Client.Connection
Definition Request.cs:19

Generating a Request with just an OPCode and awaits a response

1- Declare a function and pass it as an argument

eg of a function Declaration

public void NameOfYourCallBack(Request Response)
{
...
///
/// Do Somethings in your callback
///
...
}

and then pass it as an argument upon the creation of the request object

Request req = new Request(
<OPCODE Object>,
NameOfYouCallBack
);

2- Declare the function directly in the arguents eg

Request req = new Request(
<OPCODE Object>,
(Request Response) => {
...
///
/// Do Somethings in your callback
///
...
}
);

Generating a Request with an OPCode, Arguments and doesnt await a response

byte[][] args =
{
// Argument example from a Series of bytes
new byte[] { 0x22, 0x33},
// Argument example from a string
// Note however that you need to add this using
// using System.Text;
Encoding.ASCII.GetBytes("Argument From String"),
.
.
};
Request req = new Request(
<OPCODE Object>,
args
);

Generating a Request with an OPCode, Arguments and awaits a response

and put them in your constructore just like this

Request req = new Request(
<OPCODE Object>,
args,
Callback
);

Generating a Request with a custom UID

You can Set a Custom Request by Defining the byte array that has the length stated in the Variable _UID_LENGTH and pass it as the firest argument in either one of the Cunstructors that allows a Custom UID

Note
All Requests(Except those who have a CustomUID) Will have an auto incrementing Unique UID generated by the generateUID() Function

First generate your UID

byte [] UID = new byte[Request._UID_LENGTH];
..
// Define The value of your UID
..
static int _UID_LENGTH
The length of the UID of each Request "Request".
Definition Request.cs:25

Then if you want a Request that doesnt Await a response, create it like this:

  • See this to know how to get an `OPCODE Object`
  • Declare your arguments in an array of byte[] and then pass it as argument when creating the object, just like **here**
    Note
    If you dont have an argument then put null instead of args
    Request req = new Request(
    UID,
    <OPCODE Object>,
    args
    );
    and if you want a Request that Awaits a response, create it like this:
  • Delclare your Response Callabck just like **here**
Request req = new Request(
UID,
<OPCODE Object>,
args,
Callback
);

Making use of your Request

After you have genrated the Request object to your needs, you can send it Using this tutorial