peertube
Namekuji 2023-01-26 13:28:25 -05:00
rodzic 073510d4b5
commit 17e07d28a1
16 zmienionych plików z 209 dodań i 60 usunięć

Wyświetl plik

@ -2,7 +2,7 @@ audon.localhost {
tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem
encode zstd gzip
@backend {
path /app/* /api/* /storage/*
path /app/* /api/* /storage/* /u/*
}
handle @backend {
reverse_proxy devcontainer:8100

54
audon-fe/package-lock.json wygenerowano
Wyświetl plik

@ -1,12 +1,12 @@
{
"name": "audon-fe",
"version": "0.2.0",
"version": "0.2.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "audon-fe",
"version": "0.2.0",
"version": "0.2.3",
"dependencies": {
"@intlify/unplugin-vue-i18n": "^0.8.1",
"@picmo/popup-picker": "^5.7.2",
@ -809,9 +809,9 @@
}
},
"node_modules/acorn": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"bin": {
"acorn": "bin/acorn"
},
@ -895,9 +895,9 @@
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz",
"integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.2.5.tgz",
"integrity": "sha512-9pU/8mmjSSOb4CXVsvGIevN+MlO/t9OWtKadTaLuN85Gge3HGorUckgp8A/2FH4V4hJ7JuQ3LIeI7KAV9ITZrQ==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
@ -2342,9 +2342,9 @@
}
},
"node_modules/livekit-client": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-1.6.2.tgz",
"integrity": "sha512-OJIcBY8fzS8tf4vvBL/LNjmEHMFRLivnRjBDjbSiJ8nqV7UB7iSN40RMAejp/OPjhB5ys1u8tt6m3RIXrG2TJA==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-1.6.3.tgz",
"integrity": "sha512-hnVN/rQ9pVWK0L1lemLSOzBI6IXoJepgHP/USqmGJ6eucaoLMx1jK0iMWpR5T2/pg97GmZaUaRSUcXlELNSsoA==",
"dependencies": {
"async-await-queue": "^1.2.1",
"events": "^3.3.0",
@ -2465,9 +2465,9 @@
}
},
"node_modules/masto": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.6.0.tgz",
"integrity": "sha512-+5t6bSt/V0HyL3hDowxabVszfLjkrKVunhgWXC4LrCBMjMKIOF4vrFJriXSPKOprB6VCZztvGGuy02zSy7oRcQ==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/masto/-/masto-5.6.1.tgz",
"integrity": "sha512-mQxuOLCWP0TSswZEmmrbHbV2+Olt2N+lr1V2C3FO0QCrPGAhx3KLAXRLArajeGtcVtu66/k8gtTWKksYfkQu5Q==",
"dependencies": {
"@mastojs/ponyfills": "^1.0.4",
"change-case": "^4.1.2",
@ -2963,9 +2963,9 @@
}
},
"node_modules/protobufjs": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz",
"integrity": "sha512-4ZPTPkXCdel3+L81yw3dG6+Kq3umdWKh7Dc7GW/CpNk4SX3hK58iPCWeCyhVTDrbkNeKrYNZ7EojM5WDaEWTLQ==",
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.0.tgz",
"integrity": "sha512-hYCqTDuII4iJ4stZqiuGCSU8xxWl5JeXYpwARGtn/tWcKCAro6h3WQz+xpsNbXW0UYqpmTQFEyFWO0G0Kjt64g==",
"hasInstallScript": true,
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
@ -3365,24 +3365,10 @@
"rxjs": "*"
}
},
"node_modules/typescript": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"optional": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/ua-parser-js": {
"version": "1.0.32",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.32.tgz",
"integrity": "sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA==",
"version": "1.0.33",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.33.tgz",
"integrity": "sha512-RqshF7TPTE0XLYAqmjlu5cLLuGdKrNu9O1KLA/qp39QtbZwuzwv1dT46DZSopoUMsYgXpB3Cv8a03FI8b74oFQ==",
"funding": [
{
"type": "opencollective",

Wyświetl plik

@ -46,6 +46,7 @@ roomReady:
header: "Your room is ready!"
message: "Your room \"{title}\" is now ready. Share the following URL with other participants."
errors:
offline: "This user is offline now."
invalidAddress: "Invalid address"
serverNotFound: "Instance not found"
notFound: "{value} not found"

Wyświetl plik

@ -46,6 +46,7 @@ roomReady:
header: "お部屋の用意ができました!"
message: "{title} を作りました。参加者に以下の URL を共有してください。"
errors:
offline: "このユーザーは現在オフラインです。"
invalidAddress: "アドレスが有効ではありません"
serverNotFound: "サーバーが見つかりません"
notFound: "{value} が見つかりません"

Wyświetl plik

@ -1,7 +1,8 @@
import { createRouter, createWebHistory } from "vue-router";
import LoginView from "../views/LoginView.vue";
import RoomView from "../views/RoomView.vue";
import NotFoundView from "../views/NotFoundView.vue";
import ErrorView from "../views/ErrorView.vue";
import axios from "axios";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -12,7 +13,15 @@ const router = createRouter({
meta: {
noauth: true,
},
component: NotFoundView,
component: ErrorView,
},
{
path: "/error/:type",
name: "error",
meta: {
noauth: true,
},
component: ErrorView,
},
{
path: "/",
@ -40,6 +49,27 @@ const router = createRouter({
},
component: RoomView,
},
{
path: "/u/:webfinger",
name: "currentHosting",
meta: {
noauth: true,
},
redirect: async (to) => {
try {
const resp = await axios.get(`/u/${to.params.webfinger}`);
if (resp.status === 302) {
return {
name: "room",
params: { id: resp.headers.location },
};
}
} catch (error) {
console.log(error);
}
return { name: "notfound" };
},
},
],
});

Wyświetl plik

@ -32,7 +32,15 @@ export default {
clipboard: useClipboard(),
};
},
created() {
async created() {
const resp = await axios.get("/api/room");
if (resp.data.length > 0) {
const canCreate = !some(resp.data, { role: "host" });
if (!canCreate) {
alert(this.$t("errors.alreadyAdded"));
this.$router.replace({ name: "home" });
}
}
this.cohostSearch = debounce(this.search, 1000);
},
unmounted() {

Wyświetl plik

@ -0,0 +1,23 @@
<script>
export default {
data() {
return {
name: this.$route.name,
};
},
created() {
const type = this.$route.params.type;
if (!type) return;
if (type === "offline") {
const target = new URL(decodeURI(this.$route.query.url));
alert(this.$t("errors.offline"));
window.location.href = target.toString();
}
},
};
</script>
<template>
<v-alert v-if="this.name === 'notfound'" type="error">Page not found</v-alert>
</template>

Wyświetl plik

@ -1,6 +1,7 @@
<script>
import { useMastodonStore } from "../stores/mastodon";
import axios from "axios";
import { some } from "lodash-es";
export default {
setup() {
@ -10,9 +11,16 @@ export default {
},
data() {
return {
canCreate: true,
query: "",
};
},
async created() {
const resp = await axios.get("/api/room");
if (resp.data.length > 0) {
this.canCreate = !some(resp.data, { role: "host" });
}
},
methods: {
async onLogout() {
// if (!confirm(this.$t("logoutConfirm"))) return;
@ -63,9 +71,13 @@ export default {
<v-text-field v-mode="query"></v-text-field>
</v-col> -->
<v-col cols="12">
<v-btn block :to="{ name: 'create' }" color="indigo">{{
$t("createNewRoom")
}}</v-btn>
<v-btn
:disabled="!canCreate"
block
:to="{ name: 'create' }"
color="indigo"
>{{ $t("createNewRoom") }}</v-btn
>
</v-col>
</v-row>
</main>

Wyświetl plik

@ -1,5 +0,0 @@
<script></script>
<template>
<v-alert type="error">Page not found</v-alert>
</template>

Wyświetl plik

@ -557,11 +557,7 @@ export default {
return metadata;
},
async fetchMastoData(identity) {
if (
this.cachedMastoData[identity] !== undefined ||
this.roomInfo.accounts[identity] === undefined
)
return;
if (this.roomInfo.accounts[identity] === undefined) return;
try {
const resp = await axios.get(`/app/user/${identity}`);
const account = this.roomInfo.accounts[identity];

Wyświetl plik

@ -174,7 +174,6 @@ func oauthHandler(c echo.Context) (err error) {
}
return c.Redirect(http.StatusFound, req.Redirect)
// return c.Redirect(http.StatusFound, "http://localhost:5173")
}
func getUserTokenHandler(c echo.Context) (err error) {

17
room.go
Wyświetl plik

@ -35,6 +35,23 @@ func createRoomHandler(c echo.Context) error {
host := c.Get("user").(*AudonUser)
room.Host = host
// check if user is already hosting
lkRooms, err := host.GetCurrentLivekitRooms(c.Request().Context())
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
for _, r := range lkRooms {
meta, err := getRoomMetadataFromLivekitRoom(r)
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
if meta.Host.Equal(host) {
return ErrOperationNotPermitted
}
}
coll := mainDB.Collection(COLLECTION_ROOM)
now := time.Now().UTC()

Wyświetl plik

@ -133,6 +133,15 @@ func (r *Room) IsHost(u *AudonUser) bool {
return r != nil && r.Host.Equal(u)
}
func (r *RoomMetadata) IsSpeaker(u *AudonUser) bool {
for _, s := range r.Speakers {
if s.Equal(u) {
return true
}
}
return false
}
func getRoomMetadataFromLivekitRoom(lkRoom *livekit.Room) (*RoomMetadata, error) {
metadata := new(RoomMetadata)
if err := json.Unmarshal([]byte(lkRoom.GetMetadata()), metadata); err != nil {
@ -240,3 +249,12 @@ func findUserByID(ctx context.Context, audonID string) (*AudonUser, error) {
}
return &result, nil
}
func findUserByWebfinger(ctx context.Context, webfinger string) (*AudonUser, error) {
var result AudonUser
coll := mainDB.Collection(COLLECTION_USER)
if err := coll.FindOne(ctx, bson.D{{Key: "webfinger", Value: webfinger}}).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}

Wyświetl plik

@ -182,6 +182,7 @@ func main() {
e.Static("/static", "audon-fe/dist/static")
e.Static("/storage", mainConfig.StorageDir)
e.GET("/r/:id", renderRoomHandler)
e.GET("/u/:webfinger", redirectUserHandler)
e.GET("/*", func(c echo.Context) error {
return c.Render(http.StatusOK, "tmpl", &TemplateData{Config: &mainConfig.AppConfigBase})
})

74
user.go
Wyświetl plik

@ -2,7 +2,9 @@ package main
import (
"context"
"fmt"
"net/http"
"net/url"
"time"
"github.com/labstack/echo/v4"
@ -51,13 +53,56 @@ func getUserHandler(c echo.Context) error {
func getStatusHandler(c echo.Context) error {
u := c.Get("user").(*AudonUser)
ids, err := u.GetCurrentRoomIDs(c.Request().Context())
status, err := u.GetCurrentRoomStatus(c.Request().Context())
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
return c.JSON(http.StatusOK, ids)
return c.JSON(http.StatusOK, status)
}
func redirectUserHandler(c echo.Context) error {
input := c.Param("webfinger")
if err := mainValidator.Var(&input, "required,startswith=@,min=4"); err != nil {
return wrapValidationError(err)
}
webfinger := input[1:]
if err := mainValidator.Var(&webfinger, "email"); err != nil {
return wrapValidationError(err)
}
user, err := findUserByWebfinger(c.Request().Context(), webfinger)
if err != nil || user == nil {
return ErrUserNotFound
}
rooms, err := user.GetCurrentLivekitRooms(c.Request().Context())
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
for _, r := range rooms {
meta, err := getRoomMetadataFromLivekitRoom(r)
if err != nil {
continue
}
if meta.Host.Equal(user) {
return c.Redirect(http.StatusFound, fmt.Sprintf("/r/%s", r.GetName()))
}
}
query := make(url.Values)
query.Add("url", user.RemoteURL)
result := url.URL{
Path: "/error/offline",
ForceQuery: true,
OmitHost: true,
RawQuery: query.Encode(),
}
return c.Redirect(http.StatusFound, result.String())
}
func (a *AudonUser) Equal(u *AudonUser) bool {
@ -90,14 +135,31 @@ func (a *AudonUser) ClearUserAvatar(ctx context.Context) error {
return err
}
func (a *AudonUser) GetCurrentRoomIDs(ctx context.Context) ([]string, error) {
type UserStatus struct {
RoomID string `json:"roomID"`
Role string `json:"role"`
}
func (a *AudonUser) GetCurrentRoomStatus(ctx context.Context) ([]UserStatus, error) {
rooms, err := a.GetCurrentLivekitRooms(ctx)
if err != nil {
return nil, err
}
roomIDs := make([]string, len(rooms))
roomList := make([]UserStatus, len(rooms))
for i, r := range rooms {
roomIDs[i] = r.GetName()
meta, _ := getRoomMetadataFromLivekitRoom(r)
role := "listener"
if meta.Room.IsHost(a) {
role = "host"
} else if meta.Room.IsCoHost(a) {
role = "cohost"
} else if meta.IsSpeaker(a) {
role = "speaker"
}
roomList[i] = UserStatus{
RoomID: r.GetName(),
Role: role,
}
}
return roomIDs, nil
return roomList, nil
}

Wyświetl plik

@ -64,13 +64,13 @@ func livekitWebhookHandler(c echo.Context) error {
<-oldTimer.C
}
}
countdown := time.NewTimer(10 * time.Second)
countdown := time.NewTimer(60 * time.Second)
webhookTimerCache.Set(audonID, countdown, ttlcache.DefaultTTL)
go func() {
<-countdown.C
webhookTimerCache.Delete(audonID)
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
stillAgain, err := user.InLivekit(ctx)