Skip to content
This repository was archived by the owner on Mar 17, 2025. It is now read-only.

Implement modem (attempt 2) #83

Merged
merged 6 commits into from
Apr 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "test/googletest"]
path = test/googletest
url = https://github.com/google/googletest.git
[submodule "test/arduino-mock"]
path = test/arduino-mock
url = https://github.com/ed7coyne/arduino-mock.git
94 changes: 57 additions & 37 deletions src/Firebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,9 @@
//
#include "Firebase.h"

// Detect whether stable version of HTTP library is installed instead of
// master branch and patch in missing status and methods.
#ifndef HTTP_CODE_TEMPORARY_REDIRECT
#define HTTP_CODE_TEMPORARY_REDIRECT 307
#define USE_ESP_ARDUINO_CORE_2_0_0
#endif
using std::unique_ptr;

namespace {
const char* kFirebaseFingerprint = "7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A";
const uint16_t kFirebasePort = 443;

String makeFirebaseURL(const String& path, const String& auth) {
String url;
if (path[0] != '/') {
Expand All @@ -41,45 +33,75 @@ String makeFirebaseURL(const String& path, const String& auth) {
} // namespace

Firebase::Firebase(const String& host) : host_(host) {
http_.setReuse(true);
http_.reset(FirebaseHttpClient::create());
http_->setReuseConnection(true);
}

Firebase& Firebase::auth(const String& auth) {
auth_ = auth;
return *this;
}

const String& Firebase::auth() {
return auth_;
}

FirebaseGet Firebase::get(const String& path) {
return FirebaseGet(host_, auth_, path, &http_);
return FirebaseGet(host_, auth_, path, http_.get());
}

unique_ptr<FirebaseGet> Firebase::getPtr(const String& path) {
return unique_ptr<FirebaseGet>(new FirebaseGet(host_, auth_, path, http_.get()));
}

FirebaseSet Firebase::set(const String& path, const String& value) {
return FirebaseSet(host_, auth_, path, value, &http_);
return FirebaseSet(host_, auth_, path, value, http_.get());
}

unique_ptr<FirebaseSet> Firebase::setPtr(const String& path,
const String& value) {
return unique_ptr<FirebaseSet>(
new FirebaseSet(host_, auth_, path, value, http_.get()));
}

FirebasePush Firebase::push(const String& path, const String& value) {
return FirebasePush(host_, auth_, path, value, &http_);
return FirebasePush(host_, auth_, path, value, http_.get());
}
unique_ptr<FirebasePush> Firebase::pushPtr(const String& path, const String& value) {
return unique_ptr<FirebasePush>(
new FirebasePush(host_, auth_, path, value, http_.get()));
}

FirebaseRemove Firebase::remove(const String& path) {
return FirebaseRemove(host_, auth_, path, &http_);
return FirebaseRemove(host_, auth_, path, http_.get());
}

unique_ptr<FirebaseRemove> Firebase::removePtr(const String& path) {
return unique_ptr<FirebaseRemove>(
new FirebaseRemove(host_, auth_, path, http_.get()));
}

FirebaseStream Firebase::stream(const String& path) {
// TODO: create new client dedicated to stream.
return FirebaseStream(host_, auth_, path, &http_);
return FirebaseStream(host_, auth_, path, http_.get());
}

unique_ptr<FirebaseStream> Firebase::streamPtr(const String& path) {
// TODO: create new client dedicated to stream.
return unique_ptr<FirebaseStream>(
new FirebaseStream(host_, auth_, path, http_.get()));
}

// FirebaseCall
FirebaseCall::FirebaseCall(const String& host, const String& auth,
const char* method, const String& path,
const String& data, HTTPClient* http) : http_(http) {
String url = makeFirebaseURL(path, auth);
http_->setReuse(true);
http_->begin(host, kFirebasePort, url, true, kFirebaseFingerprint);
const String& data, FirebaseHttpClient* http) : http_(http) {
String path_with_auth = makeFirebaseURL(path, auth);
http_->setReuseConnection(true);
http_->begin(host, path_with_auth);

bool followRedirect = false;
if (method == "STREAM") {
if (String(method) == "STREAM") {
method = "GET";
http_->addHeader("Accept", "text/event-stream");
followRedirect = true;
Expand All @@ -90,26 +112,24 @@ FirebaseCall::FirebaseCall(const String& host, const String& auth,
http_->collectHeaders(headers, 1);
}

int status = http_->sendRequest(method, (uint8_t*)data.c_str(), data.length());
int status = http_->sendRequest(method, data);

// TODO: Add a max redirect check
if (followRedirect) {
while (status == HTTP_CODE_TEMPORARY_REDIRECT) {
while (status == HttpStatus::TEMPORARY_REDIRECT) {
String location = http_->header("Location");
http_->setReuse(false);
http_->setReuseConnection(false);
http_->end();
http_->setReuse(true);
http_->begin(location, kFirebaseFingerprint);
status = http_->sendRequest("GET", (uint8_t*)NULL, 0);
http_->setReuseConnection(true);
http_->begin(location);
status = http_->sendRequest("GET", String());
}
}

if (status != 200) {
#ifdef USE_ESP_ARDUINO_CORE_2_0_0
error_ = FirebaseError(status, String(method) + " " + url + ": " + status);
#else
error_ = FirebaseError(status, String(method) + " " + url + ": " + HTTPClient::errorToString(status));
#endif
error_ = FirebaseError(status,
String(method) + " " + path_with_auth +
": " + http_->errorToString(status));
}

// if not streaming.
Expand All @@ -128,14 +148,14 @@ const JsonObject& FirebaseCall::json() {
// FirebaseGet
FirebaseGet::FirebaseGet(const String& host, const String& auth,
const String& path,
HTTPClient* http)
FirebaseHttpClient* http)
: FirebaseCall(host, auth, "GET", path, "", http) {
}

// FirebaseSet
FirebaseSet::FirebaseSet(const String& host, const String& auth,
const String& path, const String& value,
HTTPClient* http)
FirebaseHttpClient* http)
: FirebaseCall(host, auth, "PUT", path, value, http) {
if (!error()) {
// TODO: parse json
Expand All @@ -145,24 +165,24 @@ FirebaseSet::FirebaseSet(const String& host, const String& auth,
// FirebasePush
FirebasePush::FirebasePush(const String& host, const String& auth,
const String& path, const String& value,
HTTPClient* http)
FirebaseHttpClient* http)
: FirebaseCall(host, auth, "POST", path, value, http) {
if (!error()) {
name_ = json()["name"].as<const char*>();
//name_ = json()["name"].as<const char*>();
}
}

// FirebasePush
FirebaseRemove::FirebaseRemove(const String& host, const String& auth,
const String& path,
HTTPClient* http)
FirebaseHttpClient* http)
: FirebaseCall(host, auth, "DELETE", path, "", http) {
}

// FirebaseStream
FirebaseStream::FirebaseStream(const String& host, const String& auth,
const String& path,
HTTPClient* http)
FirebaseHttpClient* http)
: FirebaseCall(host, auth, "STREAM", path, "", http) {
}

Expand Down
67 changes: 49 additions & 18 deletions src/Firebase.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
#define firebase_h

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <ESP8266HTTPClient.h>
#include <memory>
#include "FirebaseHttpClient.h"
// TODO(edcoyne): move this into our mock_arduino fork where we actually do the
// override.
#define ARDUINO_STRING_OVERRIDE
#include "third-party/arduino-json-5.1.1/include/ArduinoJson.h"

class FirebaseGet;
Expand All @@ -35,26 +37,41 @@ class FirebaseStream;
// Firebase REST API client.
class Firebase {
public:
Firebase(const String& host);
explicit Firebase(const String& host);
Firebase& auth(const String& auth);
virtual ~Firebase() = default;

Firebase(const Firebase&) = delete;

// Fetch auth string back.
const String& auth();

// Fetch json encoded `value` at `path`.
FirebaseGet get(const String& path);
virtual std::unique_ptr<FirebaseGet> getPtr(const String& path);

// Set json encoded `value` at `path`.
FirebaseSet set(const String& path, const String& json);
virtual std::unique_ptr<FirebaseSet> setPtr(const String& path, const String& json);

// Add new json encoded `value` to list at `path`.
FirebasePush push(const String& path, const String& json);
virtual std::unique_ptr<FirebasePush> pushPtr(const String& path, const String& json);

// Delete value at `path`.
FirebaseRemove remove(const String& path);
virtual std::unique_ptr<FirebaseRemove> removePtr(const String& path);

// Start a stream of events that affect value at `path`.
FirebaseStream stream(const String& path);
virtual std::unique_ptr<FirebaseStream> streamPtr(const String& path);

protected:
// Used for testing.
Firebase() {}

private:
HTTPClient http_;
std::unique_ptr<FirebaseHttpClient> http_;
String host_;
String auth_;
};
Expand All @@ -77,20 +94,20 @@ class FirebaseCall {
FirebaseCall() {}
FirebaseCall(const String& host, const String& auth,
const char* method, const String& path,
const String& data = "",
HTTPClient* http = NULL);
const FirebaseError& error() const {
const String& data = "",
FirebaseHttpClient* http = NULL);
virtual const FirebaseError& error() const {
return error_;
}

const String& response() {
virtual const String& response() {
return response_;
}

const JsonObject& json();

protected:
HTTPClient* http_;
FirebaseHttpClient* http_;
FirebaseError error_;
String response_;
DynamicJsonBuffer buffer_;
Expand All @@ -100,7 +117,7 @@ class FirebaseGet : public FirebaseCall {
public:
FirebaseGet() {}
FirebaseGet(const String& host, const String& auth,
const String& path, HTTPClient* http = NULL);
const String& path, FirebaseHttpClient* http = NULL);

private:
String json_;
Expand All @@ -110,7 +127,8 @@ class FirebaseSet: public FirebaseCall {
public:
FirebaseSet() {}
FirebaseSet(const String& host, const String& auth,
const String& path, const String& value, HTTPClient* http = NULL);
const String& path, const String& value, FirebaseHttpClient* http = NULL);


private:
String json_;
Expand All @@ -120,9 +138,9 @@ class FirebasePush : public FirebaseCall {
public:
FirebasePush() {}
FirebasePush(const String& host, const String& auth,
const String& path, const String& value, HTTPClient* http = NULL);
const String& path, const String& value, FirebaseHttpClient* http = NULL);

const String& name() const {
virtual const String& name() const {
return name_;
}

Expand All @@ -134,18 +152,18 @@ class FirebaseRemove : public FirebaseCall {
public:
FirebaseRemove() {}
FirebaseRemove(const String& host, const String& auth,
const String& path, HTTPClient* http = NULL);
const String& path, FirebaseHttpClient* http = NULL);
};


class FirebaseStream : public FirebaseCall {
public:
FirebaseStream() {}
FirebaseStream(const String& host, const String& auth,
const String& path, HTTPClient* http = NULL);
const String& path, FirebaseHttpClient* http = NULL);

// Return if there is any event available to read.
bool available();
virtual bool available();

// Event type.
enum Event {
Expand All @@ -154,8 +172,21 @@ class FirebaseStream : public FirebaseCall {
PATCH
};

static inline String EventToName(Event event) {
switch(event) {
case UNKNOWN:
return "UNKNOWN";
case PUT:
return "PUT";
case PATCH:
return "PATCH";
default:
return "INVALID_EVENT_" + event;
}
}

// Read next json encoded `event` from stream.
Event read(String& event);
virtual Event read(String& event);

const FirebaseError& error() const {
return _error;
Expand Down
41 changes: 41 additions & 0 deletions src/FirebaseHttpClient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#ifndef FIREBASE_HTTP_CLIENT_H
#define FIREBASE_HTTP_CLIENT_H

#include "Arduino.h"
#include "Stream.h"

struct HttpStatus {
static const int TEMPORARY_REDIRECT = 307;
};

class FirebaseHttpClient {
public:
static FirebaseHttpClient* create();

virtual void setReuseConnection(bool reuse) = 0;
virtual void begin(const String& url) = 0;
virtual void begin(const String& host, const String& path) = 0;

virtual void end() = 0;

virtual void addHeader(const String& name, const String& value) = 0;
virtual void collectHeaders(const char* header_keys[],
const int header_key_count) = 0;
virtual String header(const String& name) = 0;

virtual int sendRequest(const String& method, const String& data) = 0;

virtual String getString() = 0;

virtual Stream* getStreamPtr() = 0;

virtual String errorToString(int error_code) = 0;

protected:
static const uint16_t kFirebasePort = 443;
};

static const String kFirebaseFingerprint =
"7A 54 06 9B DC 7A 25 B3 86 8D 66 53 48 2C 0B 96 42 C7 B3 0A";

#endif // FIREBASE_HTTP_CLIENT_H
Loading