Skip to content

Commit 9a34a53

Browse files
authored
Merge pull request #106 from fullstackreact/master
Cross platform error codes
2 parents 58a7828 + 03aab39 commit 9a34a53

File tree

192 files changed

+7472
-8495
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

192 files changed

+7472
-8495
lines changed

.gitignore

+46
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,49 @@ npm-debug.log
1010
*.xcuserstate
1111
project.xcworkspace/
1212
xcuserdata/
13+
14+
# Android
15+
16+
# Built application files
17+
android/*/build/
18+
19+
# Crashlytics configuations
20+
android/com_crashlytics_export_strings.xml
21+
22+
# Local configuration file (sdk path, etc)
23+
android/local.properties
24+
25+
# Gradle generated files
26+
android/.gradle/
27+
28+
# Signing files
29+
android/.signing/
30+
31+
# User-specific configurations
32+
android/.idea/libraries/
33+
android/.idea/workspace.xml
34+
android/.idea/tasks.xml
35+
android/.idea/.name
36+
android/.idea/compiler.xml
37+
android/.idea/copyright/profiles_settings.xml
38+
android/.idea/encodings.xml
39+
android/.idea/misc.xml
40+
android/.idea/modules.xml
41+
android/.idea/scopes/scope_settings.xml
42+
android/.idea/vcs.xml
43+
android/*.iml
44+
45+
# OS-specific files
46+
.DS_Store
47+
.DS_Store?
48+
._*
49+
.Spotlight-V100
50+
.Trashes
51+
ehthumbs.db
52+
Thumbs.dbandroid/gradle
53+
android/gradlew
54+
android/gradlew.bat
55+
android/gradle/
56+
.idea
57+
.idea
58+
coverage

.npmignore

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
*.swp
2+
*~
3+
*.iml
4+
.*.haste_cache.*
5+
.DS_Store
6+
.idea
7+
.babelrc
8+
.eslintrc
9+
npm-debug.log
10+
src/
11+
examples/
12+
public/
13+
scripts/
14+
test/

Contributing.md

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
## Contributing guide
2+
3+
This is an in-progress guide to help guide you in understanding how Firestack works with the goal to help on-board your contributions. If you have any questions, comments, or concerns, feel free to leave it here or join the [gitter channel at https://gitter.im/fullstackreact/react-native-firestack](https://gitter.im/fullstackreact/react-native-firestack).
4+
5+
## Contribution methods
6+
7+
Contributing is easy. Make a fork of the project on [github](https://github.com/fullstackreact/react-native-firestack). Clone this repo on your machine and work on the edits there.
8+
9+
```shell
10+
git clone https://github.com/[your_name]/react-native-firestack.git
11+
cd react-native-firestack
12+
npm install
13+
```
14+
15+
We have an [Example app - FirestackApp](https://github.com/fullstackreact/FirestackApp) which we use to demonstrate and test features (until we can get a proper testing environment). Currently, our workflow looks like this:
16+
17+
1. Write JS/native feature
18+
2. `rsync` the local library to your `node_modules` directory (react-native does not play well with symlinks).
19+
For instance, running the following in the firestackApp root directory. Make sure you replace the `~/Development/react-native/mine/react-native-firestack` with the path of your cloned repo on your drive:
20+
21+
```javascript
22+
rsync -avhW --delete \
23+
--exclude='node_modules' \
24+
--exclude='.git' \
25+
--exclude='coverage' \
26+
~/Development/react-native/mine/react-native-firestack/ \
27+
./node_modules/react-native-firestack/
28+
```
29+
30+
3. Test in-app
31+
4. Update README.md with bugfix/feature
32+
5. Create a pull request (PR)
33+
34+
## High level
35+
36+
## How it works technically
37+
38+
Firestack is broken up by functional modules which control/interact with the different features of Firebase. I.e. there is a database module, which maps to the Real-Time Database feature in Firebase, Analytics maps to the Firebase analytics stack.
39+
40+
When the user creates a new instance of Firestack, they are creating an instance of the JS class defined in `lib/firestack.js`.
41+
42+
```javascript
43+
// This creates a JS instance of the
44+
// Firestack class
45+
const firestack = new Firestack({});
46+
```
47+
48+
Each of the modules in Firestack can be accessed through this instance. For instance, when we want to access the real-time database through the `firestack` instance, the JS API exposes a `database` accessor.
49+
50+
For instance, when interacting with the database from the instance above, we would call `.database` to get access to a singleton instance of the JS `Database` class defined in `lib/modules/database.js`.
51+
52+
### Database walk-through
53+
54+
```javascript
55+
const db = firestack.database;
56+
```
57+
58+
The `lib/modules/database.js` file exports two classes, one called `Database` and the other called `DatabaseRef`. Essentially, the `Database` class is a wrapper class that provides a handful of methods to forward off to a `DatabaseRef` instance.
59+
60+
The `DatabaseRef` class defines the actual interaction with the native Firebase SDK. Let's look at the `getAt` method as an example of how the JS side interacts with the native-side and back.
61+
62+
When the user accessess a Firebase ref, the `Database` instance creates a new instance of the `DatabaseRef` JS class.
63+
64+
```javascript
65+
const ref = db.ref('/events');
66+
```
67+
68+
The `DatabaseRef` class is the wrapper that maps to Firebase database points. For efficiency, the `paths` are stored as an array so we can walk up and down the firebase database using the `parent()` and `child()` methods on a database ref.
69+
70+
Calling `getAt()` on the `ref` (an instance of the `DatabaseRef` class) will make a call to the **native** SDK using a method called `promisify()`
71+
72+
```javascript
73+
class DatabaseRef {
74+
// ...
75+
getAt(key) {
76+
let path = this.path;
77+
if (key && typeof(key) == 'string') {
78+
path = `${path}${separator}${key}`
79+
}
80+
return promisify('onOnce', FirestackDatabase)(path);
81+
}
82+
}
83+
```
84+
85+
Ignoring the first few lines (which are helpers to add to the `path`, which we'll look at shortly), the `promisify()` function (defined in `lib/promisify.js`) takes two arguments:
86+
87+
1. The 'string' name of the native function to call
88+
2. The native module we want to call it on
89+
90+
The `promisify()` function returns a function that returns a `Promise` object in JS. This returned function calls the native function with a React-Native callback. When the React Native function calls the callback function, the Promise is resolved.
91+
92+
Getting back to the Database example, the `getAt()` function (which has an alias of `get`) calls the `onOnce` function on the `FirestackDatabase` native module. Each platform has their own native module version for each feature area of Firebase.
93+
94+
Every function on the `DatabaseRef` class is called with the `path` from Firebase as well as it's other options.
95+
96+
Let's look at the `onOnce` function of the iOS version of `FirestackDatabase` implemented in `ios/Firestack/FirestackDatabase.m`:
97+
98+
```
99+
// This might differ from the current code, but
100+
// is implemented this way at the time of the writing
101+
// of this document
102+
RCT_EXPORT_METHOD(onOnce:(NSString *) path
103+
name:(NSString *) name
104+
callback:(RCTResponseSenderBlock) callback)
105+
{
106+
int eventType = [self eventTypeFromName:name];
107+
108+
FIRDatabaseReference *ref = [self getRefAtPath:path];
109+
[ref observeSingleEventOfType:eventType
110+
withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
111+
callback(@[[NSNull null], [self snapshotToDict:snapshot]]);
112+
}
113+
withCancelBlock:^(NSError * _Nonnull error) {
114+
NSLog(@"Error onDBEventOnce: %@", [error debugDescription]);
115+
callback(@[@{
116+
@"error": @"onceError",
117+
@"msg": [error debugDescription]
118+
}]);
119+
}];
120+
}
121+
```
122+
123+
Every native function (in either iOS or Android) is expected to accept a single callback as the final argument. The `onOnce` function accepts the path (as the first argument) and the name of the event we're interested in (such as `value`) and uses the Native SDK to set up the appropriate functionality. When the function has been called and completed, the callback is called with an error on failure and with success on success.
124+
125+
> An error response is considered one which the first argument is non-null. Therefore, to send a successful response, the first value when calling the callback should be null to indicate success.
126+
127+
## Adding functionality
128+
129+
// TODO

0 commit comments

Comments
 (0)