Skip to content

Commit 6b4bd0c

Browse files
committed
add SubPageSession
1 parent fc99bde commit 6b4bd0c

File tree

3 files changed

+113
-14
lines changed

3 files changed

+113
-14
lines changed

webiojs/src/main.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {config as appConfig, state} from "./state";
2-
import {Command, HttpSession, is_http_backend, Session, WebSocketSession, pushData} from "./session";
2+
import {Command, HttpSession, detect_backend, Session, WebSocketSession, pushData, SubPageSession} from "./session";
33
import {InputHandler} from "./handlers/input"
44
import {OutputHandler} from "./handlers/output"
55
import {CommandDispatcher, SessionCtrlHandler} from "./handlers/base"
@@ -69,19 +69,27 @@ function startWebIOClient(options: {
6969
}
7070
const backend_addr = backend_absaddr(options.backend_address);
7171

72-
let start_session = (is_http: boolean) => {
72+
let start_session = (session_type: String) => {
7373
let session;
74-
if (is_http)
74+
if (session_type === 'http')
7575
session = new HttpSession(backend_addr, options.app_name, appConfig.httpPullInterval);
76-
else
76+
else if (session_type === 'ws')
7777
session = new WebSocketSession(backend_addr, options.app_name);
78+
else if (session_type === 'page')
79+
session = new SubPageSession()
80+
else
81+
throw `Unsupported session type: ${session_type}`;
82+
7883
set_up_session(session, options.output_container_elem, options.input_container_elem);
7984
session.start_session(appConfig.debug);
8085
};
81-
if (options.protocol == 'auto')
82-
is_http_backend(backend_addr).then(start_session);
86+
87+
if (SubPageSession.is_sub_page()) {
88+
start_session('page')
89+
} else if (options.protocol == 'auto')
90+
detect_backend(backend_addr).then(start_session);
8391
else
84-
start_session(options.protocol == 'http')
92+
start_session(options.protocol)
8593
}
8694

8795

webiojs/src/session.ts

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,21 @@ export interface ClientEvent {
2323
export interface Session {
2424
webio_session_id: string;
2525

26+
// add session creation callback
2627
on_session_create(callback: () => void): void;
2728

29+
// add session close callback
2830
on_session_close(callback: () => void): void;
2931

32+
// add session message received callback
3033
on_server_message(callback: (msg: Command) => void): void;
3134

3235
start_session(debug: boolean): void;
3336

37+
// send text message to server
3438
send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void;
3539

40+
// send binary message to server
3641
send_buffer(data: Blob, onprogress?: (loaded: number, total: number) => void): void;
3742

3843
close_session(): void;
@@ -49,11 +54,76 @@ function safe_poprun_callbacks(callbacks: (() => void)[], name = 'callback') {
4954
}
5055
}
5156

57+
export class SubPageSession implements Session {
58+
webio_session_id: string = '';
59+
debug: boolean;
60+
private _closed: boolean = false;
61+
62+
private _session_create_callbacks: (() => void)[] = [];
63+
private _session_close_callbacks: (() => void)[] = [];
64+
private _on_server_message: (msg: Command) => any = () => {
65+
};
66+
67+
// check if it's a pywebio subpage
68+
static is_sub_page(): boolean {
69+
// - `window._pywebio_page` lazy promise is not undefined
70+
// - window.opener is not null and window.opener.WebIO is not undefined
71+
// @ts-ignore
72+
return window._pywebio_page !== undefined && window.opener !== null && window.opener.WebIO !== undefined;
73+
}
74+
75+
on_session_create(callback: () => any): void {
76+
this._session_create_callbacks.push(callback);
77+
};
78+
79+
on_session_close(callback: () => any): void {
80+
this._session_close_callbacks.push(callback);
81+
}
82+
83+
on_server_message(callback: (msg: Command) => any): void {
84+
this._on_server_message = callback;
85+
}
86+
87+
start_session(debug: boolean): void {
88+
this.debug = debug;
89+
safe_poprun_callbacks(this._session_create_callbacks, 'session_create_callback');
90+
91+
// @ts-ignore
92+
window._pywebio_page.promise.resolve(this);
93+
};
94+
95+
// called by opener, transfer command to this session
96+
server_message(command: Command) {
97+
if (this.debug)
98+
console.info('>>>', command);
99+
this._on_server_message(command);
100+
}
101+
102+
// send text message to opener
103+
send_message(msg: ClientEvent, onprogress?: (loaded: number, total: number) => void): void {
104+
window.opener.WebIO._state.CurrentSession.send_message(msg, onprogress);
105+
}
106+
107+
// send binary message to opener
108+
send_buffer(data: Blob, onprogress?: (loaded: number, total: number) => void): void {
109+
window.opener.WebIO._state.CurrentSession.send_buffer(data, onprogress);
110+
}
111+
112+
close_session(): void {
113+
this._closed = true;
114+
safe_poprun_callbacks(this._session_close_callbacks, 'session_close_callback');
115+
}
116+
117+
closed(): boolean {
118+
return this._closed;
119+
}
120+
}
121+
52122
export class WebSocketSession implements Session {
53123
ws: WebSocket;
54124
debug: boolean;
55125
webio_session_id: string = 'NEW';
56-
private _closed: boolean; // session logic closed (by `close_session` command)
126+
private _closed: boolean; // session logical closed (by `close_session` command)
57127
private _session_create_ts = 0;
58128
private _session_create_callbacks: (() => void)[] = [];
59129
private _session_close_callbacks: (() => void)[] = [];
@@ -308,22 +378,21 @@ export class HttpSession implements Session {
308378
}
309379

310380
/*
311-
* Check given `backend_addr` is a http backend
381+
* Check backend type: http or ws
312382
* Usage:
313-
* // `http_backend` is a boolean to present whether or not a http_backend the given `backend_addr` is
314-
* is_http_backend('http://localhost:8080/io').then(function(http_backend){ });
383+
* detect_backend('http://localhost:8080/io').then(function(backend_type){ });
315384
* */
316-
export function is_http_backend(backend_addr: string) {
385+
export function detect_backend(backend_addr: string) {
317386
let url = new URL(backend_addr);
318387
let protocol = url.protocol || window.location.protocol;
319388
url.protocol = protocol.replace('wss', 'https').replace('ws', 'http');
320389
backend_addr = url.href;
321390

322391
return new Promise(function (resolve, reject) {
323392
$.get(backend_addr, {test: 1}, undefined, 'html').done(function (data: string) {
324-
resolve(data === 'ok');
393+
resolve(data === 'ok' ? 'http' : 'ws');
325394
}).fail(function (e: JQuery.jqXHR) {
326-
resolve(false);
395+
resolve('ws');
327396
});
328397
});
329398
}

webiojs/src/utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,26 @@ function int2bytes(num: number) {
176176
dataView.setUint32(0, (num / 4294967296) | 0); // 4294967296 == 2^32
177177
dataView.setUint32(4, num | 0);
178178
return buf;
179+
}
180+
181+
182+
export class LazyPromise {
183+
/*
184+
* Execute operations when some the dependency is ready.
185+
*
186+
* Add pending operations:
187+
* LazyPromise.promise.then((dependency)=> ...)
188+
* Mark dependency is ready:
189+
* LazyPromise.promise.resolve(dependency)
190+
* */
191+
public promise: Promise<any>;
192+
public resolve: (_: any) => void;
193+
public reject: (_: any) => void;
194+
195+
constructor() {
196+
this.promise = new Promise((resolve, reject) => {
197+
this.resolve = resolve;
198+
this.reject = reject;
199+
});
200+
}
179201
}

0 commit comments

Comments
 (0)