Skip to content

Commit 4b96940

Browse files
committed
[futurepress#95] Android: Add native methods to obtain the currently running service
1 parent d381d45 commit 4b96940

File tree

7 files changed

+87
-26
lines changed

7 files changed

+87
-26
lines changed

README.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ and [old][Old Architecture] RN architectures.
8989
- [extractBundledAssets()] — Extracts bundled assets into a regular folder
9090
(Android-specific).
9191
- [getActiveServer()] — Gets currently active, starting, or stopping
92-
server instance, if any.
92+
server instance, if any, according to the TS layer data.
93+
- [getActiveServerId()] — Gets ID of the currently active, starting, or
94+
stopping server instance, if any, according to the Native layer data.
9395
- [resolveAssetsPath()] — Resolves relative paths for bundled assets.
9496
- [ERROR_LOG_FILE] — Location of the error log file.
9597
- [STATES] — Enumerates possible states of [Server] instance.
@@ -551,6 +553,13 @@ within `options` argument:
551553
special `hostname` values to ask the library to automatically select
552554
appropriate non-local address._
553555
556+
- `id` — **number** — Optional. Allows to enforce a specific ID,
557+
used to communicate with the server instance within the Native layer, thus
558+
it allows to re-connect to an existing native server instance.
559+
See [getActiveServerId()] for details, and also pay attention to set
560+
the correct `state` option value in this case. By default is is assigned
561+
by the library.
562+
554563
- `nonLocal` — **boolean** — Optional. By default, if `hostname`
555564
option was not provided, the server starts at the "`127.0.0.1`" (loopback)
556565
address, and it is only accessible within the host app.
@@ -565,6 +574,11 @@ within `options` argument:
565574
- `port` — **number** — Optional. The port at which to start the server.
566575
If 0 (default) an available port will be automatically selected.
567576
577+
- `state` — [STATES] — Optional. Allows to enforce initial
578+
server state value, which is needed when connecting to an existing
579+
native server instance with help of the `id` option.
580+
By default it is set to `STATES.INACTIVE`.
581+
568582
- `stopInBackground` — **boolean** — Optional.
569583
570584
By default, the server continues to work as usual when its host app enters
@@ -795,17 +809,43 @@ This is an Android-specific function; it does nothing on other platforms.
795809
796810
### getActiveServer()
797811
[getActiveServer()]: #getactiveserver
798-
```js
812+
```ts
799813
import {getActiveServer} from '@dr.pogodin/react-native-static-server';
800814
801-
getActiveServer(): Server;
815+
getActiveServer(): Server | undefined;
802816
```
803817
Returns currently active, starting, or stopping [Server] instance, if any exist
804818
in the app. It does not return, however, any inactive server instance which has
805819
been stopped automatically because of `stopInBackground` option, when the app
806820
entered background, and might be automatically started in future if the app
807821
enters foreground again prior to an explicit [.stop()] call for that instance.
808822
823+
**NOTE:** The result of this function is based on the TypeScript layer data
824+
(that's why it is synchronous), in contrast to the [getActiveServerId()]
825+
function below, which calls into the Native layer, and returns ID of the active
826+
server based on that.
827+
828+
### getActiveServerId()
829+
[getActiveServerId()]: #getactiveserverid
830+
```ts
831+
import {getActiveServerId} from '@dr.pogodin/react-native-static-server';
832+
833+
getActiveServerId(): Promise<number | null>;
834+
```
835+
Returns ID of the currently active, starting, or stopping server instance,
836+
if any exist in the Native layer.
837+
838+
This function is provided in response to
839+
[the ticket #95](https://github.com/birdofpreyru/react-native-static-server/issues/95),
840+
which asked to provide a way to re-connect to a server running within the Native
841+
layer after a reset of TypeScript RN layer. The ID returned by this function can
842+
be passed in into [Server] instance [constructor()] to create server instance
843+
communicating to the existing native layer server.
844+
845+
**NOTE:** It is different from [getActiveServer()] function above, which
846+
returns the acurrently active, starting, or stopping [Server] instance based on
847+
TypeScript layer data.
848+
809849
### resolveAssetsPath()
810850
[resolveAssetsPath()]: #resolveassetspath
811851
```ts

android/src/main/java/com/drpogodin/reactnativestaticserver/ReactNativeStaticServerModule.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ class ReactNativeStaticServerModule internal constructor(context: ReactApplicati
3434
return constants
3535
}
3636

37+
@ReactMethod
38+
override fun getActiveServerId(promise: Promise) {
39+
promise.resolve(server?.id)
40+
}
41+
3742
@ReactMethod
3843
override fun getLocalIpAddress(promise: Promise) {
3944
try {
@@ -90,10 +95,8 @@ class ReactNativeStaticServerModule internal constructor(context: ReactApplicati
9095
pendingPromise = promise
9196
val emitter: DeviceEventManagerModule.RCTDeviceEventEmitter = getReactApplicationContext()
9297
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
93-
server = Server(
94-
configPath,
95-
errlogPath
96-
) { signal, details ->
98+
99+
server = Server(id, configPath, errlogPath) { signal, details ->
97100
if (signal !== Server.LAUNCHED) server = null
98101
if (pendingPromise == null) {
99102
val event = Arguments.createMap()

android/src/main/java/com/lighttpd/Server.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import java.util.function.BiConsumer
2222
* if any, has terminated or crashed before launching a new one!
2323
*/
2424
class Server(
25+
var id: Double,
2526
var configPath: String,
2627
var errlogPath: String,
2728
private val signalConsumer: BiConsumer<String, String?>

android/src/oldarch/ReactNativeStaticServerSpec.kt

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
66

77
abstract class ReactNativeStaticServerSpec internal constructor(context: ReactApplicationContext) :
88
ReactContextBaseJavaModule(context) {
9-
abstract override fun getName(): String
10-
abstract fun getTypedExportedConstants(): Map<String, Any>
9+
abstract override fun getName(): String
10+
abstract fun getTypedExportedConstants(): Map<String, Any>
1111

12-
override fun getConstants(): Map<String, Any>? {
13-
return getTypedExportedConstants()
14-
}
12+
abstract fun getActiveServerId(promise: Promise)
1513

16-
abstract fun start(
17-
id: Double, configPath: String?, errlogPath: String?, promise: Promise?)
14+
override fun getConstants(): Map<String, Any>? {
15+
return getTypedExportedConstants()
16+
}
1817

19-
abstract fun getLocalIpAddress(promise: Promise)
20-
abstract fun getOpenPort(address: String, promise: Promise)
21-
abstract fun stop(promise: Promise?)
18+
abstract fun start(
19+
id: Double,
20+
configPath: String,
21+
errlogPath: String,
22+
promise: Promise)
23+
24+
abstract fun getLocalIpAddress(promise: Promise)
25+
abstract fun getOpenPort(address: String, promise: Promise)
26+
abstract fun stop(promise: Promise?)
2227

2328
abstract fun addListener(eventName: String?)
2429

src/NativeReactNativeStaticServer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export interface Spec extends TurboModule {
1111

1212
addListener(eventName: string): void;
1313

14+
getActiveServerId(): Promise<number | null>;
15+
1416
removeListeners(count: number): void;
1517

1618
start(id: number, configPath: string, errlogPath: string): Promise<string>;

src/ReactNativeStaticServer.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { NativeModules, Platform } from 'react-native';
22

3+
import type { Spec } from './NativeReactNativeStaticServer';
4+
35
const LINKING_ERROR =
46
`The package '@dr.pogodin/react-native-static-server' doesn't seem to be linked. Make sure: \n\n` +
57
Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
@@ -24,4 +26,4 @@ const ReactNativeStaticServer = ReactNativeStaticServerModule
2426
},
2527
);
2628

27-
export default ReactNativeStaticServer;
29+
export default ReactNativeStaticServer as Spec;

src/index.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,21 +93,15 @@ class StaticServer {
9393
_stopInBackground: boolean;
9494
_port: number;
9595

96-
_state: STATES = STATES.INACTIVE;
96+
_state: STATES;
9797
_stateChangeEmitter = new Emitter<[STATES, string, Error | undefined]>();
9898

9999
// TODO: It will be better to use UUID, but I believe "uuid" library
100100
// I would use won't work in RN without additional workarounds applied
101101
// to RN setup to get around some issues with randombytes support in
102102
// RN JS engine. Anyway, it should be double-checked later, but using
103103
// timestamps as ID will do for now.
104-
105-
// NOTE: For some reasons RN-Windows corrupts large numbers sent
106-
// as event arguments across JS / Native boundary.
107-
// Everything smaller than 65535 seems to work fine, so let's just
108-
// truncate these IDs for now.
109-
// See: https://github.com/microsoft/react-native-windows/issues/11322
110-
_id = Date.now() % 65535;
104+
_id: number;
111105

112106
// It is used to serialize state change requests, thus ensuring that parallel
113107
// requests to start / stop the server won't result in a corrupt state.
@@ -166,9 +160,17 @@ class StaticServer {
166160
fileDir,
167161
hostname,
168162

163+
// NOTE: For some reasons RN-Windows corrupts large numbers sent
164+
// as event arguments across JS / Native boundary.
165+
// Everything smaller than 65535 seems to work fine, so let's just
166+
// truncate these IDs for now.
167+
// See: https://github.com/microsoft/react-native-windows/issues/11322
168+
id = Date.now() % 65535,
169+
169170
/* DEPRECATED */ nonLocal = false,
170171

171172
port = 0,
173+
state = STATES.INACTIVE,
172174
stopInBackground = false,
173175

174176
/* DEPRECATED */ webdav,
@@ -177,22 +179,26 @@ class StaticServer {
177179
errorLog?: boolean | ErrorLogOptions;
178180
fileDir: string;
179181
hostname?: string;
182+
id?: number;
180183

181184
/* DEPRECATED */ nonLocal?: boolean;
182185

183186
port?: number;
187+
state?: STATES;
184188
stopInBackground?: boolean;
185189

186190
/* DEPRECATED */ webdav?: string[];
187191
}) {
188192
if (errorLog) this._errorLog = errorLog === true ? {} : errorLog;
189193

190194
this._extraConfig = extraConfig;
195+
this._id = id;
191196

192197
this._nonLocal = nonLocal;
193198
this._hostname = hostname || (nonLocal ? '' : LOOPBACK_ADDRESS);
194199

195200
this._port = port;
201+
this._state = state;
196202
this._stopInBackground = stopInBackground;
197203

198204
if (!fileDir) throw Error('`fileDir` MUST BE a non-empty string');
@@ -422,3 +428,5 @@ export function getActiveServer() {
422428
server.state !== STATES.INACTIVE && server.state !== STATES.CRASHED,
423429
);
424430
}
431+
432+
export const getActiveServerId = ReactNativeStaticServer.getActiveServerId;

0 commit comments

Comments
 (0)