Share a File
+Click to select a file
+File stays on your device until downloaded
+Connected Users
+My Shared Files
+- No files shared yet
All Available Files
+- No files available
-
-Running Node.js application over Wifi and share with your friends.
-
-For previous mature version, please explore source code on
- kotlin branch and
- v0flutter branch.
-
-## Rewrite Progress
-
-[x] migrate kotlin service code
-[x] implement windows adapter for MethodChannel and EventChannel
-[ ] rewrite new design UI in dart
-[ ] implement linux adapter
-[ ] implement macosx adapter
-[ ] implement web+ios adapter
-
-## How to use
-
-- Platform/App market is online
- - click into platform or application page
- - click on the top-right cart icon button
- - select what you want to download
- - e.g. download platform `node-10.10.0`
- - download app `file-transfer`
- - edit app `file-transfer` platform value to `node-10.10.0`
- - start `file-transfer` by clicking play icon button
-- Create a new platform, for example named `node`
- - fill node url like `file:///sdcard/bin-node-v10.10.0` or `https://example.com/latest/arm/node`
- - click download button and wait for task complete
- - (NodeBase will copy the binary to its app zone and make it executable)
- - Wow; now we not only support node binary but also customized exectuables.
-- Create a new app, for example named `test` and its platform is `node`
- - click into the new app
- - download an app zip into for example `/sdcard/test.zip`
- - fill `Import / Export` text field with `/sdcard/test.zip`
- - click upload button and wait for task complete
- - (NodeBase will extract zip app as a app folder into app zone)
- - fill `Params` text field (for example, file manager need to config target folder as first param)
- - click `play` button to start node app
- - click `open in browser` button to open the app in a webview / `pop-out` button to open in external browser
- - click `stop` button to stop node app
-
-### App folder structure
-
-```
-/
+
+Platform to Build Sharable Application for Android
+
+Running Websocket application over Wifi and share with your friends.
+
+> WSTun: it is a base server on http/websocket with netty; and project name is "WSTun"
+
+The design is changed, we never use a pre-built binary of NodeJS to run server anymore.
+
+We run a native http/websocket with netty.
+
+Any JS client can register itself as a service so that it can be a control center of data.
+
+Others can connect as clients of the service and do more flexible things like file sharing, board gaming!
+
+> It is also a project enjoy vibe coding! (save lots of time)
diff --git a/analysis_options.yaml b/analysis_options.yaml
deleted file mode 100755
index d4e0f0c..0000000
--- a/analysis_options.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file configures the analyzer, which statically analyzes Dart code to
-# check for errors, warnings, and lints.
-#
-# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
-# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
-# invoked from the command line by running `flutter analyze`.
-
-# The following line activates a set of recommended lints for Flutter apps,
-# packages, and plugins designed to encourage good coding practices.
-include: package:flutter_lints/flutter.yaml
-
-linter:
- # The lint rules applied to this project can be customized in the
- # section below to disable rules from the `package:flutter_lints/flutter.yaml`
- # included above or to enable additional rules. A list of all available lints
- # and their documentation is published at https://dart.dev/lints.
- #
- # Instead of disabling a lint rule for the entire project in the
- # section below, it can also be suppressed for a single line of code
- # or a specific dart file by using the `// ignore: name_of_lint` and
- # `// ignore_for_file: name_of_lint` syntax on the line or in the file
- # producing the lint.
- rules:
- # avoid_print: false # Uncomment to disable the `avoid_print` rule
- # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
-
-# Additional information about this file can be found at
-# https://dart.dev/guides/language/analysis-options
diff --git a/android/.gitignore b/android/.gitignore
deleted file mode 100755
index 5d99765..0000000
--- a/android/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-gradle-wrapper.jar
-/.gradle
-/captures/
-/gradlew
-/gradlew.bat
-/local.properties
-GeneratedPluginRegistrant.java
-
-# Remember to never publicly share your keystore.
-# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
-key.properties
-**/*.keystore
-**/*.jks
diff --git a/android/README.md b/android/README.md
new file mode 100644
index 0000000..8f633da
--- /dev/null
+++ b/android/README.md
@@ -0,0 +1,166 @@
+# WSTun - WebSocket Tunnel Server
+
+An Android app that runs an HTTP/WebSocket server for service sharing in local networks.
+
+## Features
+
+### Server (Android App)
+- HTTP server with WebSocket support using Netty
+- Optional HTTPS with self-signed certificate
+- Service registration via WebSocket
+- HTTP request relay to connected services
+- Foreground service for background operation
+- Service management UI (view, kick)
+
+### Services
+- Connect via WebSocket and register endpoints
+- Define HTTP routes that relay to the service
+- Provide static resources (HTML/JS/CSS)
+- No server-side storage - everything relayed
+
+## Architecture
+
+```
+┌─────────────┐ WebSocket ┌─────────────────┐
+│ Service │◄───────────────────►│ WSTun App │
+│ Client │ │ (HTTP Server) │
+└─────────────┘ └────────┬────────┘
+ │ HTTP
+ ▼
+ ┌─────────────────┐
+ │ Web Browser │
+ │ (User) │
+ └─────────────────┘
+```
+
+1. Service connects via WebSocket and registers
+2. User accesses `http://server/[service]/main`
+3. Server relays request to service via WebSocket
+4. Service sends response via WebSocket
+5. Server sends HTTP response to user
+
+## Building
+
+### Android App
+
+```bash
+cd wstun
+./gradlew assembleDebug
+```
+
+### Service Clients
+
+```bash
+cd services/fileshare
+npm install
+
+cd services/chat
+npm install
+```
+
+## Usage
+
+### Start the Server
+
+1. Install the APK on an Android device
+2. Configure port and HTTPS option
+3. Tap "Start Server"
+4. Note the displayed IP address
+
+### Connect Services
+
+```bash
+# File sharing
+cd services/fileshare
+node client.js ws://192.168.1.100:8080/ws
+
+# Chat
+cd services/chat
+node client.js ws://192.168.1.100:8080/ws
+```
+
+### Access Services
+
+- Server info: `http://192.168.1.100:8080/`
+- FileShare: `http://192.168.1.100:8080/fileshare/main`
+- Chat: `http://192.168.1.100:8080/chat/main`
+
+## Protocol
+
+### Service Registration
+
+```json
+{
+ "type": "register",
+ "id": "unique-id",
+ "payload": {
+ "name": "servicename",
+ "type": "service-type",
+ "description": "Service description",
+ "endpoints": [
+ { "path": "/main", "method": "GET", "relay": true }
+ ],
+ "static_resources": {
+ "/main": "..."
+ }
+ }
+}
+```
+
+### HTTP Request Relay
+
+Server sends to service:
+```json
+{
+ "type": "http_request",
+ "payload": {
+ "request_id": "req-123",
+ "method": "GET",
+ "path": "/servicename/main",
+ "headers": { "Content-Type": "text/html" },
+ "body": "..."
+ }
+}
+```
+
+Service responds:
+```json
+{
+ "type": "http_response",
+ "payload": {
+ "request_id": "req-123",
+ "status": 200,
+ "headers": { "Content-Type": "text/html" },
+ "body": "..."
+ }
+}
+```
+
+## Included Services
+
+### FileShare
+
+Share files without server storage:
+- Virtual folder tree
+- File upload/download via browser
+- Relay mode for temporary sharing
+- All data flows through the client
+
+### Chat
+
+Real-time chat with rich messages:
+- Text, Card, and Poll message types
+- Broadcast to all or private messages
+- Abstract JSON format for custom rendering
+- Self-contained HTML/JS/CSS
+
+## Security Notes
+
+- HTTPS uses self-signed certificate (browser warning expected)
+- No authentication built-in (add as needed)
+- For local network use only
+- Services should validate inputs
+
+## License
+
+MIT
diff --git a/android/app/build.gradle b/android/app/build.gradle
old mode 100755
new mode 100644
index 4a42cf3..334f5b2
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,57 +1,48 @@
-plugins {
- id "com.android.application"
- id "kotlin-android"
- id "dev.flutter.flutter-gradle-plugin"
-}
-
-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file('local.properties')
-if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader('UTF-8') { reader ->
- localProperties.load(reader)
- }
-}
-
-def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
-if (flutterVersionCode == null) {
- flutterVersionCode = '1'
-}
-
-def flutterVersionName = localProperties.getProperty('flutter.versionName')
-if (flutterVersionName == null) {
- flutterVersionName = '1.0'
-}
-
-android {
- namespace "net.seven.nodebase.nodebase"
- compileSdkVersion flutter.compileSdkVersion
- ndkVersion flutter.ndkVersion
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
- }
-
- defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId "net.seven.nodebase.nodebase"
- // You can update the following values to match your application needs.
- // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
- minSdkVersion flutter.minSdkVersion
- targetSdkVersion flutter.targetSdkVersion
- versionCode flutterVersionCode.toInteger()
- versionName flutterVersionName
- }
-
- buildTypes {
- release {
- // TODO: Add your own signing config for the release build.
- // Signing with the debug keys for now, so `flutter run --release` works.
- signingConfig signingConfigs.debug
- }
- }
-}
-
-flutter {
- source '../..'
-}
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ namespace 'seven.lab.wstun'
+ compileSdk 34
+
+ defaultConfig {
+ applicationId "seven.lab.wstun"
+ minSdk 24
+ targetSdk 34
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ packagingOptions {
+ exclude 'META-INF/INDEX.LIST'
+ exclude 'META-INF/io.netty.versions.properties'
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'com.google.android.material:material:1.11.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.recyclerview:recyclerview:1.3.2'
+ implementation 'com.google.code.gson:gson:2.10.1'
+
+ // Netty
+ implementation 'io.netty:netty-all:4.1.100.Final'
+
+ // Bouncy Castle for SSL
+ implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
+ implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
+}
diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro
new file mode 100644
index 0000000..d52bf27
--- /dev/null
+++ b/android/app/proguard-rules.pro
@@ -0,0 +1,20 @@
+# Netty
+-keepclassmembers class io.netty.** { *; }
+-keep class io.netty.** { *; }
+-dontwarn io.netty.**
+
+# Bouncy Castle
+-keep class org.bouncycastle.** { *; }
+-dontwarn org.bouncycastle.**
+
+# Gson
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class com.google.gson.** { *; }
+-keep class * implements java.io.Serializable { *; }
+
+# Protocol classes
+-keep class seven.lab.wstun.protocol.** { *; }
+
+# Server classes
+-keep class seven.lab.wstun.server.** { *; }
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
deleted file mode 100755
index 8ffe024..0000000
--- a/android/app/src/debug/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-Create a chat room
+ +Click to open the chat page
+Loading...
+Create a file sharing room
+ +Click to open the file sharing page
+Loading...
+Share files with others
+Loading available rooms...
+Click to select a file
+File stays on your device until downloaded
+