Page load and parsing durations in HTTP header
This commit is contained in:
parent
2f713f40fc
commit
514260205c
|
@ -22,7 +22,7 @@ var (
|
||||||
|
|
||||||
type incomingRawText struct {
|
type incomingRawText struct {
|
||||||
RequestID string `json:"request_id"`
|
RequestID string `json:"request_id"`
|
||||||
RawText string `json:"body"`
|
RawJSON string `json:"json"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func startWebSocketServer() {
|
func startWebSocketServer() {
|
||||||
|
@ -96,7 +96,7 @@ func handleRawFrameTextCommands(parts []string) {
|
||||||
}
|
}
|
||||||
if incoming.RequestID != "" {
|
if incoming.RequestID != "" {
|
||||||
Log("Raw text for " + incoming.RequestID)
|
Log("Raw text for " + incoming.RequestID)
|
||||||
rawTextRequests[incoming.RequestID] = incoming.RawText
|
rawTextRequests[incoming.RequestID] = incoming.RawJSON
|
||||||
} else {
|
} else {
|
||||||
Log("Raw text but no associated request ID")
|
Log("Raw text but no associated request ID")
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package browsh
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -21,6 +22,12 @@ import (
|
||||||
// real browser to render the webpage, we keep track of requests in a map.
|
// real browser to render the webpage, we keep track of requests in a map.
|
||||||
var rawTextRequests = make(map[string]string)
|
var rawTextRequests = make(map[string]string)
|
||||||
|
|
||||||
|
type rawTextResponse struct {
|
||||||
|
PageloadDuration int `json:"page_load_duration"`
|
||||||
|
ParsingDuration int `json:"parsing_duration"`
|
||||||
|
Text string `json:"body"`
|
||||||
|
}
|
||||||
|
|
||||||
// HTTPServerStart starts the HTTP server is a seperate service from the usual interactive TTY
|
// HTTPServerStart starts the HTTP server is a seperate service from the usual interactive TTY
|
||||||
// app. It accepts normal HTTP requests and uses the path portion of the URL as the entry to the
|
// app. It accepts normal HTTP requests and uses the path portion of the URL as the entry to the
|
||||||
// Browsh URL bar. It then returns a simple line-broken text version of whatever the browser
|
// Browsh URL bar. It then returns a simple line-broken text version of whatever the browser
|
||||||
|
@ -81,6 +88,7 @@ func (h *slashFix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
func handleHTTPServerRequest(w http.ResponseWriter, r *http.Request) {
|
func handleHTTPServerRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
var message string
|
var message string
|
||||||
var isErrored bool
|
var isErrored bool
|
||||||
|
var start = time.Now().Format(time.RFC3339)
|
||||||
urlForBrowsh, _ := url.PathUnescape(strings.TrimPrefix(r.URL.Path, "/"))
|
urlForBrowsh, _ := url.PathUnescape(strings.TrimPrefix(r.URL.Path, "/"))
|
||||||
urlForBrowsh, isErrored = deRecurseURL(urlForBrowsh)
|
urlForBrowsh, isErrored = deRecurseURL(urlForBrowsh)
|
||||||
if isErrored {
|
if isErrored {
|
||||||
|
@ -128,6 +136,7 @@ func handleHTTPServerRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rawTextRequestID := pseudoUUID()
|
rawTextRequestID := pseudoUUID()
|
||||||
|
rawTextRequests[rawTextRequestID+"-start"] = start
|
||||||
mode := getRawTextMode(r)
|
mode := getRawTextMode(r)
|
||||||
sendMessageToWebExtension(
|
sendMessageToWebExtension(
|
||||||
"/raw_text_request," + rawTextRequestID + "," +
|
"/raw_text_request," + rawTextRequestID + "," +
|
||||||
|
@ -198,13 +207,36 @@ func getRawTextMode(r *http.Request) string {
|
||||||
|
|
||||||
func waitForResponse(rawTextRequestID string, w http.ResponseWriter) {
|
func waitForResponse(rawTextRequestID string, w http.ResponseWriter) {
|
||||||
var rawTextRequestResponse string
|
var rawTextRequestResponse string
|
||||||
|
var jsonResponse rawTextResponse
|
||||||
|
var totalTime, pageLoad, parsing string
|
||||||
var ok bool
|
var ok bool
|
||||||
for {
|
for {
|
||||||
if rawTextRequestResponse, ok = rawTextRequests[rawTextRequestID]; ok {
|
if rawTextRequestResponse, ok = rawTextRequests[rawTextRequestID]; ok {
|
||||||
io.WriteString(w, rawTextRequestResponse)
|
jsonResponse = unpackResponse(rawTextRequestResponse)
|
||||||
|
totalTime = getTotalTiming(rawTextRequests[rawTextRequestID+"-start"])
|
||||||
|
pageLoad = fmt.Sprintf("%dms", jsonResponse.PageloadDuration)
|
||||||
|
parsing = fmt.Sprintf("%dms", jsonResponse.ParsingDuration)
|
||||||
|
w.Header().Set("X-Browsh-Duration-Total", totalTime+"ms")
|
||||||
|
w.Header().Set("X-Browsh-Duration-Pageload", pageLoad)
|
||||||
|
w.Header().Set("X-Browsh-Duration-Parsing", parsing)
|
||||||
|
io.WriteString(w, jsonResponse.Text)
|
||||||
delete(rawTextRequests, rawTextRequestID)
|
delete(rawTextRequests, rawTextRequestID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(1 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unpackResponse(jsonString string) rawTextResponse {
|
||||||
|
var response rawTextResponse
|
||||||
|
jsonBytes := []byte(jsonString)
|
||||||
|
if err := json.Unmarshal(jsonBytes, &response); err != nil {
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTotalTiming(startString string) string {
|
||||||
|
start, _ := time.Parse(time.RFC3339, startString)
|
||||||
|
elapsed := time.Since(start) / time.Millisecond
|
||||||
|
return fmt.Sprintf("%d", elapsed)
|
||||||
|
}
|
||||||
|
|
|
@ -158,14 +158,22 @@ export default class extends utils.mixins(CommonMixin, TTYCommandsMixin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyUpdates(tabish_object) {
|
_applyUpdates(tabish_object) {
|
||||||
let tab = this._maybeNewTab({ id: tabish_object.id });
|
let tab = this._maybeNewTab({
|
||||||
["id", "title", "url", "active", "request_id", "raw_text_mode_type"].map(
|
id: tabish_object.id
|
||||||
key => {
|
});
|
||||||
if (tabish_object.hasOwnProperty(key)) {
|
[
|
||||||
tab[key] = tabish_object[key];
|
"id",
|
||||||
}
|
"title",
|
||||||
|
"url",
|
||||||
|
"active",
|
||||||
|
"request_id",
|
||||||
|
"raw_text_mode_type",
|
||||||
|
"start_time"
|
||||||
|
].map(key => {
|
||||||
|
if (tabish_object.hasOwnProperty(key)) {
|
||||||
|
tab[key] = tabish_object[key];
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
if (tabish_object.active) {
|
if (tabish_object.active) {
|
||||||
this.active_tab_id = tab.id;
|
this.active_tab_id = tab.id;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +297,9 @@ export default class extends utils.mixins(CommonMixin, TTYCommandsMixin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ urls: ["*://*/*"] },
|
{
|
||||||
|
urls: ["*://*/*"]
|
||||||
|
},
|
||||||
["blocking"]
|
["blocking"]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@ export default class extends utils.mixins(CommonMixin, TabCommandsMixin) {
|
||||||
|
|
||||||
sendGlobalConfig(config) {
|
sendGlobalConfig(config) {
|
||||||
config.http_server_mode_type = this._calculateMode();
|
config.http_server_mode_type = this._calculateMode();
|
||||||
|
config.start_time = this.start_time;
|
||||||
this.channel.postMessage(`/config,${JSON.stringify(config)}`);
|
this.channel.postMessage(`/config,${JSON.stringify(config)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,11 @@ export default MixinBase =>
|
||||||
}
|
}
|
||||||
|
|
||||||
_rawTextRequest(incoming) {
|
_rawTextRequest(incoming) {
|
||||||
incoming.request_id = this.request_id;
|
let payload = {
|
||||||
this.sendToTerminal(`/raw_text,${JSON.stringify(incoming)}`);
|
json: JSON.stringify(incoming),
|
||||||
|
request_id: this.request_id
|
||||||
|
};
|
||||||
|
this.sendToTerminal(`/raw_text,${JSON.stringify(payload)}`);
|
||||||
this._tabCount(count => {
|
this._tabCount(count => {
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
this.remove();
|
this.remove();
|
||||||
|
|
|
@ -190,7 +190,8 @@ export default MixinBase =>
|
||||||
this._acknowledgeNewTab({
|
this._acknowledgeNewTab({
|
||||||
id: native_tab.id,
|
id: native_tab.id,
|
||||||
request_id: request_id,
|
request_id: request_id,
|
||||||
raw_text_mode_type: mode.toLowerCase()
|
raw_text_mode_type: mode.toLowerCase(),
|
||||||
|
start_time: Date.now()
|
||||||
});
|
});
|
||||||
// Sometimes tabs fail to load for whatever reason. Make sure they get
|
// Sometimes tabs fail to load for whatever reason. Make sure they get
|
||||||
// removed to save RAM in long-lived Browsh HTTP servers
|
// removed to save RAM in long-lived Browsh HTTP servers
|
||||||
|
|
|
@ -37,7 +37,6 @@ export default class extends utils.mixins(CommonMixin, CommandsMixin) {
|
||||||
this.graphics_builder,
|
this.graphics_builder,
|
||||||
this.config
|
this.config
|
||||||
);
|
);
|
||||||
this.text_builder._raw_text_start = performance.now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_willHideText() {
|
_willHideText() {
|
||||||
|
@ -204,6 +203,8 @@ export default class extends utils.mixins(CommonMixin, CommandsMixin) {
|
||||||
});
|
});
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
this.is_page_finished_loading = true;
|
this.is_page_finished_loading = true;
|
||||||
|
this.config.page_load_duration = Date.now() - this.config.start_time;
|
||||||
|
this.text_builder.config = this.config;
|
||||||
this.log("PAGE LOADED");
|
this.log("PAGE LOADED");
|
||||||
});
|
});
|
||||||
window.addEventListener("unload", () => {
|
window.addEventListener("unload", () => {
|
||||||
|
|
|
@ -85,8 +85,9 @@ export default MixinBase =>
|
||||||
|
|
||||||
_getMetaData() {
|
_getMetaData() {
|
||||||
let metadata = "";
|
let metadata = "";
|
||||||
|
this._markParsingDuration();
|
||||||
const date_time = this._getCurrentDataTime();
|
const date_time = this._getCurrentDataTime();
|
||||||
const elapsed = `${performance.now() - this._raw_text_start}ms`;
|
const elapsed = `${this._parsing_duration}ms`;
|
||||||
metadata +=
|
metadata +=
|
||||||
"\n\n" + `Built ` + this._byBrowsh() + `on ${date_time} in ${elapsed}.`;
|
"\n\n" + `Built ` + this._byBrowsh() + `on ${date_time} in ${elapsed}.`;
|
||||||
if (this.dimensions.is_page_truncated) {
|
if (this.dimensions.is_page_truncated) {
|
||||||
|
@ -189,6 +190,10 @@ export default MixinBase =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_markParsingDuration() {
|
||||||
|
this._parsing_duration = performance.now() - this._parse_start_time;
|
||||||
|
}
|
||||||
|
|
||||||
_getCurrentDataTime() {
|
_getCurrentDataTime() {
|
||||||
let current_date = new Date();
|
let current_date = new Date();
|
||||||
const offset = -(new Date().getTimezoneOffset() / 60);
|
const offset = -(new Date().getTimezoneOffset() / 60);
|
||||||
|
@ -293,7 +298,9 @@ export default MixinBase =>
|
||||||
|
|
||||||
_sendRawText() {
|
_sendRawText() {
|
||||||
let payload = {
|
let payload = {
|
||||||
body: this._serialiseRawText()
|
body: this._serialiseRawText(),
|
||||||
|
page_load_duration: this.config.page_load_duration,
|
||||||
|
parsing_duration: this._parsing_duration
|
||||||
};
|
};
|
||||||
this.sendMessage(`/raw_text,${JSON.stringify(payload)}`);
|
this.sendMessage(`/raw_text,${JSON.stringify(payload)}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ export default class extends utils.mixins(CommonMixin, SerialiseMixin) {
|
||||||
|
|
||||||
sendRawText(type) {
|
sendRawText(type) {
|
||||||
this._raw_mode_type = type;
|
this._raw_mode_type = type;
|
||||||
|
this._parse_start_time = performance.now();
|
||||||
this.buildFormattedText(this._sendRawText.bind(this));
|
this.buildFormattedText(this._sendRawText.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue