Skip to content

Commit

Permalink
Switching between "hash" and "path" routing URL strategy (#110)
Browse files Browse the repository at this point in the history
* Page route URL strategy can be changed

* The same behaviour for hash and path strategies

* defaultRouteUrlStrategy is hash

* Index page notion
  • Loading branch information
FeodorFitsner authored Jul 27, 2022
1 parent f39312b commit 133d75f
Show file tree
Hide file tree
Showing 18 changed files with 127 additions and 32 deletions.
13 changes: 10 additions & 3 deletions client/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:url_strategy/url_strategy.dart';

import '../utils/platform_utils_non_web.dart'
if (dart.library.js) "../utils/platform_utils_web.dart";
import '../utils/session_store_non_web.dart'
if (dart.library.js) "../utils/session_store_web.dart";
import 'controls/create_control.dart';
import 'models/app_state.dart';
import 'models/page_view_model.dart';
import 'reducers.dart';
import 'session_store/session_store.dart'
if (dart.library.io) "session_store/session_store_io.dart"
if (dart.library.js) "session_store/session_store_js.dart";
import 'web_socket_client.dart';

const bool isProduction = bool.fromEnvironment('dart.vm.product');
Expand All @@ -35,6 +37,11 @@ void main([List<String>? args]) async {

if (kIsWeb) {
debugPrint("Flet View is running in Web mode");
var routeUrlStrategy = getRouteUrlStrategy();
debugPrint("URL Strategy: $routeUrlStrategy");
if (routeUrlStrategy == "path") {
setPathUrlStrategy();
}
} else if ((Platform.isWindows || Platform.isMacOS || Platform.isLinux) &&
!kDebugMode) {
debugPrint("Flet View is running in Desktop mode");
Expand Down
10 changes: 4 additions & 6 deletions client/lib/reducers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@ import 'package:flet_view/protocol/update_control_props_payload.dart';
import 'package:flet_view/web_socket_client.dart';
import 'package:flutter/cupertino.dart';

import '../utils/platform_utils.dart'
if (dart.library.io) "../utils/platform_utils_io.dart"
if (dart.library.js) "../utils/platform_utils_js.dart";
import '../utils/platform_utils_non_web.dart'
if (dart.library.js) "../utils/platform_utils_web.dart";
import '../utils/session_store_non_web.dart'
if (dart.library.js) "../utils/session_store_web.dart";
import 'actions.dart';
import 'models/app_state.dart';
import 'models/control.dart';
import 'session_store/session_store.dart'
if (dart.library.io) "session_store/session_store_io.dart"
if (dart.library.js) "session_store/session_store_js.dart";
import 'utils/desktop.dart';
import 'utils/uri.dart';

Expand Down
9 changes: 0 additions & 9 deletions client/lib/session_store/session_store.dart

This file was deleted.

3 changes: 0 additions & 3 deletions client/lib/utils/platform_utils.dart

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
bool isProgressiveWebApp() {
return false;
}

String getRouteUrlStrategy() {
return "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,9 @@ bool isProgressiveWebApp() {
window.matchMedia('(display-mode: fullscreen)').matches ||
window.matchMedia('(display-mode: minimal-ui)').matches;
}

String getRouteUrlStrategy() {
var meta =
document.head?.querySelector("meta[name='flet-route-url-strategy']");
return meta != null ? meta.attributes["content"]! : "";
}
File renamed without changes.
File renamed without changes.
9 changes: 8 additions & 1 deletion client/lib/utils/uri.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import 'strings.dart';

String getWebPageName(Uri uri) {
return trim(uri.path, "/");
var urlPath = trim(uri.path, "/");
if (urlPath != "") {
var pathParts = urlPath.split("/");
if (pathParts.length > 1) {
urlPath = pathParts.sublist(0, 2).join("/");
}
}
return urlPath;
}

String getWebSocketEndpoint(Uri uri) {
Expand Down
19 changes: 19 additions & 0 deletions client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: "direct main"
description:
Expand All @@ -137,6 +142,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
lints:
dependency: transitive
description:
Expand Down Expand Up @@ -247,6 +259,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
url_strategy:
dependency: "direct main"
description:
name: url_strategy
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
vector_math:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions client/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependencies:
window_manager: ^0.2.5
http: ^0.13.3
collection: ^1.16.0
url_strategy: ^0.2.0

dev_dependencies:
flutter_test:
Expand Down
7 changes: 7 additions & 0 deletions client/test/utils/uri_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ void main() {
expect(
getWebPageName(Uri.parse('http://localhost:8550/p/test/')), "p/test");
expect(getWebPageName(Uri.parse('http://localhost:8550/p/test')), "p/test");
expect(getWebPageName(Uri.parse('http://localhost:8550/aaa')), "aaa");
expect(getWebPageName(Uri.parse('http://localhost:8550/p/test/store')),
"p/test");
expect(
getWebPageName(
Uri.parse('http://localhost:8550/p/test/store/products/1')),
"p/test");
expect(getWebPageName(Uri.parse('http://localhost:8550/')), "");
expect(getWebPageName(Uri.parse('http://localhost:8550/#/')), "");
});
Expand Down
3 changes: 3 additions & 0 deletions client/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>

<!-- Flet specific -->
<meta name="flet-route-url-strategy" content="%FLET_ROUTE_URL_STRATEGY%">

<title>Flet</title>
<link rel="manifest" href="manifest.json">

Expand Down
15 changes: 13 additions & 2 deletions sdk/python/flet/flet.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def page(
view: AppViewer = WEB_BROWSER,
assets_dir=None,
web_renderer="canvaskit",
route_url_strategy="hash",
):
conn = _connect_internal(
page_name=name,
Expand All @@ -52,6 +53,7 @@ def page(
permissions=permissions,
assets_dir=assets_dir,
web_renderer=web_renderer,
route_url_strategy=route_url_strategy,
)
print("Page URL:", conn.page_url)
page = Page(conn, constants.ZERO_SESSION)
Expand All @@ -71,6 +73,7 @@ def app(
view: AppViewer = FLET_APP,
assets_dir=None,
web_renderer="canvaskit",
route_url_strategy="hash",
):

if target == None:
Expand All @@ -84,6 +87,7 @@ def app(
session_handler=target,
assets_dir=assets_dir,
web_renderer=web_renderer,
route_url_strategy=route_url_strategy,
)
print("App URL:", conn.page_url)

Expand Down Expand Up @@ -139,6 +143,7 @@ def _connect_internal(
session_handler=None,
assets_dir=None,
web_renderer=None,
route_url_strategy=None,
):
if share and server == None:
server = constants.HOSTED_SERVICE_URL
Expand All @@ -151,7 +156,9 @@ def _connect_internal(
# page with a custom port starts detached process
attached = False if not is_app and port != 0 else True

port = _start_flet_server(port, attached, assets_dir, web_renderer)
port = _start_flet_server(
port, attached, assets_dir, web_renderer, route_url_strategy
)
server = f"http://127.0.0.1:{port}"

connected = threading.Event()
Expand Down Expand Up @@ -219,7 +226,7 @@ def _on_ws_failed_connect():
return conn


def _start_flet_server(port, attached, assets_dir, web_renderer):
def _start_flet_server(port, attached, assets_dir, web_renderer, route_url_strategy):

if port == 0:
port = _get_free_tcp_port()
Expand Down Expand Up @@ -263,6 +270,10 @@ def _start_flet_server(port, attached, assets_dir, web_renderer):
logging.info(f"Web renderer configured: {web_renderer}")
fletd_env["FLET_WEB_RENDERER"] = web_renderer

if route_url_strategy != None:
logging.info(f"Route URL strategy configured: {route_url_strategy}")
fletd_env["FLET_ROUTE_URL_STRATEGY"] = route_url_strategy

args = [fletd_path, "--port", str(port)]

creationflags = 0
Expand Down
13 changes: 11 additions & 2 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ const (
defaultMasterSecretKey = "master_secret_key"

// development
staticRootDir = "STATIC_ROOT_DIR"
webRenderer = "WEB_RENDERER"
staticRootDir = "STATIC_ROOT_DIR"
webRenderer = "WEB_RENDERER"
routeUrlStrategy = "ROUTE_URL_STRATEGY"
defaultRouteUrlStrategy = "hash"
)

func init() {
Expand Down Expand Up @@ -124,6 +126,9 @@ func init() {
// security
viper.SetDefault(cookieSecret, getSecretManagerValue(cookieSecret, defaultCookieSecret))
viper.SetDefault(masterSecretKey, getSecretManagerValue(masterSecretKey, defaultMasterSecretKey))

// development
viper.SetDefault(routeUrlStrategy, defaultRouteUrlStrategy)
}

func getSecretManagerValue(name string, defaultValue string) string {
Expand Down Expand Up @@ -288,3 +293,7 @@ func StaticRootDir() string {
func WebRenderer() string {
return viper.GetString(webRenderer)
}

func RouteUrlStrategy() string {
return viper.GetString(routeUrlStrategy)
}
6 changes: 6 additions & 0 deletions server/model/page_name.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const (
type PageName struct {
Account string
Name string
IsIndex bool
}

func ParsePageName(pageName string) (*PageName, error) {
Expand All @@ -27,6 +28,7 @@ func ParsePageName(pageName string) (*PageName, error) {
return &PageName{
Account: publicAccount,
Name: indexPage,
IsIndex: true,
}, nil
}

Expand Down Expand Up @@ -62,6 +64,10 @@ func ParsePageName(pageName string) (*PageName, error) {
return nil, fmt.Errorf("page name exceeds the maximum allowed size of %d symbols", maxSlugSize)
}

if p.Account == publicAccount && p.Name == indexPage {
p.IsIndex = true
}

return p, nil
}

Expand Down
11 changes: 8 additions & 3 deletions server/page/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,14 @@ func (c *Client) registerWebClientCore(request *RegisterWebClientRequestPayload)

// get page
page := store.GetPageByName(pageName.String())
if page == nil {
response.Error = pageNotFoundMessage
return
if page == nil && !pageName.IsIndex {
// fallback to index
pageName, _ = model.ParsePageName("")
page = store.GetPageByName(pageName.String())
if page == nil {
response.Error = pageNotFoundMessage
return
}
}

// func: check if "Sign in required" response should be sent
Expand Down
30 changes: 27 additions & 3 deletions server/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,40 @@ func Start(ctx context.Context, wg *sync.WaitGroup, serverPort int) {
router.NoRoute(func(c *gin.Context) {

if !strings.HasPrefix(c.Request.RequestURI, apiRoutePrefix+"/") {
urlPath := strings.TrimRight(c.Request.URL.Path, "/") + "/"
log.Debugln("Request path:", urlPath)
baseHref := strings.Trim(c.Request.URL.Path, "/")
log.Debugln("Request path:", baseHref)

if baseHref != "" {
hrefParts := strings.Split(baseHref, "/")
if len(hrefParts) > 1 {
baseHref = strings.Join(hrefParts[:2], "/")
if store.GetPageByName(baseHref) == nil {
// fallback to index page
baseHref = ""
}
} else {
baseHref = ""
}
}

if baseHref != "" {
baseHref = "/" + baseHref + "/"
} else {
baseHref = "/"
}

index, _ := assetsFS.Open(siteDefaultDocument)
indexData, _ := ioutil.ReadAll(index)

// base path
indexData = bytes.Replace(indexData,
[]byte("<base href=\"/\">"),
[]byte("<base href=\""+urlPath+"\">"), 1)
[]byte("<base href=\""+baseHref+"\">"), 1)

// route URL strategy
indexData = bytes.Replace(indexData,
[]byte("%FLET_ROUTE_URL_STRATEGY%"),
[]byte(config.RouteUrlStrategy()), 1)

// web renderer
if config.WebRenderer() != "" {
Expand Down

0 comments on commit 133d75f

Please sign in to comment.