mirror of
https://github.com/status-im/realm-js.git
synced 2025-02-23 03:38:16 +00:00
Use device IP addresses to connect to RPC host
It still only tries localhost for the simulator, but for devices, we now get a list of possible IP addresses to attempt to connect to before throw a more helpful exception. Resolves #284 and fixes #276
This commit is contained in:
parent
578e6b9742
commit
00b19d95b8
@ -13,6 +13,7 @@
|
|||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-console": 0,
|
||||||
"strict": 0
|
"strict": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import { NativeModules } from 'react-native';
|
||||||
import { keys, propTypes, objectTypes } from './constants';
|
import { keys, propTypes, objectTypes } from './constants';
|
||||||
import * as lists from './lists';
|
import * as lists from './lists';
|
||||||
import * as objects from './objects';
|
import * as objects from './objects';
|
||||||
@ -25,6 +26,7 @@ import * as results from './results';
|
|||||||
import * as rpc from './rpc';
|
import * as rpc from './rpc';
|
||||||
import * as util from './util';
|
import * as util from './util';
|
||||||
|
|
||||||
|
const {debugHosts, debugPort} = NativeModules.Realm;
|
||||||
const listenersKey = Symbol();
|
const listenersKey = Symbol();
|
||||||
|
|
||||||
rpc.registerTypeConverter(objectTypes.LIST, lists.create);
|
rpc.registerTypeConverter(objectTypes.LIST, lists.create);
|
||||||
@ -162,5 +164,24 @@ Object.defineProperties(Realm, {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// The session ID refers to the Realm constructor object in the RPC server.
|
for (let i = 0, len = debugHosts.length; i < len; i++) {
|
||||||
Realm[keys.id] = rpc.createSession();
|
try {
|
||||||
|
// The session ID refers to the Realm constructor object in the RPC server.
|
||||||
|
Realm[keys.id] = rpc.createSession(debugHosts[i] + ':' + debugPort);
|
||||||
|
break;
|
||||||
|
} catch (e) {
|
||||||
|
// Only throw exception after all hosts have been tried.
|
||||||
|
if (i < len - 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the original exception for debugging purposes.
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
'Realm failed to connect to the embedded debug server inside the app. ' +
|
||||||
|
'If attempting to use Chrome debugging from a device, ensure the device is ' +
|
||||||
|
'reachable on the same network as this machine.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,12 +21,11 @@
|
|||||||
import * as base64 from './base64';
|
import * as base64 from './base64';
|
||||||
import { keys, objectTypes } from './constants';
|
import { keys, objectTypes } from './constants';
|
||||||
|
|
||||||
const DEVICE_HOST = 'localhost:8082';
|
|
||||||
|
|
||||||
const {id: idKey, realm: realmKey} = keys;
|
const {id: idKey, realm: realmKey} = keys;
|
||||||
const typeConverters = {};
|
const typeConverters = {};
|
||||||
|
|
||||||
let XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest;
|
let XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest;
|
||||||
|
let sessionHost;
|
||||||
let sessionId;
|
let sessionId;
|
||||||
|
|
||||||
// Check if XMLHttpRequest has been overridden, and get the native one if that's the case.
|
// Check if XMLHttpRequest has been overridden, and get the native one if that's the case.
|
||||||
@ -45,8 +44,17 @@ export function registerTypeConverter(type, handler) {
|
|||||||
typeConverters[type] = handler;
|
typeConverters[type] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSession() {
|
export function createSession(host) {
|
||||||
sessionId = sendRequest('create_session');
|
let oldHost = sessionHost;
|
||||||
|
|
||||||
|
try {
|
||||||
|
sessionHost = host;
|
||||||
|
sessionId = sendRequest('create_session');
|
||||||
|
} catch (e) {
|
||||||
|
sessionHost = oldHost;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
return sessionId;
|
return sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,11 +166,15 @@ function deserializeDict(realmId, info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sendRequest(command, data) {
|
function sendRequest(command, data) {
|
||||||
|
if (!sessionHost) {
|
||||||
|
throw new Error('Must first create RPC session with a valid host');
|
||||||
|
}
|
||||||
|
|
||||||
data = Object.assign({}, data, sessionId ? {sessionId} : null);
|
data = Object.assign({}, data, sessionId ? {sessionId} : null);
|
||||||
|
|
||||||
let body = JSON.stringify(data);
|
let body = JSON.stringify(data);
|
||||||
let request = new XMLHttpRequest();
|
let request = new XMLHttpRequest();
|
||||||
let url = 'http://' + DEVICE_HOST + '/' + command;
|
let url = 'http://' + sessionHost + '/' + command;
|
||||||
|
|
||||||
request.open('POST', url, false);
|
request.open('POST', url, false);
|
||||||
request.send(body);
|
request.send(body);
|
||||||
|
@ -24,7 +24,11 @@
|
|||||||
#import "shared_realm.hpp"
|
#import "shared_realm.hpp"
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
#import <arpa/inet.h>
|
||||||
#import <dlfcn.h>
|
#import <dlfcn.h>
|
||||||
|
#import <ifaddrs.h>
|
||||||
|
#import <netdb.h>
|
||||||
|
#import <net/if.h>
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#import <GCDWebServer/Core/GCDWebServer.h>
|
#import <GCDWebServer/Core/GCDWebServer.h>
|
||||||
@ -32,6 +36,8 @@
|
|||||||
#import <GCDWebServer/Responses/GCDWebServerDataResponse.h>
|
#import <GCDWebServer/Responses/GCDWebServerDataResponse.h>
|
||||||
#import <GCDWebServer/Responses/GCDWebServerErrorResponse.h>
|
#import <GCDWebServer/Responses/GCDWebServerErrorResponse.h>
|
||||||
#import "rpc.hpp"
|
#import "rpc.hpp"
|
||||||
|
|
||||||
|
#define WEB_SERVER_PORT 8082
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@interface NSObject ()
|
@interface NSObject ()
|
||||||
@ -118,6 +124,23 @@ extern "C" JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executo
|
|||||||
return dispatch_get_main_queue();
|
return dispatch_get_main_queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDictionary *)constantsToExport {
|
||||||
|
#if DEBUG
|
||||||
|
#if TARGET_IPHONE_SIMULATOR
|
||||||
|
NSArray *hosts = @[@"localhost"];
|
||||||
|
#else
|
||||||
|
NSArray *hosts = [self getIPAddresses];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return @{
|
||||||
|
@"debugHosts": hosts,
|
||||||
|
@"debugPort": @(WEB_SERVER_PORT),
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
return @{};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
- (void)addListenerForEvent:(NSString *)eventName handler:(RealmReactEventHandler)handler {
|
- (void)addListenerForEvent:(NSString *)eventName handler:(RealmReactEventHandler)handler {
|
||||||
NSMutableOrderedSet *handlers = _eventHandlers[eventName];
|
NSMutableOrderedSet *handlers = _eventHandlers[eventName];
|
||||||
if (!handlers) {
|
if (!handlers) {
|
||||||
@ -138,6 +161,60 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
- (NSArray *)getIPAddresses {
|
||||||
|
static const char * const wifiInterface = "en0";
|
||||||
|
|
||||||
|
struct ifaddrs *ifaddrs;
|
||||||
|
if (getifaddrs(&ifaddrs)) {
|
||||||
|
NSLog(@"Failed to get interface addresses: %s", strerror(errno));
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableArray *ipAddresses = [[NSMutableArray alloc] init];
|
||||||
|
char host[INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
for (struct ifaddrs *ifaddr = ifaddrs; ifaddr; ifaddr = ifaddr->ifa_next) {
|
||||||
|
if ((ifaddr->ifa_flags & IFF_LOOPBACK) || !(ifaddr->ifa_flags & IFF_UP)) {
|
||||||
|
// Ignore loopbacks and interfaces that aren't up.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr *addr = ifaddr->ifa_addr;
|
||||||
|
if (addr->sa_family == AF_INET) {
|
||||||
|
// Ignore link-local ipv4 addresses.
|
||||||
|
in_addr_t sin_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
|
||||||
|
if (IN_LOOPBACK(sin_addr) || IN_LINKLOCAL(sin_addr) || IN_ZERONET(sin_addr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr->sa_family == AF_INET6) {
|
||||||
|
// Ignore link-local ipv6 addresses.
|
||||||
|
struct in6_addr *sin6_addr = &((struct sockaddr_in6 *)addr)->sin6_addr;
|
||||||
|
if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(sin6_addr)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Ignore addresses that are not ipv4 or ipv6.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(ifaddr->ifa_name, wifiInterface)) {
|
||||||
|
// Ignore non-wifi addresses.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (int error = getnameinfo(addr, addr->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) {
|
||||||
|
NSLog(@"Couldn't resolve host name for address: %s", gai_strerror(error));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ipAddresses addObject:@(host)];
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddrs);
|
||||||
|
return [ipAddresses copy];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)startRPC {
|
- (void)startRPC {
|
||||||
[GCDWebServer setLogLevel:3];
|
[GCDWebServer setLogLevel:3];
|
||||||
_webServer = [[GCDWebServer alloc] init];
|
_webServer = [[GCDWebServer alloc] init];
|
||||||
@ -178,7 +255,7 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
|||||||
return response;
|
return response;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[_webServer startWithPort:8082 bonjourName:nil];
|
[_webServer startWithPort:WEB_SERVER_PORT bonjourName:nil];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +101,7 @@ public class RealmAnalytics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldExecute() {
|
public static boolean shouldExecute() {
|
||||||
return System.getenv("REALM_DISABLE_ANALYTICS") == null
|
return System.getenv("REALM_DISABLE_ANALYTICS") == null && isRunningOnEmulator();
|
||||||
&& (isRunningOnGenymotion() || isRunningOnStockEmulator());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send() {
|
private void send() {
|
||||||
@ -152,12 +151,9 @@ public class RealmAnalytics {
|
|||||||
.replaceAll("%OS_VERSION%", System.getProperty("os.version"));
|
.replaceAll("%OS_VERSION%", System.getProperty("os.version"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isRunningOnGenymotion() {
|
public static boolean isRunningOnEmulator() {
|
||||||
return Build.FINGERPRINT.contains("vbox");
|
// Check if running in Genymotion or on the stock emulator.
|
||||||
}
|
return Build.FINGERPRINT.contains("vbox") || Build.FINGERPRINT.contains("generic");
|
||||||
|
|
||||||
private static boolean isRunningOnStockEmulator() {
|
|
||||||
return Build.FINGERPRINT.contains("generic");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,8 +9,15 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|||||||
import com.facebook.soloader.SoLoader;
|
import com.facebook.soloader.SoLoader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.NetworkInterface;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
@ -58,7 +65,18 @@ public class RealmReactModule extends ReactContextBaseJavaModule {
|
|||||||
if (!isContextInjected()) {
|
if (!isContextInjected()) {
|
||||||
startWebServer();
|
startWebServer();
|
||||||
}
|
}
|
||||||
return Collections.EMPTY_MAP;
|
|
||||||
|
List<String> hosts;
|
||||||
|
if (RealmAnalytics.isRunningOnEmulator()) {
|
||||||
|
hosts = Arrays.asList(new String[]{"localhost"});
|
||||||
|
} else {
|
||||||
|
hosts = getIPAddresses();
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, Object> constants = new HashMap<String, Object>();
|
||||||
|
constants.put("debugHosts", hosts);
|
||||||
|
constants.put("debugPort", DEFAULT_PORT);
|
||||||
|
return constants;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,6 +85,35 @@ public class RealmReactModule extends ReactContextBaseJavaModule {
|
|||||||
stopWebServer();
|
stopWebServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getIPAddresses() {
|
||||||
|
ArrayList<String> ipAddresses = new ArrayList<String>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||||
|
|
||||||
|
while (networkInterfaces.hasMoreElements()) {
|
||||||
|
NetworkInterface networkInterface = networkInterfaces.nextElement();
|
||||||
|
if (networkInterface.isLoopback() || !networkInterface.isUp()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
|
||||||
|
while (addresses.hasMoreElements()) {
|
||||||
|
InetAddress address = addresses.nextElement();
|
||||||
|
if (address.isLoopbackAddress() || address.isLinkLocalAddress() || address.isAnyLocalAddress()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipAddresses.add(address.getHostAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (SocketException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipAddresses;
|
||||||
|
}
|
||||||
|
|
||||||
private void startWebServer() {
|
private void startWebServer() {
|
||||||
setupChromeDebugModeRealmJsContext();
|
setupChromeDebugModeRealmJsContext();
|
||||||
webServer = new AndroidWebServer(DEFAULT_PORT);
|
webServer = new AndroidWebServer(DEFAULT_PORT);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user