www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Class, constructor and inherance.

reply holo <holosian gmail.com> writes:
Hello

I'm trying to write my first class. I want to use it as module 
and build anothers on top of it. I read that default functions 
attributes are not inherited. Is it that same for constructor? 
This is how my class (not finished) is looking right now:

class credential
{
	auto accessKey = environment.get["AWS_ACCESS_KEY"];
	auto secretKey = environment.get["AWS_SECRET_KEY"];
}

class sigv4 : credential
{
	public:
		string method;
		string service;
		string host;
		string region;
		string endpoint;
		string request_parameters;
		string payload;

	private:
		const algorithm = "AWS4-HMAC-SHA256";

		auto currentClock = Clock.currTime(UTC());
		auto currentDate = cast(Date)currentClock;
		auto curDateStr = currentDate.toISOString;
		auto currentTime = cast(TimeOfDay)currentClock;
		auto curTimeStr = currentTime.toISOString;
		auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";

		auto hmac_sha256(ubyte[] key, ubyte[] msg)
		{
			auto hmac = hmac!SHA256(key);
			hmac.put(msg);
			auto digest = hmac.finish;

			return digest;
		}

		auto getSignatureKey(string key, string dateStamp, string 
regionName, string serviceName)
		{
			ubyte[] kString = cast(ubyte[])("AWS4" ~ key);
			auto kDate = sign(kString, cast(ubyte[])dateStamp);
			auto kRegion = sign(kDate, cast(ubyte[])regionName);
			auto kService = sign(kRegion,  cast(ubyte[])serviceName);
			auto kSigning = sign(kService, cast(ubyte[])"aws4_request");

			return kSigning;
		}

		auto getCanonicalRequest(string canonicalURI, string 
canonicalQueryString, string canonicalHeaderString, string 
signedHeaders)
		{
			string payloadHash = sha256Of("").toHexString.toLower;
			string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" 
~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ 
signedHeaders ~ "\n" ~ payloadHash;
		}

		this()
		{
			
		}
}

I need to set all variables by defaults values from "public" and 
all needed by function "getCanonicalRequest". But if i will use 
that class to build another should i set defaults again? If yes 
is there some solution for it?

//holo
Oct 11 2015
next sibling parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 12/10/15 3:14 PM, holo wrote:
 Hello

 I'm trying to write my first class. I want to use it as module and build
 anothers on top of it. I read that default functions attributes are not
 inherited. Is it that same for constructor? This is how my class (not
 finished) is looking right now:

 class credential
 {
      auto accessKey = environment.get["AWS_ACCESS_KEY"];
      auto secretKey = environment.get["AWS_SECRET_KEY"];
 }

 class sigv4 : credential
 {
      public:
          string method;
          string service;
          string host;
          string region;
          string endpoint;
          string request_parameters;
          string payload;

      private:
          const algorithm = "AWS4-HMAC-SHA256";

          auto currentClock = Clock.currTime(UTC());
          auto currentDate = cast(Date)currentClock;
          auto curDateStr = currentDate.toISOString;
          auto currentTime = cast(TimeOfDay)currentClock;
          auto curTimeStr = currentTime.toISOString;
          auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";

          auto hmac_sha256(ubyte[] key, ubyte[] msg)
          {
              auto hmac = hmac!SHA256(key);
              hmac.put(msg);
              auto digest = hmac.finish;

              return digest;
          }

          auto getSignatureKey(string key, string dateStamp, string
 regionName, string serviceName)
          {
              ubyte[] kString = cast(ubyte[])("AWS4" ~ key);
              auto kDate = sign(kString, cast(ubyte[])dateStamp);
              auto kRegion = sign(kDate, cast(ubyte[])regionName);
              auto kService = sign(kRegion,  cast(ubyte[])serviceName);
              auto kSigning = sign(kService, cast(ubyte[])"aws4_request");

              return kSigning;
          }

          auto getCanonicalRequest(string canonicalURI, string
 canonicalQueryString, string canonicalHeaderString, string signedHeaders)
          {
              string payloadHash = sha256Of("").toHexString.toLower;
              string canonicalRequest = method ~ "\n" ~ canonicalURI ~
 "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~
 signedHeaders ~ "\n" ~ payloadHash;
          }

          this()
          {

          }
 }

 I need to set all variables by defaults values from "public" and all
 needed by function "getCanonicalRequest". But if i will use that class
 to build another should i set defaults again? If yes is there some
 solution for it?

 //holo
By the looks, I'm guessing you do not have much experience when it comes to OOP. I think you are wanting something a bit closer to: import std.typecons : tuple, TypeTuple; interface Credential { string encode(....); } class SigV4 : Credential { this(....) { .... } string encode(....) { } private: .... } TypeTuple!(string, string) AWSKeys() { import std.process; return tuple(environment.get("AWS_ACCESS_KEY"), environment.get("AWS_SECRET_KEY")); }
Oct 11 2015
parent reply holo <holosian gmail.com> writes:
 By the looks, I'm guessing you do not have much experience when 
 it comes to OOP.

 I think you are wanting something a bit closer to:

 import std.typecons : tuple, TypeTuple;

 interface Credential {
 	string encode(....);
 }

 class SigV4 : Credential {
 	this(....) {
 		....	
 	}
 	
 	string encode(....) {
 		
 	}
 	
 	private:
 	....
 }


 TypeTuple!(string, string) AWSKeys() {
     import std.process;
     return tuple(environment.get("AWS_ACCESS_KEY"), 
 environment.get("AWS_SECRET_KEY"));
 }
Yes you guessed good, i don't have any experience with OOP (i have some experience with C - simple AVR projects and tons of bash scripts) this is my first such kind of language which I'm trying to learn. For beginning I'm trying to avoid advanced things like templates or from your example touples (Touples looks for me like some kind of array but every cell can be different type, am i right? Eg tuple from your example is that same what string[2] var?) i was reading about it but for now i can't understand what they are and for what they are useful. I'm trying to learn on the examples and honestly i'm not understand how that TypeTuple is resolving my problem with default values for classes? Second thing that interfaces, are they needed? Without it you can write same function just compilator wont be screaming for it lack.
Oct 11 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 12/10/15 4:13 PM, holo wrote:
 By the looks, I'm guessing you do not have much experience when it
 comes to OOP.

 I think you are wanting something a bit closer to:

 import std.typecons : tuple, TypeTuple;

 interface Credential {
     string encode(....);
 }

 class SigV4 : Credential {
     this(....) {
         ....
     }

     string encode(....) {

     }

     private:
     ....
 }


 TypeTuple!(string, string) AWSKeys() {
     import std.process;
     return tuple(environment.get("AWS_ACCESS_KEY"),
 environment.get("AWS_SECRET_KEY"));
 }
Yes you guessed good, i don't have any experience with OOP (i have some experience with C - simple AVR projects and tons of bash scripts) this is my first such kind of language which I'm trying to learn. For beginning I'm trying to avoid advanced things like templates or from your example touples (Touples looks for me like some kind of array but every cell can be different type, am i right? Eg tuple from your example is that same what string[2] var?) i was reading about it but for now i can't understand what they are and for what they are useful.
Templates are just compile time arguments :) Mostly used for types and constants. Simple concept, just don't get too scared off by what is possible with template if's. Tuples are pretty simple. It's basically just a struct. They are not arrays. But they do have a similar behavior. With opIndex overloading. You could for example use: struct AWSKeys { string access, secret; static AWSKeys get() { import std.process : environment; return AWSKeys(environment.get("AWS_ACCESS_KEY"), environment.get("AWS_SECRET_KEY")); } } Instead of that free function and tuples.
 I'm trying to learn on the examples and honestly i'm not understand how
 that TypeTuple is resolving my problem with default values for classes?
It wasn't meant to, I got started rewriting the example code you gave, and ehh gave up after the basics of the class/interface.
 Second thing that interfaces, are they needed? Without it you can write
 same function just compilator wont be screaming for it lack.
An interface basically says, this object adheres to these methods. When dealing with possibly changing authentication/communication protocols you would have the interface being how you get what to send, but the actual implementation being whatever you want to be using. Keep in mind, this class which handles creating the messages to the remote api's is not per message sent. It is a global communication mechanism. If you didn't need to make it easily changeable I would say not even bother with OOP at all. I would recommend coming on to #d on Freenode, we can help you better there.
Oct 11 2015
parent holo <holosian gmail.com> writes:
On Monday, 12 October 2015 at 03:29:12 UTC, Rikki Cattermole 
wrote:
 On 12/10/15 4:13 PM, holo wrote:
 By the looks, I'm guessing you do not have much experience 
 when it
 comes to OOP.

 I think you are wanting something a bit closer to:

 import std.typecons : tuple, TypeTuple;

 interface Credential {
     string encode(....);
 }

 class SigV4 : Credential {
     this(....) {
         ....
     }

     string encode(....) {

     }

     private:
     ....
 }


 TypeTuple!(string, string) AWSKeys() {
     import std.process;
     return tuple(environment.get("AWS_ACCESS_KEY"),
 environment.get("AWS_SECRET_KEY"));
 }
Yes you guessed good, i don't have any experience with OOP (i have some experience with C - simple AVR projects and tons of bash scripts) this is my first such kind of language which I'm trying to learn. For beginning I'm trying to avoid advanced things like templates or from your example touples (Touples looks for me like some kind of array but every cell can be different type, am i right? Eg tuple from your example is that same what string[2] var?) i was reading about it but for now i can't understand what they are and for what they are useful.
Templates are just compile time arguments :) Mostly used for types and constants. Simple concept, just don't get too scared off by what is possible with template if's. Tuples are pretty simple. It's basically just a struct. They are not arrays. But they do have a similar behavior. With opIndex overloading. You could for example use: struct AWSKeys { string access, secret; static AWSKeys get() { import std.process : environment; return AWSKeys(environment.get("AWS_ACCESS_KEY"), environment.get("AWS_SECRET_KEY")); } } Instead of that free function and tuples.
 I'm trying to learn on the examples and honestly i'm not 
 understand how
 that TypeTuple is resolving my problem with default values for 
 classes?
It wasn't meant to, I got started rewriting the example code you gave, and ehh gave up after the basics of the class/interface.
 Second thing that interfaces, are they needed? Without it you 
 can write
 same function just compilator wont be screaming for it lack.
An interface basically says, this object adheres to these methods. When dealing with possibly changing authentication/communication protocols you would have the interface being how you get what to send, but the actual implementation being whatever you want to be using. Keep in mind, this class which handles creating the messages to the remote api's is not per message sent. It is a global communication mechanism. If you didn't need to make it easily changeable I would say not even bother with OOP at all. I would recommend coming on to #d on Freenode, we can help you better there.
Thank you for explanation tomorrow (today) will back to it and read it carefully, will join IRC too. //almost 6:00AM here :)
Oct 11 2015
prev sibling parent reply Meta <jared771 gmail.com> writes:
On Monday, 12 October 2015 at 02:14:35 UTC, holo wrote:
 class credential
 {
 	auto accessKey = environment.get["AWS_ACCESS_KEY"];
 	auto secretKey = environment.get["AWS_SECRET_KEY"];
 }

 class sigv4 : credential
 {
 	private:
 		const algorithm = "AWS4-HMAC-SHA256";

 		auto currentClock = Clock.currTime(UTC());
 		auto currentDate = cast(Date)currentClock;
 		auto curDateStr = currentDate.toISOString;
 		auto currentTime = cast(TimeOfDay)currentClock;
 		auto curTimeStr = currentTime.toISOString;
 		auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";
 }
You should set these in the constructor rather than in the class body (the only one that's okay to intialize here is `algorithm`, as it's a const string).
Oct 11 2015
parent reply holo <holosian gmail.com> writes:
On Monday, 12 October 2015 at 02:30:43 UTC, Meta wrote:
 On Monday, 12 October 2015 at 02:14:35 UTC, holo wrote:
 class credential
 {
 	auto accessKey = environment.get["AWS_ACCESS_KEY"];
 	auto secretKey = environment.get["AWS_SECRET_KEY"];
 }

 class sigv4 : credential
 {
 	private:
 		const algorithm = "AWS4-HMAC-SHA256";

 		auto currentClock = Clock.currTime(UTC());
 		auto currentDate = cast(Date)currentClock;
 		auto curDateStr = currentDate.toISOString;
 		auto currentTime = cast(TimeOfDay)currentClock;
 		auto curTimeStr = currentTime.toISOString;
 		auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";
 }
You should set these in the constructor rather than in the class body (the only one that's okay to intialize here is `algorithm`, as it's a const string).
I rewrite it to something like this: module sigawsv4 import std.stdio, std.process; import std.digest.sha, std.digest.hmac; import std.string; import std.conv; import std.datetime; import std.net.curl; class credential { auto accessKey = environment.get["AWS_ACCESS_KEY"]; auto secretKey = environment.get["AWS_SECRET_KEY"]; } class sigv4 : credential { this(string URI = "/", string queryStr = "Action=DescribeInstances&Version=2013-10-15", string headerStr = "host:" ~ host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n", string headers = "host;x-amz-date") { auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; string canonicalURI = URI; string canonicalQueryString = queryStr; string canonicalHeaderString = headerStr; string signedHeaders = headers; } public: string method; string service; string host; string region; string endpoint; string request_parameters; string payload; private: const algorithm = "AWS4-HMAC-SHA256"; auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; auto hmac_sha256(ubyte[] key, ubyte[] msg) { auto hmac = hmac!SHA256(key); hmac.put(msg); auto digest = hmac.finish; return digest; } auto getSignatureKey(string key, string dateStamp, string regionName, string serviceName) { ubyte[] kString = cast(ubyte[])("AWS4" ~ key); auto kDate = sign(kString, cast(ubyte[])dateStamp); auto kRegion = sign(kDate, cast(ubyte[])regionName); auto kService = sign(kRegion, cast(ubyte[])serviceName); auto kSigning = sign(kService, cast(ubyte[])"aws4_request"); return kSigning; } auto getCanonicalRequest(string canonicalURI, string canonicalQueryString, string canonicalHeaderString, string signedHeaders) { string payloadHash = sha256Of("").toHexString.toLower; string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ signedHeaders ~ "\n" ~ payloadHash; } } Is right now that constructor ok? My question was too if now i will inherit that class, will that default values be in child class available?
Oct 11 2015
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/11/2015 08:26 PM, holo wrote:
 On Monday, 12 October 2015 at 02:30:43 UTC, Meta wrote:
 On Monday, 12 October 2015 at 02:14:35 UTC, holo wrote:
 class credential
 {
     auto accessKey = environment.get["AWS_ACCESS_KEY"];
     auto secretKey = environment.get["AWS_SECRET_KEY"];
 }

 class sigv4 : credential
 {
     private:
         const algorithm = "AWS4-HMAC-SHA256";

         auto currentClock = Clock.currTime(UTC());
         auto currentDate = cast(Date)currentClock;
         auto curDateStr = currentDate.toISOString;
         auto currentTime = cast(TimeOfDay)currentClock;
         auto curTimeStr = currentTime.toISOString;
         auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";
 }
You should set these in the constructor rather than in the class body (the only one that's okay to intialize here is `algorithm`, as it's a const string).
I rewrite it to something like this:
What Meta is saying is that the expressions used for default values class bodies must be known at compile time. For example, you cannot get current time at run time. Besides, if it did work, there is the question of "should every sigv4 object get the same default value currentClock, or should every object get their own time?"
 class credential
 {
      auto accessKey = environment.get["AWS_ACCESS_KEY"];
      auto secretKey = environment.get["AWS_SECRET_KEY"];
 }
As mentioned, that cannot compile.
 class sigv4 : credential
 {
      this(string URI = "/", string queryStr =
 "Action=DescribeInstances&Version=2013-10-15", string headerStr =
 "host:" ~ host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n", string headers
 = "host;x-amz-date")
      {
          auto currentClock = Clock.currTime(UTC());
That is a known error, which is usually caused by copy-paste: Because you used 'auot' on the left-hand side, that is the definition of a local variable. 'currentClock' above is not the member of this class. It is adviced to use fully qualify members with this. in constructors: this.currentClock = // ...
          auto currentClock = Clock.currTime(UTC());
Just define the members without a default value; they will be initialized in the constructor: SysTime currentDate;
 My question was too if now i will inherit that class, will that default
 values be in child class available?
Yes, every variable will obey its default value. When in doubt, test with simple examples. :) class Base { int i = 42; } class Derived : Base { int j; this() { this.j = 100; } } void main() { auto d = new Derived(); assert(d.i == 42); // set by default value assert(d.j == 100); // set in the constructor } Ali
Oct 11 2015
next sibling parent reply anonymous <anonymous example.com> writes:
On Monday 12 October 2015 07:28, Ali Çehreli wrote:

 For example, you cannot get current time at run time.
I think you mean compile time here.
Oct 11 2015
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/11/2015 10:35 PM, anonymous wrote:
 On Monday 12 October 2015 07:28, Ali Çehreli wrote:

 For example, you cannot get current time at run time.
I think you mean compile time here.
Thanks. :) Ali
Oct 11 2015
prev sibling parent reply holo <holosian gmail.com> writes:
 Rikki:

 If you didn't need to make it easily changeable I would say not 
 even bother with OOP at all.
Basically that what i had was enough for me and on top of that i could build my app. It need to just periodically check for new instances and if they are started or stopped and count "up and running time" for billing purpose. But like i said i want to learn programming in D and basically OOP too so i want to make it "proper way". BTW: i think right now i understand what tuple is, but still don't know for what to duplicate struct functionalities :). Those Templates still don't understand but i hope that will came naturally with time and practice. eg.. they are very similar to normal functions but you can call it with types not only attributes.. strange ;) I red yours advises and try to create according to it my own first class. I moved time functions and variables to method "go" they need to be current as possible when im sending request, if wont authorization could not pass.. so i think they shouldn't be in constructor. I moved some other variables too, and created interface. From all that things came out such monster which is working and doing its job :) module sigawsv4; import std.stdio, std.process; import std.digest.sha, std.digest.hmac; import std.string; import std.conv; import std.datetime; import std.net.curl; interface credential { int go(); } class sigv4 : credential { //could be changed to take some structure as parameter instead of such ammount of attributes this(string methodStr = "GET", string serviceStr = "ec2", string hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", string endpointStr = "https://ec2.amazonaws.com", string payloadStr = "", string parmStr = "Action=DescribeInstances&Version=2013-10-15") { this.method = methodStr; this.service = serviceStr; this.host = hostStr; this.region = regionStr; this.endpoint = endpointStr; this.payload = payloadStr; this.request_parameters = parmStr; this.accessKey = environment.get("AWS_ACCESS_KEY"); this.secretKey = environment.get("AWS_SECRET_KEY"); } public: string method; string service; string host; string region; string endpoint; string payload; string request_parameters; int go() { //time need to be set when we are sending request not before auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; canonicalURI = "/"; canonicalQueryString = request_parameters; canonicalHeadersString = "host:" ~ this.host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n"; signedHeaders = "host;x-amz-date"; auto canonicalRequest = getCanonicalRequest(canonicalURI, canonicalQueryString, canonicalHeadersString, signedHeaders); string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~ service ~ "/" ~ "aws4_request"; string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~ credentialScope ~ "\n" ~ sha256Of(canonicalRequest).toHexString.toLower; auto signingKey = getSignatureKey(secretKey, curDateStr, region, service); string signature = hmac!SHA256(stringToSign.representation, signingKey).toHexString.toLower; string authorizationHeader = algorithm ~ " " ~ "Credential=" ~ accessKey ~ "/" ~ credentialScope ~ ", " ~ "SignedHeaders=" ~ signedHeaders ~ ", " ~ "Signature=" ~ signature; auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString); client.method = HTTP.Method.get; client.addRequestHeader("x-amz-date", xamztime); client.addRequestHeader("Authorization", authorizationHeader); auto content = client.perform(); return content; } private: const algorithm = "AWS4-HMAC-SHA256"; string accessKey; string secretKey; string currentClock; string currentDate; string curDateStr; string currentTime; string curTimeStr; string xamztime; string canonicalURI; string canonicalQueryString; string canonicalHeadersString; string signedHeaders; alias sign = hmac!SHA256; auto getSignatureKey(string key, string dateStamp, string regionName, string serviceName) { auto kString = ("AWS4" ~ key).representation; auto kDate = sign(dateStamp.representation, kString); auto kRegion = sign(regionName.representation, kDate); auto kService = sign(serviceName.representation, kRegion); auto kSigning = sign("aws4_request".representation, kService); return kSigning; } auto getCanonicalRequest(string canonicalURI, string canonicalQueryString, string canonicalHeadersString, string signedHeaders) { string payloadHash = sha256Of(payload).toHexString.toLower; string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ signedHeaders ~ "\n" ~ payloadHash; return canonicalRequest; } } void main() { sigv4 sig = new sigv4(); writeln(sig.go()); } I want to ask you for advises what i could do with that class to make it looks more "pro"/elegant/build in "proper way". Probably there are lot of mistakes which all beginners are doing. eg.: Did i use interface correctly?
Oct 12 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 13/10/15 5:56 AM, holo wrote:
  Rikki:

 If you didn't need to make it easily changeable I would say not even
 bother with OOP at all.
Basically that what i had was enough for me and on top of that i could build my app. It need to just periodically check for new instances and if they are started or stopped and count "up and running time" for billing purpose. But like i said i want to learn programming in D and basically OOP too so i want to make it "proper way". BTW: i think right now i understand what tuple is, but still don't know for what to duplicate struct functionalities :). Those Templates still don't understand but i hope that will came naturally with time and practice. eg.. they are very similar to normal functions but you can call it with types not only attributes.. strange ;) I red yours advises and try to create according to it my own first class. I moved time functions and variables to method "go" they need to be current as possible when im sending request, if wont authorization could not pass.. so i think they shouldn't be in constructor. I moved some other variables too, and created interface. From all that things came out such monster which is working and doing its job :) module sigawsv4; import std.stdio, std.process; import std.digest.sha, std.digest.hmac; import std.string; import std.conv; import std.datetime; import std.net.curl; interface credential { int go(); } class sigv4 : credential { //could be changed to take some structure as parameter instead of such ammount of attributes this(string methodStr = "GET", string serviceStr = "ec2", string hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", string endpointStr = "https://ec2.amazonaws.com", string payloadStr = "", string parmStr = "Action=DescribeInstances&Version=2013-10-15") { this.method = methodStr; this.service = serviceStr; this.host = hostStr; this.region = regionStr; this.endpoint = endpointStr; this.payload = payloadStr; this.request_parameters = parmStr; this.accessKey = environment.get("AWS_ACCESS_KEY"); this.secretKey = environment.get("AWS_SECRET_KEY"); } public: string method; string service; string host; string region; string endpoint; string payload; string request_parameters; int go() { //time need to be set when we are sending request not before auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; canonicalURI = "/"; canonicalQueryString = request_parameters; canonicalHeadersString = "host:" ~ this.host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n"; signedHeaders = "host;x-amz-date"; auto canonicalRequest = getCanonicalRequest(canonicalURI, canonicalQueryString, canonicalHeadersString, signedHeaders); string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~ service ~ "/" ~ "aws4_request"; string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~ credentialScope ~ "\n" ~ sha256Of(canonicalRequest).toHexString.toLower; auto signingKey = getSignatureKey(secretKey, curDateStr, region, service); string signature = hmac!SHA256(stringToSign.representation, signingKey).toHexString.toLower; string authorizationHeader = algorithm ~ " " ~ "Credential=" ~ accessKey ~ "/" ~ credentialScope ~ ", " ~ "SignedHeaders=" ~ signedHeaders ~ ", " ~ "Signature=" ~ signature; auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString); client.method = HTTP.Method.get; client.addRequestHeader("x-amz-date", xamztime); client.addRequestHeader("Authorization", authorizationHeader); auto content = client.perform(); return content; } private: const algorithm = "AWS4-HMAC-SHA256"; string accessKey; string secretKey; string currentClock; string currentDate; string curDateStr; string currentTime; string curTimeStr; string xamztime; string canonicalURI; string canonicalQueryString; string canonicalHeadersString; string signedHeaders; alias sign = hmac!SHA256; auto getSignatureKey(string key, string dateStamp, string regionName, string serviceName) { auto kString = ("AWS4" ~ key).representation; auto kDate = sign(dateStamp.representation, kString); auto kRegion = sign(regionName.representation, kDate); auto kService = sign(serviceName.representation, kRegion); auto kSigning = sign("aws4_request".representation, kService); return kSigning; } auto getCanonicalRequest(string canonicalURI, string canonicalQueryString, string canonicalHeadersString, string signedHeaders) { string payloadHash = sha256Of(payload).toHexString.toLower; string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ signedHeaders ~ "\n" ~ payloadHash; return canonicalRequest; } } void main() { sigv4 sig = new sigv4(); writeln(sig.go()); } I want to ask you for advises what i could do with that class to make it looks more "pro"/elegant/build in "proper way". Probably there are lot of mistakes which all beginners are doing. eg.: Did i use interface correctly?
You are reasonably close: credential sig = new sigv4(); Although go is not really doing what I expect it to do. To me go should be dedicated to performing a request given what ever you need for just that request. The class sigv4 is your global state aka what doesn't change per request. To me what go returns is whatever is the common denominator for what you need from it is. From what I can see, you probably want go to take the payload as an argument. That way you can reuse an instance of sigv4. Which is the ultimate goal.
Oct 12 2015
parent reply holo <holosian gmail.com> writes:
On Tuesday, 13 October 2015 at 02:03:46 UTC, Rikki Cattermole 
wrote:
 On 13/10/15 5:56 AM, holo wrote:
  Rikki:

 If you didn't need to make it easily changeable I would say 
 not even
 bother with OOP at all.
Basically that what i had was enough for me and on top of that i could build my app. It need to just periodically check for new instances and if they are started or stopped and count "up and running time" for billing purpose. But like i said i want to learn programming in D and basically OOP too so i want to make it "proper way". BTW: i think right now i understand what tuple is, but still don't know for what to duplicate struct functionalities :). Those Templates still don't understand but i hope that will came naturally with time and practice. eg.. they are very similar to normal functions but you can call it with types not only attributes.. strange ;) I red yours advises and try to create according to it my own first class. I moved time functions and variables to method "go" they need to be current as possible when im sending request, if wont authorization could not pass.. so i think they shouldn't be in constructor. I moved some other variables too, and created interface. From all that things came out such monster which is working and doing its job :) module sigawsv4; import std.stdio, std.process; import std.digest.sha, std.digest.hmac; import std.string; import std.conv; import std.datetime; import std.net.curl; interface credential { int go(); } class sigv4 : credential { //could be changed to take some structure as parameter instead of such ammount of attributes this(string methodStr = "GET", string serviceStr = "ec2", string hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", string endpointStr = "https://ec2.amazonaws.com", string payloadStr = "", string parmStr = "Action=DescribeInstances&Version=2013-10-15") { this.method = methodStr; this.service = serviceStr; this.host = hostStr; this.region = regionStr; this.endpoint = endpointStr; this.payload = payloadStr; this.request_parameters = parmStr; this.accessKey = environment.get("AWS_ACCESS_KEY"); this.secretKey = environment.get("AWS_SECRET_KEY"); } public: string method; string service; string host; string region; string endpoint; string payload; string request_parameters; int go() { //time need to be set when we are sending request not before auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; canonicalURI = "/"; canonicalQueryString = request_parameters; canonicalHeadersString = "host:" ~ this.host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n"; signedHeaders = "host;x-amz-date"; auto canonicalRequest = getCanonicalRequest(canonicalURI, canonicalQueryString, canonicalHeadersString, signedHeaders); string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~ service ~ "/" ~ "aws4_request"; string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~ credentialScope ~ "\n" ~ sha256Of(canonicalRequest).toHexString.toLower; auto signingKey = getSignatureKey(secretKey, curDateStr, region, service); string signature = hmac!SHA256(stringToSign.representation, signingKey).toHexString.toLower; string authorizationHeader = algorithm ~ " " ~ "Credential=" ~ accessKey ~ "/" ~ credentialScope ~ ", " ~ "SignedHeaders=" ~ signedHeaders ~ ", " ~ "Signature=" ~ signature; auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString); client.method = HTTP.Method.get; client.addRequestHeader("x-amz-date", xamztime); client.addRequestHeader("Authorization", authorizationHeader); auto content = client.perform(); return content; } private: const algorithm = "AWS4-HMAC-SHA256"; string accessKey; string secretKey; string currentClock; string currentDate; string curDateStr; string currentTime; string curTimeStr; string xamztime; string canonicalURI; string canonicalQueryString; string canonicalHeadersString; string signedHeaders; alias sign = hmac!SHA256; auto getSignatureKey(string key, string dateStamp, string regionName, string serviceName) { auto kString = ("AWS4" ~ key).representation; auto kDate = sign(dateStamp.representation, kString); auto kRegion = sign(regionName.representation, kDate); auto kService = sign(serviceName.representation, kRegion); auto kSigning = sign("aws4_request".representation, kService); return kSigning; } auto getCanonicalRequest(string canonicalURI, string canonicalQueryString, string canonicalHeadersString, string signedHeaders) { string payloadHash = sha256Of(payload).toHexString.toLower; string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ signedHeaders ~ "\n" ~ payloadHash; return canonicalRequest; } } void main() { sigv4 sig = new sigv4(); writeln(sig.go()); } I want to ask you for advises what i could do with that class to make it looks more "pro"/elegant/build in "proper way". Probably there are lot of mistakes which all beginners are doing. eg.: Did i use interface correctly?
You are reasonably close: credential sig = new sigv4();
Why are you creating sigv4 object with type credential? How in your opinion should look interface for such class?
 Although go is not really doing what I expect it to do.
 To me go should be dedicated to performing a request given what 
 ever you need for just that request. The class sigv4 is your 
 global state aka what doesn't change per request.
 To me what go returns is whatever is the common denominator for 
 what you need from it is.
Not sure if i correctly understood that. Do you propose to take out eg signing process from go function and let it only to make requests? Signature is depending on kind of request and accurate time when request is send. That is why i all that things put to it.
 From what I can see, you probably want go to take the payload 
 as an argument.
 That way you can reuse an instance of sigv4. Which is the 
 ultimate goal.
In plan i wanted to change variables per request that why i left that public variables and created that arguments for constructor - to have possibility to change that values durring creation of object. On example, im expecting it will be behaving like that: sigv4 obj = new sigv4(); content = obj.go(); //will get instances list obj.request_parameters = "Action=DescribeRegions&Version=2013-10-15" content2 = obj.go(); //will get list of regions destroy(obj); so that go will get me back what i need per request not per one object live, or it wont work like that? go method returns xml form (need to find out how force AWS to return JSON cos i saw xml module in dlang is deprecated) with structures depends on query - in default query that will be list of instances with all parameters. That xml file i want to parse in higher classes/functions (different class for different request).
Oct 12 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 13/10/15 5:17 PM, holo wrote:
 On Tuesday, 13 October 2015 at 02:03:46 UTC, Rikki Cattermole wrote:
 On 13/10/15 5:56 AM, holo wrote:
  Rikki:

 If you didn't need to make it easily changeable I would say not even
 bother with OOP at all.
Basically that what i had was enough for me and on top of that i could build my app. It need to just periodically check for new instances and if they are started or stopped and count "up and running time" for billing purpose. But like i said i want to learn programming in D and basically OOP too so i want to make it "proper way". BTW: i think right now i understand what tuple is, but still don't know for what to duplicate struct functionalities :). Those Templates still don't understand but i hope that will came naturally with time and practice. eg.. they are very similar to normal functions but you can call it with types not only attributes.. strange ;) I red yours advises and try to create according to it my own first class. I moved time functions and variables to method "go" they need to be current as possible when im sending request, if wont authorization could not pass.. so i think they shouldn't be in constructor. I moved some other variables too, and created interface. From all that things came out such monster which is working and doing its job :) module sigawsv4; import std.stdio, std.process; import std.digest.sha, std.digest.hmac; import std.string; import std.conv; import std.datetime; import std.net.curl; interface credential { int go(); } class sigv4 : credential { //could be changed to take some structure as parameter instead of such ammount of attributes this(string methodStr = "GET", string serviceStr = "ec2", string hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", string endpointStr = "https://ec2.amazonaws.com", string payloadStr = "", string parmStr = "Action=DescribeInstances&Version=2013-10-15") { this.method = methodStr; this.service = serviceStr; this.host = hostStr; this.region = regionStr; this.endpoint = endpointStr; this.payload = payloadStr; this.request_parameters = parmStr; this.accessKey = environment.get("AWS_ACCESS_KEY"); this.secretKey = environment.get("AWS_SECRET_KEY"); } public: string method; string service; string host; string region; string endpoint; string payload; string request_parameters; int go() { //time need to be set when we are sending request not before auto currentClock = Clock.currTime(UTC()); auto currentDate = cast(Date)currentClock; auto curDateStr = currentDate.toISOString; auto currentTime = cast(TimeOfDay)currentClock; auto curTimeStr = currentTime.toISOString; auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z"; canonicalURI = "/"; canonicalQueryString = request_parameters; canonicalHeadersString = "host:" ~ this.host ~ "\n" ~ "x-amz-date:" ~ xamztime ~ "\n"; signedHeaders = "host;x-amz-date"; auto canonicalRequest = getCanonicalRequest(canonicalURI, canonicalQueryString, canonicalHeadersString, signedHeaders); string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~ service ~ "/" ~ "aws4_request"; string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~ credentialScope ~ "\n" ~ sha256Of(canonicalRequest).toHexString.toLower; auto signingKey = getSignatureKey(secretKey, curDateStr, region, service); string signature = hmac!SHA256(stringToSign.representation, signingKey).toHexString.toLower; string authorizationHeader = algorithm ~ " " ~ "Credential=" ~ accessKey ~ "/" ~ credentialScope ~ ", " ~ "SignedHeaders=" ~ signedHeaders ~ ", " ~ "Signature=" ~ signature; auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString); client.method = HTTP.Method.get; client.addRequestHeader("x-amz-date", xamztime); client.addRequestHeader("Authorization", authorizationHeader); auto content = client.perform(); return content; } private: const algorithm = "AWS4-HMAC-SHA256"; string accessKey; string secretKey; string currentClock; string currentDate; string curDateStr; string currentTime; string curTimeStr; string xamztime; string canonicalURI; string canonicalQueryString; string canonicalHeadersString; string signedHeaders; alias sign = hmac!SHA256; auto getSignatureKey(string key, string dateStamp, string regionName, string serviceName) { auto kString = ("AWS4" ~ key).representation; auto kDate = sign(dateStamp.representation, kString); auto kRegion = sign(regionName.representation, kDate); auto kService = sign(serviceName.representation, kRegion); auto kSigning = sign("aws4_request".representation, kService); return kSigning; } auto getCanonicalRequest(string canonicalURI, string canonicalQueryString, string canonicalHeadersString, string signedHeaders) { string payloadHash = sha256Of(payload).toHexString.toLower; string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ signedHeaders ~ "\n" ~ payloadHash; return canonicalRequest; } } void main() { sigv4 sig = new sigv4(); writeln(sig.go()); } I want to ask you for advises what i could do with that class to make it looks more "pro"/elegant/build in "proper way". Probably there are lot of mistakes which all beginners are doing. eg.: Did i use interface correctly?
You are reasonably close: credential sig = new sigv4();
Why are you creating sigv4 object with type credential? How in your opinion should look interface for such class?
 Although go is not really doing what I expect it to do.
 To me go should be dedicated to performing a request given what ever
 you need for just that request. The class sigv4 is your global state
 aka what doesn't change per request.
 To me what go returns is whatever is the common denominator for what
 you need from it is.
Not sure if i correctly understood that. Do you propose to take out eg signing process from go function and let it only to make requests? Signature is depending on kind of request and accurate time when request is send. That is why i all that things put to it.
The implementation such as sigv4 can be configured with as much detail as possible extra that you need. The method go can for instance do what ever it needs to, to for fill it's goal.
 From what I can see, you probably want go to take the payload as an
 argument.
 That way you can reuse an instance of sigv4. Which is the ultimate goal.
In plan i wanted to change variables per request that why i left that public variables and created that arguments for constructor - to have possibility to change that values durring creation of object. On example, im expecting it will be behaving like that: sigv4 obj = new sigv4(); content = obj.go(); //will get instances list obj.request_parameters = "Action=DescribeRegions&Version=2013-10-15" content2 = obj.go(); //will get list of regions destroy(obj); so that go will get me back what i need per request not per one object live, or it wont work like that?
It indeed should not. Also remember go is currently returning an integer. Not data from the request.
 go method returns xml form (need to find out how force AWS to return
 JSON cos i saw xml module in dlang is deprecated) with structures
 depends on query - in default query that will be list of  instances with
 all  parameters. That xml file i want to parse in higher
 classes/functions (different class for different request).
If you need to use std.xml use it. We don't appear to be replacing it any time soon. So here is the thing. You are tieing your usage of the API to SigV4 standard. This is bad bad bad. Any updates or changes to it, will cause problems. If you want to tie yourself to said standard, then you don't need OOP. Another thing, you may want to consider to use an interface as the return type of go. That way your implementation of it can have extra fields/methods which if you know that it is sigv4 you can cast to, to get access to, should you need it. Also classes start with a capital letter, like Credential or SigV4. And D prefers camal casing aka requestParameters for variables/functions.
Oct 13 2015
parent reply holo <holosian gmail.com> writes:
 I want to ask you for  advises what i could do with that 
 class to make
 it looks more "pro"/elegant/build in "proper way". Probably 
 there are
 lot of mistakes which all beginners are doing.

 eg.: Did i use interface correctly?
You are reasonably close: credential sig = new sigv4();
Why are you creating sigv4 object with type credential? How in your opinion should look interface for such class?
 Although go is not really doing what I expect it to do.
 To me go should be dedicated to performing a request given 
 what ever
 you need for just that request. The class sigv4 is your 
 global state
 aka what doesn't change per request.
 To me what go returns is whatever is the common denominator 
 for what
 you need from it is.
Not sure if i correctly understood that. Do you propose to take out eg signing process from go function and let it only to make requests? Signature is depending on kind of request and accurate time when request is send. That is why i all that things put to it.
The implementation such as sigv4 can be configured with as much detail as possible extra that you need. The method go can for instance do what ever it needs to, to for fill it's goal.
 From what I can see, you probably want go to take the payload 
 as an
 argument.
 That way you can reuse an instance of sigv4. Which is the 
 ultimate goal.
In plan i wanted to change variables per request that why i left that public variables and created that arguments for constructor - to have possibility to change that values durring creation of object. On example, im expecting it will be behaving like that: sigv4 obj = new sigv4(); content = obj.go(); //will get instances list obj.request_parameters = "Action=DescribeRegions&Version=2013-10-15" content2 = obj.go(); //will get list of regions destroy(obj); so that go will get me back what i need per request not per one object live, or it wont work like that?
It indeed should not. Also remember go is currently returning an integer. Not data from the request.
I test it with such code: void main() { SigV4 sig = new SigV4(); writeln(sig.go); sig.requestParameters = "Action=DescribeRegions&Version=2013-10-15"; writeln(sig.go()); } Actually it is working, first it returned to me default request DescribeInstances and right after that request DescirbeRegions. I understand that, before i will start parsing it with xml lib i need to convert it to string. Should it be solved in other way?
 go method returns xml form (need to find out how force AWS to 
 return
 JSON cos i saw xml module in dlang is deprecated) with 
 structures
 depends on query - in default query that will be list of  
 instances with
 all  parameters. That xml file i want to parse in higher
 classes/functions (different class for different request).
If you need to use std.xml use it. We don't appear to be replacing it any time soon. So here is the thing. You are tieing your usage of the API to SigV4 standard. This is bad bad bad. Any updates or changes to it, will cause problems. If you want to tie yourself to said standard, then you don't need OOP.
How it could be solved in that case to not be tied to SigV4? If there will came some other request signing process it will need to be implement in that "go" function. Is there possibility to make it universal for all kind of signing processes? How it should be done in OOP (some example, pseudo code)? Or i missed what you are pointing to?
 Another thing, you may want to consider to use an interface as 
 the return type of go. That way your implementation of it can 
 have extra fields/methods which if you know that it is sigv4 
 you can cast to, to get access to, should you need it.
It interesting what you wrote. Can you show me some example (pseudo code) how it can be implemented and how it could be used? It think that it is what you wrote in previous post: Credential sigv4 = new sigv4(); Remember im really beginner and some obvious things are not necessarily such for me. :)
 Also classes start with a capital letter, like Credential or 
 SigV4. And D prefers camal casing aka requestParameters for 
 variables/functions.
Updated my code according to those directions. //holo
Oct 14 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 15/10/15 8:15 AM, holo wrote:
 I want to ask you for  advises what i could do with that class to make
 it looks more "pro"/elegant/build in "proper way". Probably there are
 lot of mistakes which all beginners are doing.

 eg.: Did i use interface correctly?
You are reasonably close: credential sig = new sigv4();
Why are you creating sigv4 object with type credential? How in your opinion should look interface for such class?
 Although go is not really doing what I expect it to do.
 To me go should be dedicated to performing a request given what ever
 you need for just that request. The class sigv4 is your global state
 aka what doesn't change per request.
 To me what go returns is whatever is the common denominator for what
 you need from it is.
Not sure if i correctly understood that. Do you propose to take out eg signing process from go function and let it only to make requests? Signature is depending on kind of request and accurate time when request is send. That is why i all that things put to it.
The implementation such as sigv4 can be configured with as much detail as possible extra that you need. The method go can for instance do what ever it needs to, to for fill it's goal.
 From what I can see, you probably want go to take the payload as an
 argument.
 That way you can reuse an instance of sigv4. Which is the ultimate
 goal.
In plan i wanted to change variables per request that why i left that public variables and created that arguments for constructor - to have possibility to change that values durring creation of object. On example, im expecting it will be behaving like that: sigv4 obj = new sigv4(); content = obj.go(); //will get instances list obj.request_parameters = "Action=DescribeRegions&Version=2013-10-15" content2 = obj.go(); //will get list of regions destroy(obj); so that go will get me back what i need per request not per one object live, or it wont work like that?
It indeed should not. Also remember go is currently returning an integer. Not data from the request.
I test it with such code: void main() { SigV4 sig = new SigV4(); writeln(sig.go); sig.requestParameters = "Action=DescribeRegions&Version=2013-10-15"; writeln(sig.go()); } Actually it is working, first it returned to me default request DescribeInstances and right after that request DescirbeRegions. I understand that, before i will start parsing it with xml lib i need to convert it to string. Should it be solved in other way?
 go method returns xml form (need to find out how force AWS to return
 JSON cos i saw xml module in dlang is deprecated) with structures
 depends on query - in default query that will be list of instances with
 all  parameters. That xml file i want to parse in higher
 classes/functions (different class for different request).
If you need to use std.xml use it. We don't appear to be replacing it any time soon. So here is the thing. You are tieing your usage of the API to SigV4 standard. This is bad bad bad. Any updates or changes to it, will cause problems. If you want to tie yourself to said standard, then you don't need OOP.
How it could be solved in that case to not be tied to SigV4? If there will came some other request signing process it will need to be implement in that "go" function. Is there possibility to make it universal for all kind of signing processes? How it should be done in OOP (some example, pseudo code)? Or i missed what you are pointing to?
 Another thing, you may want to consider to use an interface as the
 return type of go. That way your implementation of it can have extra
 fields/methods which if you know that it is sigv4 you can cast to, to
 get access to, should you need it.
It interesting what you wrote. Can you show me some example (pseudo code) how it can be implemented and how it could be used? It think that it is what you wrote in previous post: Credential sigv4 = new sigv4(); Remember im really beginner and some obvious things are not necessarily such for me. :)
 Also classes start with a capital letter, like Credential or SigV4.
 And D prefers camal casing aka requestParameters for variables/functions.
Updated my code according to those directions. //holo
Just some ideas: interface RequestResult { ... } RequestResult go(string[string] requestParameters)
Oct 14 2015
parent reply holo <holosian gmail.com> writes:
 Just some ideas:

 interface RequestResult {
 	...
 }

 RequestResult go(string[string] requestParameters)
Basically it is same what you wrote in one of first posts. Interface is for declaration of methods which need to be implemented in class. How in that case is it possible to return RequestResult which is basically xml form as function/s and one of it will be go itself? Do you have any link to such solution which i can take as example? I was looking for it but didn't find such solution. One idea interface RequestResult { string doSomethingWithXML(string xmlString); RequestResult go(); //or just not put here that go? } Class SigV4 : RequestResult { ... go() { string xml; ... return doSomethingWithXML(xml); } doSomethingWithXML(string xmlString) { ... } } but i still don't see how it could work like that.
Oct 14 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 15/10/15 4:45 PM, holo wrote:
 Just some ideas:

 interface RequestResult {
     ...
 }

 RequestResult go(string[string] requestParameters)
Basically it is same what you wrote in one of first posts. Interface is for declaration of methods which need to be implemented in class. How in that case is it possible to return RequestResult which is basically xml form as function/s and one of it will be go itself? Do you have any link to such solution which i can take as example? I was looking for it but didn't find such solution. One idea interface RequestResult { string doSomethingWithXML(string xmlString); RequestResult go(); //or just not put here that go? } Class SigV4 : RequestResult { ... go() { string xml; ... return doSomethingWithXML(xml); } doSomethingWithXML(string xmlString) { ... } } but i still don't see how it could work like that.
SigV4 would not inherit from RequestResult. Credential interface provides a method to make the requests. RequestResult would be just an abstraction around what you expect to get back. The abstraction allows so that interface is what you will commonly need. You can cast to the specific implementation e.g. SigV4Result to get access to resulting data from the SigV4 process.
Oct 14 2015
parent reply holo <holosian gmail.com> writes:
Please again, any example? I'm trying to figure out how it should 
be done but i don't have any base from which i can build some 
solution.



import std.stdio;

interface RequestResult
{

         int add (int x);

}

class B : RequestResult
{
         int add(int x)
         {
                 return ++x;
         }
}

class A
{
         RequestResult go(int varA, int varB)
         {
                 return add(varA + varB);
         }
}

void main()
{
         B b = new B();
         A a = new A();
         int x = 12;
         int y = 15;


         RequestResult c = A.go(x, y);
}

It even don't want to compile, but that probably not what you 
ware thinking about.

[holo ultraxps workplace]$ dmd test.d
test.d(24): Error: undefined identifier 'add'
test.d(38): Error: need 'this' for 'go' of type 
'RequestResult(int varA, int varB)'
[holo ultraxps workplace]$
Oct 14 2015
parent reply Rikki Cattermole <alphaglosined gmail.com> writes:
On 15/10/15 5:43 PM, holo wrote:
 Please again, any example? I'm trying to figure out how it should be
 done but i don't have any base from which i can build some solution.



 import std.stdio;

 interface RequestResult
 {

          int add (int x);

 }

 class B : RequestResult
 {
          int add(int x)
          {
                  return ++x;
          }
 }

 class A
 {
          RequestResult go(int varA, int varB)
          {
                  return add(varA + varB);
          }
 }

 void main()
 {
          B b = new B();
          A a = new A();
          int x = 12;
          int y = 15;


          RequestResult c = A.go(x, y);
 }

 It even don't want to compile, but that probably not what you ware
 thinking about.

 [holo ultraxps workplace]$ dmd test.d
 test.d(24): Error: undefined identifier 'add'
 test.d(38): Error: need 'this' for 'go' of type 'RequestResult(int varA,
 int varB)'
 [holo ultraxps workplace]$
interface IA { IB do(int x, int y); } interface IB { int z(); } class A : IA { IB do(int x, int y) {return new B(x + y);} } class B : IB { private int value; this(int value) { this.value = value; } int z() { return value; } void proof() { import std.stdio; writeln("proof this is B"); } } void main() { IA a = new A(); IB b = a.do(1, 1); B realB = cast(B)b; realB.proof(); } b.proof() won't compile obviously, since IB does not have a proof method. The point here is to separate out the object gained from how you go it. So that the implementation on how to get it doesn't matter. That way it can be swapped at runtime without any ill effects.
Oct 14 2015
next sibling parent holo <holosian gmail.com> writes:
Thank you for example. I asked about it programmers at work too - 
PHP guys - and they explained me how you are see usage of that 
interfaces in my code. They prepare for me some "skeleton" on 
which i will try to build my solution. Will be back  if i will 
have some code.
Oct 15 2015
prev sibling parent reply holo <holosian gmail.com> writes:
I created interface IfRequestHandler it is used only by one class 
RequestHandlerXML right now but thanks to such solution i can 
create more classes with same interface which can handle it in 
different way.. eg second can be RequestHandlerCSVReport or 
RequestHandlerSendViaEmail. Is it this what you ware mentioning? 
Bellow working code:

/////////
//main.d:
/////////



import std.stdio, sigv4, conf;



void main()
{
     ResultHandlerXML hand = new ResultHandlerXML;
     SigV4 req = new SigV4(hand);

     //req.ResultHandler = hand;
     req.go();
     hand.processResult();

}

/////////
//conf.d:
/////////

module conf;

import std.stdio, std.process;
import std.net.curl:exit;

interface IfConfig
{
     void set(string val, string var);
     string get(string var);
}


class Config : IfConfig
{
     this()
     {
         this.accKey = environment.get("AWS_ACCESS_KEY");
         if(accKey is null)
         {
             writeln("accessKey not available");
             exit(-1);
         }
         this.secKey = environment.get("AWS_SECRET_KEY");
         if(secKey is null)
         {
             writeln("secretKey not available");
             exit(-1);
         }
     }

     public:

         void set(string val, string var)
         {
             switch(var)
             {
                 case "accKey": accKey = val; break;
                 case "secKey": secKey = val; break;
                 default: writeln("Can not be set, not such 
value");
             }
         }


         string get(string var)
         {
             string str = "";

             switch(var)
             {
             case "accKey": return accKey;
             case "secKey": return secKey;
             default: writeln("Can not be get, not such value");
             }

             return str;
         }


  //   private:

         string accKey;
         string secKey;

}

/////////
//sigv4.d
/////////

module sigv4;

import std.stdio, std.process;
import std.digest.sha, std.digest.hmac;
import std.string;
import std.conv;
import std.datetime;
import std.net.curl;
import conf;


interface IfSigV4
{
	IfResultHandler go(ResultHandlerXML ResultHandler);
}

interface IfResultHandler
{
         void setResult(int content);
         void processResult();
}

class ResultHandlerXML : IfResultHandler
{
     void setResult(int content)
     {
         this.xmlresult = content;
     }

     void processResult()
     {
         writeln(xmlresult);
     }

     private:
         int xmlresult;
}

class SigV4 : IfSigV4
{
	//could be changed to take some structure as parameter instead 
of such ammount of attributes

	this(string methodStr = "GET", string serviceStr = "ec2", string 
hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", 
string endpointStr = "https://ec2.amazonaws.com", string 
payloadStr = "", string parmStr = "Action=DescribeInstances")
	in
	{
		writeln(parmStr);
	}
	body
	{
         conf.Config config = new conf.Config;

		this.method = methodStr;
		this.service = serviceStr;
		this.host = hostStr;
		this.region = regionStr;
		this.endpoint = endpointStr;
		this.payload = payloadStr;
		this.requestParameters = parmStr;

		this.accessKey = config.get("accKey");
		if(accessKey is null)
		{
			writeln("accessKey not available");
			exit(-1);
		}
		this.secretKey = config.get("secKey");
		if(secretKey is null)
                 {
                         writeln("secretKey not available");
			exit(-1);
                 }

	}

	public:
		string method;
		string service;
		string host;
		string region;
		string endpoint;
		string payload;
		string requestParameters;

		IfResultHandler ResultHandler;




		IfResultHandler go(ResultHandlerXML ResultHandler)
		{
			//time need to be set when we are sending request not before
			auto currentClock = Clock.currTime(UTC());
			auto currentDate = cast(Date)currentClock;
			auto curDateStr = currentDate.toISOString;
			auto currentTime = cast(TimeOfDay)currentClock;
			auto curTimeStr = currentTime.toISOString;
			auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";

			canonicalURI = "/";
			canonicalQueryString = requestParameters ~ this.Version;
			canonicalHeadersString =  "host:" ~ this.host ~ "\n" ~ 
"x-amz-date:" ~ xamztime ~ "\n";
			signedHeaders = "host;x-amz-date";

			auto canonicalRequest = getCanonicalRequest(canonicalURI, 
canonicalQueryString, canonicalHeadersString, signedHeaders);

			string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~ 
service ~ "/" ~ "aws4_request";

			string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~ 
credentialScope ~ "\n" ~ 
sha256Of(canonicalRequest).toHexString.toLower;

			auto signingKey = getSignatureKey(secretKey, curDateStr, 
region, service);

			string signature = hmac!SHA256(stringToSign.representation, 
signingKey).toHexString.toLower;

			string authorizationHeader = algorithm ~ " " ~ "Credential=" ~ 
accessKey ~ "/" ~ credentialScope ~ ", " ~ "SignedHeaders=" ~ 
signedHeaders ~ ", " ~ "Signature=" ~ signature;

			auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString);
			client.method = HTTP.Method.get;
			client.addRequestHeader("x-amz-date", xamztime);
			client.addRequestHeader("Authorization", authorizationHeader);
			auto content = client.perform();

             writeln(content);

			ResultHandler.setResult(content);
                         return ResultHandler;
		}

	private:
		const string algorithm = "AWS4-HMAC-SHA256";
		const string Version = "&Version=2013-10-15";

		string accessKey;
		string secretKey;



		string canonicalURI;
		string canonicalQueryString;
	       	string canonicalHeadersString;
	       	string signedHeaders;



		alias sign = hmac!SHA256;

		auto getSignatureKey(string key, string dateStamp, string 
regionName, string serviceName)
		{
			auto kString = ("AWS4" ~ key).representation;
			auto kDate = sign(dateStamp.representation, kString);
			auto kRegion = sign(regionName.representation, kDate);
			auto kService = sign(serviceName.representation, kRegion);
			auto kSigning = sign("aws4_request".representation, kService);

			return kSigning;
		}


		auto getCanonicalRequest(string canonicalURI, string 
canonicalQueryString, string canonicalHeadersString, string 
signedHeaders)
		{
			string payloadHash = sha256Of(payload).toHexString.toLower;
			string canonicalRequest = method ~ "\n" ~ canonicalURI ~ "\n" 
~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~ 
signedHeaders ~ "\n" ~ payloadHash;
			return canonicalRequest;
		}
}
Oct 15 2015
parent Rikki Cattermole <alphaglosined gmail.com> writes:
On 16/10/15 4:14 PM, holo wrote:
 I created interface IfRequestHandler it is used only by one class
 RequestHandlerXML right now but thanks to such solution i can create
 more classes with same interface which can handle it in different way..
 eg second can be RequestHandlerCSVReport or RequestHandlerSendViaEmail.
 Is it this what you ware mentioning? Bellow working code:

 /////////
 //main.d:
 /////////



 import std.stdio, sigv4, conf;



 void main()
 {
      ResultHandlerXML hand = new ResultHandlerXML;
      SigV4 req = new SigV4(hand);

      //req.ResultHandler = hand;
      req.go();
      hand.processResult();

 }

 /////////
 //conf.d:
 /////////

 module conf;

 import std.stdio, std.process;
 import std.net.curl:exit;

 interface IfConfig
 {
      void set(string val, string var);
      string get(string var);
 }


 class Config : IfConfig
 {
      this()
      {
          this.accKey = environment.get("AWS_ACCESS_KEY");
          if(accKey is null)
          {
              writeln("accessKey not available");
              exit(-1);
          }
          this.secKey = environment.get("AWS_SECRET_KEY");
          if(secKey is null)
          {
              writeln("secretKey not available");
              exit(-1);
          }
      }

      public:

          void set(string val, string var)
          {
              switch(var)
              {
                  case "accKey": accKey = val; break;
                  case "secKey": secKey = val; break;
                  default: writeln("Can not be set, not such value");
              }
          }


          string get(string var)
          {
              string str = "";

              switch(var)
              {
              case "accKey": return accKey;
              case "secKey": return secKey;
              default: writeln("Can not be get, not such value");
              }

              return str;
          }


   //   private:

          string accKey;
          string secKey;

 }

 /////////
 //sigv4.d
 /////////

 module sigv4;

 import std.stdio, std.process;
 import std.digest.sha, std.digest.hmac;
 import std.string;
 import std.conv;
 import std.datetime;
 import std.net.curl;
 import conf;


 interface IfSigV4
 {
      IfResultHandler go(ResultHandlerXML ResultHandler);
 }

 interface IfResultHandler
 {
          void setResult(int content);
          void processResult();
 }

 class ResultHandlerXML : IfResultHandler
 {
      void setResult(int content)
      {
          this.xmlresult = content;
      }

      void processResult()
      {
          writeln(xmlresult);
      }

      private:
          int xmlresult;
 }

 class SigV4 : IfSigV4
 {
      //could be changed to take some structure as parameter instead of
 such ammount of attributes

      this(string methodStr = "GET", string serviceStr = "ec2", string
 hostStr = "ec2.amazonaws.com", string regionStr = "us-east-1", string
 endpointStr = "https://ec2.amazonaws.com", string payloadStr = "",
 string parmStr = "Action=DescribeInstances")
      in
      {
          writeln(parmStr);
      }
      body
      {
          conf.Config config = new conf.Config;

          this.method = methodStr;
          this.service = serviceStr;
          this.host = hostStr;
          this.region = regionStr;
          this.endpoint = endpointStr;
          this.payload = payloadStr;
          this.requestParameters = parmStr;

          this.accessKey = config.get("accKey");
          if(accessKey is null)
          {
              writeln("accessKey not available");
              exit(-1);
          }
          this.secretKey = config.get("secKey");
          if(secretKey is null)
                  {
                          writeln("secretKey not available");
              exit(-1);
                  }

      }

      public:
          string method;
          string service;
          string host;
          string region;
          string endpoint;
          string payload;
          string requestParameters;

          IfResultHandler ResultHandler;




          IfResultHandler go(ResultHandlerXML ResultHandler)
          {
              //time need to be set when we are sending request not before
              auto currentClock = Clock.currTime(UTC());
              auto currentDate = cast(Date)currentClock;
              auto curDateStr = currentDate.toISOString;
              auto currentTime = cast(TimeOfDay)currentClock;
              auto curTimeStr = currentTime.toISOString;
              auto xamztime = curDateStr ~ "T" ~ curTimeStr ~ "Z";

              canonicalURI = "/";
              canonicalQueryString = requestParameters ~ this.Version;
              canonicalHeadersString =  "host:" ~ this.host ~ "\n" ~
 "x-amz-date:" ~ xamztime ~ "\n";
              signedHeaders = "host;x-amz-date";

              auto canonicalRequest = getCanonicalRequest(canonicalURI,
 canonicalQueryString, canonicalHeadersString, signedHeaders);

              string credentialScope = curDateStr ~ "/" ~ region ~ "/" ~
 service ~ "/" ~ "aws4_request";

              string stringToSign = algorithm ~ "\n" ~ xamztime ~ "\n" ~
 credentialScope ~ "\n" ~ sha256Of(canonicalRequest).toHexString.toLower;

              auto signingKey = getSignatureKey(secretKey, curDateStr,
 region, service);

              string signature = hmac!SHA256(stringToSign.representation,
 signingKey).toHexString.toLower;

              string authorizationHeader = algorithm ~ " " ~
 "Credential=" ~ accessKey ~ "/" ~ credentialScope ~ ", " ~
 "SignedHeaders=" ~ signedHeaders ~ ", " ~ "Signature=" ~ signature;

              auto client = HTTP(endpoint ~ "?" ~ canonicalQueryString);
              client.method = HTTP.Method.get;
              client.addRequestHeader("x-amz-date", xamztime);
              client.addRequestHeader("Authorization", authorizationHeader);
              auto content = client.perform();

              writeln(content);

              ResultHandler.setResult(content);
                          return ResultHandler;
          }

      private:
          const string algorithm = "AWS4-HMAC-SHA256";
          const string Version = "&Version=2013-10-15";

          string accessKey;
          string secretKey;



          string canonicalURI;
          string canonicalQueryString;
                 string canonicalHeadersString;
                 string signedHeaders;



          alias sign = hmac!SHA256;

          auto getSignatureKey(string key, string dateStamp, string
 regionName, string serviceName)
          {
              auto kString = ("AWS4" ~ key).representation;
              auto kDate = sign(dateStamp.representation, kString);
              auto kRegion = sign(regionName.representation, kDate);
              auto kService = sign(serviceName.representation, kRegion);
              auto kSigning = sign("aws4_request".representation, kService);

              return kSigning;
          }


          auto getCanonicalRequest(string canonicalURI, string
 canonicalQueryString, string canonicalHeadersString, string signedHeaders)
          {
              string payloadHash = sha256Of(payload).toHexString.toLower;
              string canonicalRequest = method ~ "\n" ~ canonicalURI ~
 "\n" ~ canonicalQueryString ~ "\n" ~ canonicalHeadersString ~ "\n" ~
 signedHeaders ~ "\n" ~ payloadHash;
              return canonicalRequest;
          }
 }
I was thinking along the lines of a new object per result. But that sorta also works, since the handler can be and will be reused.
Oct 15 2015