0

Add support for and use socket host override. (#1682)

* Add support for and use socket host override. Closes #1378

* Fix embeds with the new websocket constructor
This commit is contained in:
Gabe Kangas 2022-03-06 17:11:51 -08:00 committed by GitHub
parent 9d5bdc320c
commit d24ddc2b0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 75 additions and 82 deletions

View File

@ -408,6 +408,25 @@ func SetServerURL(w http.ResponseWriter, r *http.Request) {
controllers.WriteSimpleResponse(w, true, "server url set") controllers.WriteSimpleResponse(w, true, "server url set")
} }
// SetSocketHostOverride will set the host override for the websocket.
func SetSocketHostOverride(w http.ResponseWriter, r *http.Request) {
if !requirePOST(w, r) {
return
}
configValue, success := getValueFromRequest(w, r)
if !success {
return
}
if err := data.SetWebsocketOverrideHost(configValue.Value.(string)); err != nil {
controllers.WriteSimpleResponse(w, false, err.Error())
return
}
controllers.WriteSimpleResponse(w, true, "websocket host override set")
}
// SetDirectoryEnabled will handle the web config request to enable or disable directory registration. // SetDirectoryEnabled will handle the web config request to enable or disable directory registration.
func SetDirectoryEnabled(w http.ResponseWriter, r *http.Request) { func SetDirectoryEnabled(w http.ResponseWriter, r *http.Request) {
if !requirePOST(w, r) { if !requirePOST(w, r) {

View File

@ -53,6 +53,7 @@ func GetServerConfig(w http.ResponseWriter, r *http.Request) {
RTMPServerPort: data.GetRTMPPortNumber(), RTMPServerPort: data.GetRTMPPortNumber(),
ChatDisabled: data.GetChatDisabled(), ChatDisabled: data.GetChatDisabled(),
ChatJoinMessagesEnabled: data.GetChatJoinMessagesEnabled(), ChatJoinMessagesEnabled: data.GetChatJoinMessagesEnabled(),
SocketHostOverride: data.GetWebsocketOverrideHost(),
VideoSettings: videoSettings{ VideoSettings: videoSettings{
VideoQualityVariants: videoQualityVariants, VideoQualityVariants: videoQualityVariants,
LatencyLevel: data.GetStreamLatencyLevel().Level, LatencyLevel: data.GetStreamLatencyLevel().Level,
@ -103,6 +104,7 @@ type serverConfigAdminResponse struct {
ForbiddenUsernames []string `json:"forbiddenUsernames"` ForbiddenUsernames []string `json:"forbiddenUsernames"`
Federation federationConfigResponse `json:"federation"` Federation federationConfigResponse `json:"federation"`
SuggestedUsernames []string `json:"suggestedUsernames"` SuggestedUsernames []string `json:"suggestedUsernames"`
SocketHostOverride string `json:"socketHostOverride,omitempty"`
} }
type videoSettings struct { type videoSettings struct {

View File

@ -21,6 +21,7 @@ type webConfigResponse struct {
Tags []string `json:"tags"` Tags []string `json:"tags"`
Version string `json:"version"` Version string `json:"version"`
NSFW bool `json:"nsfw"` NSFW bool `json:"nsfw"`
SocketHostOverride string `json:"socketHostOverride,omitempty"`
ExtraPageContent string `json:"extraPageContent"` ExtraPageContent string `json:"extraPageContent"`
StreamTitle string `json:"streamTitle,omitempty"` // What's going on with the current stream StreamTitle string `json:"streamTitle,omitempty"` // What's going on with the current stream
SocialHandles []models.SocialHandle `json:"socialHandles"` SocialHandles []models.SocialHandle `json:"socialHandles"`
@ -78,6 +79,7 @@ func GetWebConfig(w http.ResponseWriter, r *http.Request) {
Tags: data.GetServerMetadataTags(), Tags: data.GetServerMetadataTags(),
Version: config.GetReleaseString(), Version: config.GetReleaseString(),
NSFW: data.GetNSFW(), NSFW: data.GetNSFW(),
SocketHostOverride: data.GetWebsocketOverrideHost(),
ExtraPageContent: pageContent, ExtraPageContent: pageContent,
StreamTitle: data.GetStreamTitle(), StreamTitle: data.GetStreamTitle(),
SocialHandles: socialHandles, SocialHandles: socialHandles,

View File

@ -24,6 +24,7 @@ const (
serverURLKey = "server_url" serverURLKey = "server_url"
httpPortNumberKey = "http_port_number" httpPortNumberKey = "http_port_number"
httpListenAddressKey = "http_listen_address" httpListenAddressKey = "http_listen_address"
websocketHostOverrideKey = "websocket_host_override"
rtmpPortNumberKey = "rtmp_port_number" rtmpPortNumberKey = "rtmp_port_number"
serverMetadataTagsKey = "server_metadata_tags" serverMetadataTagsKey = "server_metadata_tags"
directoryEnabledKey = "directory_enabled" directoryEnabledKey = "directory_enabled"
@ -200,6 +201,18 @@ func GetHTTPPortNumber() int {
return int(port) return int(port)
} }
// SetWebsocketOverrideHost will set the host override for websockets.
func SetWebsocketOverrideHost(host string) error {
return _datastore.SetString(websocketHostOverrideKey, host)
}
// GetWebsocketOverrideHost will return the host override for websockets.
func GetWebsocketOverrideHost() string {
host, _ := _datastore.GetString(websocketHostOverrideKey)
return host
}
// SetHTTPPortNumber will set the server HTTP port. // SetHTTPPortNumber will set the server HTTP port.
func SetHTTPPortNumber(port float64) error { func SetHTTPPortNumber(port float64) error {
return _datastore.SetNumber(httpPortNumberKey, port) return _datastore.SetNumber(httpPortNumberKey, port)

View File

@ -245,6 +245,9 @@ func Start() error {
// Server rtmp port // Server rtmp port
http.HandleFunc("/api/admin/config/rtmpserverport", middleware.RequireAdminAuth(admin.SetRTMPServerPort)) http.HandleFunc("/api/admin/config/rtmpserverport", middleware.RequireAdminAuth(admin.SetRTMPServerPort))
// Websocket host override
http.HandleFunc("/api/admin/config/sockethostoverride", middleware.RequireAdminAuth(admin.SetSocketHostOverride))
// Is server marked as NSFW // Is server marked as NSFW
http.HandleFunc("/api/admin/config/nsfw", middleware.RequireAdminAuth(admin.SetNSFW)) http.HandleFunc("/api/admin/config/nsfw", middleware.RequireAdminAuth(admin.SetNSFW))

View File

@ -2087,9 +2087,9 @@
} }
}, },
"node_modules/follow-redirects": { "node_modules/follow-redirects": {
"version": "1.14.8", "version": "1.14.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@ -3652,45 +3652,12 @@
"dev": true "dev": true
}, },
"node_modules/node-fetch": { "node_modules/node-fetch": {
"version": "2.6.7", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==",
"dev": true, "dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": { "engines": {
"node": "4.x || >=6.0.0" "node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
"dev": true
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
"dev": true
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"dev": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
} }
}, },
"node_modules/node-int64": { "node_modules/node-int64": {
@ -6589,9 +6556,9 @@
} }
}, },
"follow-redirects": { "follow-redirects": {
"version": "1.14.8", "version": "1.14.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz",
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "integrity": "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==",
"dev": true "dev": true
}, },
"for-in": { "for-in": {
@ -7780,37 +7747,10 @@
"dev": true "dev": true
}, },
"node-fetch": { "node-fetch": {
"version": "2.6.7", "version": "2.6.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.2.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "integrity": "sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA==",
"dev": true, "dev": true
"requires": {
"whatwg-url": "^5.0.0"
},
"dependencies": {
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
"dev": true
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
"dev": true
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"dev": true,
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
}, },
"node-int64": { "node-int64": {
"version": "0.4.0", "version": "0.4.0",

View File

@ -20,6 +20,7 @@ import {
URL_CONFIG, URL_CONFIG,
TIMER_STATUS_UPDATE, TIMER_STATUS_UPDATE,
} from './utils/constants.js'; } from './utils/constants.js';
import { URL_WEBSOCKET } from './utils/constants.js';
export default class StandaloneChat extends Component { export default class StandaloneChat extends Component {
constructor(props, context) { constructor(props, context) {
@ -53,6 +54,8 @@ export default class StandaloneChat extends Component {
this.setupChatAuth = this.setupChatAuth.bind(this); this.setupChatAuth = this.setupChatAuth.bind(this);
this.disableChat = this.disableChat.bind(this); this.disableChat = this.disableChat.bind(this);
this.socketHostOverride = null;
// user events // user events
this.handleWebsocketMessage = this.handleWebsocketMessage.bind(this); this.handleWebsocketMessage = this.handleWebsocketMessage.bind(this);
@ -98,7 +101,7 @@ export default class StandaloneChat extends Component {
} }
setConfigData(data = {}) { setConfigData(data = {}) {
const { chatDisabled } = data; const { chatDisabled, socketHostOverride } = data;
// If this is the first time setting the config // If this is the first time setting the config
// then setup chat if it's enabled. // then setup chat if it's enabled.
@ -107,7 +110,7 @@ export default class StandaloneChat extends Component {
} }
this.hasConfiguredChat = true; this.hasConfiguredChat = true;
this.socketHostOverride = socketHostOverride;
this.setState({ this.setState({
canChat: !chatDisabled, canChat: !chatDisabled,
configData: { configData: {
@ -277,7 +280,10 @@ export default class StandaloneChat extends Component {
} }
// Without a valid access token he websocket connection will be rejected. // Without a valid access token he websocket connection will be rejected.
const websocket = new Websocket(accessToken); const websocket = new Websocket(
accessToken,
this.socketHostOverride || URL_WEBSOCKET
);
websocket.addListener( websocket.addListener(
CALLBACKS.RAW_WEBSOCKET_MESSAGE_RECEIVED, CALLBACKS.RAW_WEBSOCKET_MESSAGE_RECEIVED,
this.handleWebsocketMessage this.handleWebsocketMessage

View File

@ -2,6 +2,8 @@ import { h, Component } from '/js/web_modules/preact.js';
import htm from '/js/web_modules/htm.js'; import htm from '/js/web_modules/htm.js';
const html = htm.bind(h); const html = htm.bind(h);
import { URL_WEBSOCKET } from './utils/constants.js';
import { OwncastPlayer } from './components/player.js'; import { OwncastPlayer } from './components/player.js';
import SocialIconsList from './components/platform-logos-list.js'; import SocialIconsList from './components/platform-logos-list.js';
import UsernameForm from './components/chat/username.js'; import UsernameForm from './components/chat/username.js';
@ -154,6 +156,7 @@ export default class App extends Component {
this.hasConfiguredChat = false; this.hasConfiguredChat = false;
this.setupChatAuth = this.setupChatAuth.bind(this); this.setupChatAuth = this.setupChatAuth.bind(this);
this.disableChat = this.disableChat.bind(this); this.disableChat = this.disableChat.bind(this);
this.socketHostOverride = null;
} }
componentDidMount() { componentDidMount() {
@ -245,9 +248,11 @@ export default class App extends Component {
} }
setConfigData(data = {}) { setConfigData(data = {}) {
const { name, summary, chatDisabled } = data; const { name, summary, chatDisabled, socketHostOverride } = data;
window.document.title = name; window.document.title = name;
this.socketHostOverride = socketHostOverride;
// If this is the first time setting the config // If this is the first time setting the config
// then setup chat if it's enabled. // then setup chat if it's enabled.
if (!this.hasConfiguredChat && !chatDisabled) { if (!this.hasConfiguredChat && !chatDisabled) {
@ -638,8 +643,11 @@ export default class App extends Component {
}); });
} }
// Without a valid access token he websocket connection will be rejected. // Without a valid access token the websocket connection will be rejected.
const websocket = new Websocket(accessToken); const websocket = new Websocket(
accessToken,
this.socketHostOverride || URL_WEBSOCKET
);
websocket.addListener( websocket.addListener(
CALLBACKS.RAW_WEBSOCKET_MESSAGE_RECEIVED, CALLBACKS.RAW_WEBSOCKET_MESSAGE_RECEIVED,
this.handleWebsocketMessage this.handleWebsocketMessage

View File

@ -1,4 +1,3 @@
import { URL_WEBSOCKET } from './constants.js';
/** /**
* These are the types of messages that we can handle with the websocket. * These are the types of messages that we can handle with the websocket.
* Mostly used by `websocket.js` but if other components need to handle * Mostly used by `websocket.js` but if other components need to handle
@ -30,8 +29,9 @@ export const CALLBACKS = {
const TIMER_WEBSOCKET_RECONNECT = 5000; // ms const TIMER_WEBSOCKET_RECONNECT = 5000; // ms
export default class Websocket { export default class Websocket {
constructor(accessToken) { constructor(accessToken, path) {
this.websocket = null; this.websocket = null;
this.path = path;
this.websocketReconnectTimer = null; this.websocketReconnectTimer = null;
this.accessToken = accessToken; this.accessToken = accessToken;
@ -50,7 +50,7 @@ export default class Websocket {
} }
createAndConnect() { createAndConnect() {
const url = new URL(URL_WEBSOCKET); const url = new URL(this.path);
url.searchParams.append('accessToken', this.accessToken); url.searchParams.append('accessToken', this.accessToken);
const ws = new WebSocket(url.toString()); const ws = new WebSocket(url.toString());