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"
|
||||
},
|
||||
"rules": {
|
||||
"no-console": 0,
|
||||
"strict": 0
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { NativeModules } from 'react-native';
|
||||
import { keys, propTypes, objectTypes } from './constants';
|
||||
import * as lists from './lists';
|
||||
import * as objects from './objects';
|
||||
@ -25,6 +26,7 @@ import * as results from './results';
|
||||
import * as rpc from './rpc';
|
||||
import * as util from './util';
|
||||
|
||||
const {debugHosts, debugPort} = NativeModules.Realm;
|
||||
const listenersKey = Symbol();
|
||||
|
||||
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.
|
||||
Realm[keys.id] = rpc.createSession();
|
||||
for (let i = 0, len = debugHosts.length; i < len; i++) {
|
||||
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 { keys, objectTypes } from './constants';
|
||||
|
||||
const DEVICE_HOST = 'localhost:8082';
|
||||
|
||||
const {id: idKey, realm: realmKey} = keys;
|
||||
const typeConverters = {};
|
||||
|
||||
let XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest;
|
||||
let sessionHost;
|
||||
let sessionId;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
export function createSession() {
|
||||
sessionId = sendRequest('create_session');
|
||||
export function createSession(host) {
|
||||
let oldHost = sessionHost;
|
||||
|
||||
try {
|
||||
sessionHost = host;
|
||||
sessionId = sendRequest('create_session');
|
||||
} catch (e) {
|
||||
sessionHost = oldHost;
|
||||
throw e;
|
||||
}
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
@ -158,11 +166,15 @@ function deserializeDict(realmId, info) {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
let body = JSON.stringify(data);
|
||||
let request = new XMLHttpRequest();
|
||||
let url = 'http://' + DEVICE_HOST + '/' + command;
|
||||
let url = 'http://' + sessionHost + '/' + command;
|
||||
|
||||
request.open('POST', url, false);
|
||||
request.send(body);
|
||||
|
@ -24,7 +24,11 @@
|
||||
#import "shared_realm.hpp"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <dlfcn.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
#import <net/if.h>
|
||||
|
||||
#if DEBUG
|
||||
#import <GCDWebServer/Core/GCDWebServer.h>
|
||||
@ -32,6 +36,8 @@
|
||||
#import <GCDWebServer/Responses/GCDWebServerDataResponse.h>
|
||||
#import <GCDWebServer/Responses/GCDWebServerErrorResponse.h>
|
||||
#import "rpc.hpp"
|
||||
|
||||
#define WEB_SERVER_PORT 8082
|
||||
#endif
|
||||
|
||||
@interface NSObject ()
|
||||
@ -118,6 +124,23 @@ extern "C" JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executo
|
||||
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 {
|
||||
NSMutableOrderedSet *handlers = _eventHandlers[eventName];
|
||||
if (!handlers) {
|
||||
@ -138,6 +161,60 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
||||
}
|
||||
|
||||
#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 {
|
||||
[GCDWebServer setLogLevel:3];
|
||||
_webServer = [[GCDWebServer alloc] init];
|
||||
@ -178,7 +255,7 @@ RCT_REMAP_METHOD(emit, emitEvent:(NSString *)eventName withObject:(id)object) {
|
||||
return response;
|
||||
}];
|
||||
|
||||
[_webServer startWithPort:8082 bonjourName:nil];
|
||||
[_webServer startWithPort:WEB_SERVER_PORT bonjourName:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,7 @@ public class RealmAnalytics {
|
||||
}
|
||||
|
||||
public static boolean shouldExecute() {
|
||||
return System.getenv("REALM_DISABLE_ANALYTICS") == null
|
||||
&& (isRunningOnGenymotion() || isRunningOnStockEmulator());
|
||||
return System.getenv("REALM_DISABLE_ANALYTICS") == null && isRunningOnEmulator();
|
||||
}
|
||||
|
||||
private void send() {
|
||||
@ -152,12 +151,9 @@ public class RealmAnalytics {
|
||||
.replaceAll("%OS_VERSION%", System.getProperty("os.version"));
|
||||
}
|
||||
|
||||
private static boolean isRunningOnGenymotion() {
|
||||
return Build.FINGERPRINT.contains("vbox");
|
||||
}
|
||||
|
||||
private static boolean isRunningOnStockEmulator() {
|
||||
return Build.FINGERPRINT.contains("generic");
|
||||
public static boolean isRunningOnEmulator() {
|
||||
// Check if running in Genymotion or on the stock emulator.
|
||||
return Build.FINGERPRINT.contains("vbox") || Build.FINGERPRINT.contains("generic");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,8 +9,15 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
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.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@ -58,7 +65,18 @@ public class RealmReactModule extends ReactContextBaseJavaModule {
|
||||
if (!isContextInjected()) {
|
||||
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
|
||||
@ -67,6 +85,35 @@ public class RealmReactModule extends ReactContextBaseJavaModule {
|
||||
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() {
|
||||
setupChromeDebugModeRealmJsContext();
|
||||
webServer = new AndroidWebServer(DEFAULT_PORT);
|
||||
|
Loading…
x
Reference in New Issue
Block a user