change webpack config and fine tune to use the frontend as a library
This commit is contained in:
parent
508722feb5
commit
2c39f7fd3c
9 changed files with 64 additions and 95 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,4 +3,4 @@ frontend/dist/*.js
|
||||||
frontend/.js
|
frontend/.js
|
||||||
underbbs
|
underbbs
|
||||||
underbbs-cli
|
underbbs-cli
|
||||||
__debug_*
|
__debug_*
|
||||||
|
|
21
README.md
21
README.md
|
@ -22,13 +22,24 @@ adapters receive commands via a quartzgun web API and send data back on their sh
|
||||||
|
|
||||||
requirements are
|
requirements are
|
||||||
|
|
||||||
- go 1.22
|
- go 1.22 (for the backend)
|
||||||
- any recent nodejs that can do `typescript` and `webpack` 5
|
- any recent nodejs that can do `typescript` and `webpack` 5 (for the frontend)
|
||||||
|
|
||||||
from the project root:
|
from the project root:
|
||||||
|
|
||||||
1. `./build.sh front`
|
1. `./build.sh front` (if you will use the web components)
|
||||||
2. `./build.sh server`
|
2. `./build.sh server`
|
||||||
3. `./underbbs`
|
3. `./underbbs` or `./underbbs-cli ADAPTER ACTION ARGS...`
|
||||||
|
|
||||||
visit `http://localhost:9090/app`
|
## integrating
|
||||||
|
|
||||||
|
### with the API and web components
|
||||||
|
|
||||||
|
1. fill `Settings._instance` with adapter settings; these will mostly be authentication data (`SettingsElement` illustrates this)
|
||||||
|
2. instantiate whatever components you want on your page with their `data-gateway` and `data-target` appropriately set; further docs to come on these
|
||||||
|
3. call `DatagramSocket.connect(GATEWAY)` where `GATEWAY` is the domain of the `underbbs` API. `SettingsElement`'s connect button does this for you.
|
||||||
|
|
||||||
|
### with the CLI
|
||||||
|
|
||||||
|
1. Call the CLI directly from the serverside or locally
|
||||||
|
2. Process any output to your preference
|
||||||
|
|
1
build.sh
1
build.sh
|
@ -21,6 +21,7 @@ case "$1" in
|
||||||
server)
|
server)
|
||||||
go mod tidy
|
go mod tidy
|
||||||
go build
|
go build
|
||||||
|
cp underbbs underbbs-cli
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "usage: ${0} <front|server>"
|
echo "usage: ${0} <front|server>"
|
||||||
|
|
29
frontend/dist/index.html
vendored
29
frontend/dist/index.html
vendored
|
@ -1,29 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en-US">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<title>underBBS test</title>
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<link rel="shortcut icon" href="./favicon.png"/>
|
|
||||||
<link href="./style.css" rel="stylesheet" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript><div id="noscript_container">
|
|
||||||
JS app lol
|
|
||||||
</div>
|
|
||||||
</noscript>
|
|
||||||
<div id="err_wrapper" style='display:none'><button id="err_close" onclick="closeErr()">x</button><div id="err_div"></div></div>
|
|
||||||
<main>
|
|
||||||
<div class='uicolumn'>
|
|
||||||
<details open><summary>settings</summary><div id="settings_parent"></div></details>
|
|
||||||
<details open><summary>timeline-select</summary><div id="timeline_filter_parent"></div></details>
|
|
||||||
<details open><summary>timeline</summary><div id="timeline_parent"></div></details>
|
|
||||||
</div>
|
|
||||||
<div class='uicolumn'>
|
|
||||||
<details open><summary>profile</summary><div id="profile_parent"></div></details>
|
|
||||||
<details open><summary>honks</summary><div id="honks_parent"></div></details>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
<script src="./main.js" type="application/javascript"></script>
|
|
||||||
</html>
|
|
|
@ -1,52 +0,0 @@
|
||||||
import util from "./util"
|
|
||||||
import {AdapterState, AdapterData} from "./adapter";
|
|
||||||
import {Message, Attachment, Author} from "./message"
|
|
||||||
import {Settings} from "./settings"
|
|
||||||
import { MessageElement } from "./message-element"
|
|
||||||
import { SettingsElement } from "./settings-element"
|
|
||||||
import { ProfileElement } from "./profile-element"
|
|
||||||
import { AuthorMessagesElement } from "./author-messages-element"
|
|
||||||
import { TimelineElement } from "./timeline-element"
|
|
||||||
import { TimelineFilterElement } from "./timeline-filter-element"
|
|
||||||
import {DatagramSocket} from "./websocket"
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
const saveData = localStorage.getItem("underbbs_settings");
|
|
||||||
Settings._instance = saveData ? <Settings>JSON.parse(saveData) : new Settings();
|
|
||||||
|
|
||||||
customElements.define("underbbs-message", MessageElement);
|
|
||||||
customElements.define("underbbs-settings", SettingsElement);
|
|
||||||
customElements.define("underbbs-profile", ProfileElement);
|
|
||||||
customElements.define("underbbs-author-messages", AuthorMessagesElement);
|
|
||||||
customElements.define("underbbs-timeline", TimelineElement);
|
|
||||||
customElements.define("underbbs-timeline-filter", TimelineFilterElement);
|
|
||||||
|
|
||||||
util._("closeErr", util.closeErr);
|
|
||||||
|
|
||||||
let settingsParent = util.$("settings_parent");
|
|
||||||
if (settingsParent) {
|
|
||||||
settingsParent.innerHTML = `<underbbs-settings data-adapters='${Settings._instance.adapters.map(a=>a.nickname).join(",")}' data-gateway=""></underbbs-settings>`
|
|
||||||
}
|
|
||||||
|
|
||||||
let profileParent = util.$("profile_parent");
|
|
||||||
if (profileParent) {
|
|
||||||
profileParent.innerHTML = "<underbbs-profile data-adapter='honk' data-target='https://cafe.nilfm.cc/u/nilix' data-gateway=''></underbbs-profile>"
|
|
||||||
}
|
|
||||||
|
|
||||||
let honksParent = util.$("honks_parent");
|
|
||||||
if (honksParent) {
|
|
||||||
honksParent.innerHTML = "<underbbs-author-messages data-adapter='honk' data-target='https://cafe.nilfm.cc/u/nilix' data-gateway=''></underbbs-author-messages>";
|
|
||||||
}
|
|
||||||
|
|
||||||
let timelineParent = util.$("timeline_parent");
|
|
||||||
if (timelineParent) {
|
|
||||||
timelineParent.innerHTML = "<underbbs-timeline id='honkstream' data-adapter='honk' data-target='home' data-gateway=''></underbbs-timeline>";
|
|
||||||
}
|
|
||||||
|
|
||||||
let timelineSelectParent = util.$("timeline_filter_parent");
|
|
||||||
if (timelineSelectParent) {
|
|
||||||
timelineSelectParent.innerHTML = "<underbbs-timeline-filter data-target='honkstream' data-filters='home::home/atme::atme'></underbbs-timeline-filter>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
|
@ -4,15 +4,17 @@ import {Settings} from "./settings"
|
||||||
|
|
||||||
|
|
||||||
export class SettingsElement extends HTMLElement {
|
export class SettingsElement extends HTMLElement {
|
||||||
static observedAttributes = [ "data-adapters" ]
|
static observedAttributes = [ "data-adapters", "data-gateway" ]
|
||||||
|
|
||||||
private _adapters: string[] = [];
|
private _adapters: string[] = [];
|
||||||
|
private _gateway: string = "";
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
this._gateway = this.getAttribute("data-gateway") ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(attr: string, prev: string, next: string) {
|
attributeChangedCallback(attr: string, prev: string, next: string) {
|
||||||
|
@ -49,7 +51,7 @@ export class SettingsElement extends HTMLElement {
|
||||||
}
|
}
|
||||||
let connect = util.$("settings_connect_btn");
|
let connect = util.$("settings_connect_btn");
|
||||||
if (connect) {
|
if (connect) {
|
||||||
connect.addEventListener("click", DatagramSocket.connect, false);
|
connect.addEventListener("click", ()=>{DatagramSocket.connect(this._gateway)}, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,17 @@ import util from "./util"
|
||||||
import {AdapterState, AdapterData} from "./adapter";
|
import {AdapterState, AdapterData} from "./adapter";
|
||||||
import {Message, Attachment, Author} from "./message"
|
import {Message, Attachment, Author} from "./message"
|
||||||
import {Settings} from "./settings"
|
import {Settings} from "./settings"
|
||||||
|
import {SettingsElement} from "./settings-element"
|
||||||
|
import {AuthorMessagesElement} from "./author-messages-element"
|
||||||
|
import {ProfileElement} from "./profile-element"
|
||||||
|
import {MessageElement} from "./message-element"
|
||||||
|
import {TimelineElement} from "./timeline-element"
|
||||||
|
import {TimelineFilterElement} from "./timeline-filter-element"
|
||||||
|
|
||||||
export class DatagramSocket {
|
export class DatagramSocket {
|
||||||
public static skey: string | null = null;
|
public static skey: string | null = null;
|
||||||
public static conn: WebSocket | null;
|
public static conn: WebSocket | null;
|
||||||
|
private static _gateway: string = ""
|
||||||
|
|
||||||
|
|
||||||
private static onOpen(e: Event) {
|
private static onOpen(e: Event) {
|
||||||
|
@ -14,12 +20,16 @@ export class DatagramSocket {
|
||||||
console.log(JSON.stringify(e));
|
console.log(JSON.stringify(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static gatewayWithScheme(): string {
|
||||||
|
return location.protocol + "//" + DatagramSocket._gateway
|
||||||
|
}
|
||||||
|
|
||||||
private static onMsg(e: MessageEvent) {
|
private static onMsg(e: MessageEvent) {
|
||||||
const data = JSON.parse(e.data);
|
const data = JSON.parse(e.data);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
if (data.key) {
|
if (data.key) {
|
||||||
DatagramSocket.skey = data.key;
|
DatagramSocket.skey = data.key;
|
||||||
util.authorizedFetch("POST", "/api/adapters", JSON.stringify(Settings._instance.adapters))
|
util.authorizedFetch("POST", DatagramSocket.gatewayWithScheme() + "/api/adapters", JSON.stringify(Settings._instance.adapters))
|
||||||
.then(r=> {
|
.then(r=> {
|
||||||
if (r.ok) {
|
if (r.ok) {
|
||||||
// iterate through any components which might want to fetch data
|
// iterate through any components which might want to fetch data
|
||||||
|
@ -89,9 +99,17 @@ export class DatagramSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static connect(): void {
|
static connect(gateway: string): void {
|
||||||
|
DatagramSocket._gateway = gateway;
|
||||||
|
|
||||||
const wsProto = location.protocol == "https:" ? "wss" : "ws";
|
const wsProto = location.protocol == "https:" ? "wss" : "ws";
|
||||||
const _conn = new WebSocket(`${wsProto}://${location.host}/subscribe`, "underbbs");
|
let wsUrl = ""
|
||||||
|
if (!gateway) {
|
||||||
|
wsUrl = `${wsProto}://${location.host}/subscribe`;
|
||||||
|
} else {
|
||||||
|
wsUrl = wsProto + "://" + gateway + "/subscribe"
|
||||||
|
}
|
||||||
|
const _conn = new WebSocket(wsUrl, "underbbs");
|
||||||
|
|
||||||
_conn.addEventListener("open", DatagramSocket.onOpen);
|
_conn.addEventListener("open", DatagramSocket.onOpen);
|
||||||
_conn.addEventListener("message", DatagramSocket.onMsg);
|
_conn.addEventListener("message", DatagramSocket.onMsg);
|
||||||
|
@ -104,3 +122,19 @@ export class DatagramSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
const saveData = localStorage.getItem("underbbs_settings");
|
||||||
|
Settings._instance = saveData ? JSON.parse(saveData) : new Settings();
|
||||||
|
|
||||||
|
customElements.define("underbbs-message", MessageElement);
|
||||||
|
customElements.define("underbbs-settings", SettingsElement);
|
||||||
|
customElements.define("underbbs-profile", ProfileElement);
|
||||||
|
customElements.define("underbbs-author-messages", AuthorMessagesElement);
|
||||||
|
customElements.define("underbbs-timeline", TimelineElement);
|
||||||
|
customElements.define("underbbs-timeline-filter", TimelineFilterElement);
|
||||||
|
|
||||||
|
console.log("underbbs initialized!")
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,8 @@ func (self *BBSServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
func (self *BBSServer) subscribeHandler(w http.ResponseWriter, r *http.Request) {
|
func (self *BBSServer) subscribeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
c, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||||
Subprotocols: []string{},
|
Subprotocols: []string{},
|
||||||
|
OriginPatterns: []string{"*"},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.logf("%v", err)
|
self.logf("%v", err)
|
||||||
|
|
|
@ -4,9 +4,10 @@ module.exports = {
|
||||||
mode: 'production',
|
mode: 'production',
|
||||||
context: path.resolve(__dirname, 'frontend', '.js'),
|
context: path.resolve(__dirname, 'frontend', '.js'),
|
||||||
entry: {
|
entry: {
|
||||||
main: './index.js',
|
underbbs: './websocket.js',
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
iife: false,
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
path: path.resolve(__dirname, 'frontend', 'dist'),
|
path: path.resolve(__dirname, 'frontend', 'dist'),
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue