]> git.piffa.net Git - arduino/blob - books/pdummies/Libraries/xively/XivelyClient.cpp
first commit
[arduino] / books / pdummies / Libraries / xively / XivelyClient.cpp
1 #include <Xively.h>
2 #include <HttpClient.h>
3 #include <CountingStream.h>
4
5 XivelyClient::XivelyClient(Client& aClient)
6   : _client(aClient)
7 {
8 }
9
10 int XivelyClient::put(XivelyFeed& aFeed, const char* aApiKey)
11 {
12   HttpClient http(_client);
13   char path[30];
14   buildPath(path, aFeed.id(), "json");
15   http.beginRequest();
16   int ret = http.put("api.xively.com", path);
17   if (ret == 0)
18   {
19     http.sendHeader("X-ApiKey", aApiKey);
20     http.sendHeader("User-Agent", "Xively-Arduino-Lib/1.0");    
21
22     CountingStream countingStream; // Used to work out how long that data will be
23     for (int i =kCalculateDataLength; i <= kSendData; i++)
24     {
25       Print* s;
26       int len =0;
27       if (i == kCalculateDataLength)
28       {
29         s = &countingStream;
30       }
31       else
32       {
33         s = &http;
34       }
35       len = s->print(aFeed);
36       if (i == kCalculateDataLength)
37       {
38         // We now know how long the data will be...
39         http.sendHeader("Content-Length", len);
40       }
41     }
42     // Now we're done sending the request
43     http.endRequest();
44
45     ret = http.responseStatusCode();
46     if ((ret < 200) || (ret > 299))
47     {
48       // It wasn't a successful response, ensure it's -ve so the error is easy to spot
49       if (ret > 0)
50       {
51         ret = ret * -1;
52       }
53     }
54     http.flush();
55     http.stop();
56   }
57   return ret;
58 }
59
60 void XivelyClient::buildPath(char* aDest, unsigned long aFeedId, const char* aFormat)
61 {
62   char idstr[12]; 
63   strcpy(aDest, "/v2/feeds/");
64   char* p = &idstr[10];
65   idstr[11] = 0;
66   for(*p--=aFeedId%10+0x30;aFeedId/=10;*p--=aFeedId%10+0x30);
67   strcat(aDest, p+1);
68   strcat(aDest, ".");
69   strcat(aDest, aFormat);
70 }
71
72 int XivelyClient::get(XivelyFeed& aFeed, const char* aApiKey)
73 {
74   HttpClient http(_client);
75   char path[30];
76   buildPath(path, aFeed.id(), "csv");
77   http.beginRequest();
78   int ret = http.get("api.xively.com", path);
79   if (ret == 0)
80   {
81     http.sendHeader("X-ApiKey", aApiKey);
82     http.sendHeader("User-Agent", "Xively-Arduino-Lib/1.0");    
83     http.endRequest();
84
85     ret = http.responseStatusCode();
86     if ((ret < 200) || (ret > 299))
87     {
88       // It wasn't a successful response, ensure it's -ve so the error is easy to spot
89       if (ret > 0)
90       {
91         ret = ret * -1;
92       }
93     }
94     else
95     {
96       http.skipResponseHeaders();
97       // Now we need to run through each line, looking to see if it matches one
98       // of the given datastreams.
99       // So that we don't use any more memory than necessary, we'll keep track
100       // of which character we're up to in the ID string, and have a bit-field
101       // of the remaining datastreams that match.  This limits us (if we use
102       // and unsigned long) to 32 datastreams in a feed, but that's probably ok
103       int idIdx = 0;
104       unsigned long idBitfield = 0;
105       for (int i =0; i < aFeed.size(); i++)
106       {
107         idBitfield |= 1 << i;
108       }
109       // As long as we've got bitfields to read
110 // FIXME Need to time out if this hangs for too long
111       while ((http.available() || http.connected()))
112       {
113         if (http.available())
114         {
115           char next = http.read();
116           switch (next)
117           {
118           case ',':
119             // We've reached the end of the ID string, see if it matches any of the
120             // datastreams in the feed
121             // But first skip the updated time, to get to the value
122             http.find(",");
123             for (int i =0; i < aFeed.size(); i++)
124             {
125               if ((idBitfield & 1<<i) && (aFeed[i].idLength() == idIdx))
126               {
127                 // We've found a matching datastream
128                 // FIXME cope with any errors returned
129                 aFeed[i].updateValue(http);
130                 // When we get here we'll be at the end of the line, but if aFeed[i]
131                 // was a string or buffer type, we'll have consumed the '\n'
132                 next = '\n';
133               }
134             }
135             // Need to run to the end of the line regardless now
136             // And deliberately drop through into the next case
137             while ((next != '\r')  && (next != '\n') && (http.available() || http.connected()))
138             {
139               next = http.read();
140             }
141           case '\r':
142           case '\n':
143             // We've hit the end of the line, reset everything
144             idIdx = 0;
145             for (int i =0; i < aFeed.size(); i++)
146             {
147               idBitfield |= 1 << i;
148             }
149             break;
150           default:
151             // Next character of the ID string
152             for (int i =0; i < aFeed.size(); i++)
153             {
154               if (!(idBitfield & 1<<i) || (aFeed[i].idChar(idIdx) != next))
155               {
156                 idBitfield &= ~(1<<i);
157               }
158               // else we're still matching
159             }
160             idIdx++; // onto the next character in the ID
161             break;
162           };
163         }
164       }
165       delay(10);
166     }
167     http.stop();
168   }
169   return ret;
170 }
171
172