Commit 72ca4e74 authored by Steven's avatar Steven

refactor: impl part of grpcweb

parent d5c1706e
......@@ -5,6 +5,7 @@ import (
"fmt"
grpcRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"github.com/labstack/echo/v4"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
"github.com/usememos/memos/server/profile"
......@@ -24,6 +25,7 @@ type APIV2Service struct {
}
func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store, grpcServerPort int) *APIV2Service {
grpc.EnableTracing = true
authProvider := NewGRPCAuthInterceptor(store, secret)
grpcServer := grpc.NewServer(
grpc.ChainUnaryInterceptor(
......@@ -81,5 +83,15 @@ func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error
}
e.Any("/api/v2/*", echo.WrapHandler(gwMux))
// GRPC web proxy.
options := []grpcweb.Option{
grpcweb.WithCorsForRegisteredEndpointsOnly(false),
grpcweb.WithOriginFunc(func(origin string) bool {
return true
}),
}
wrappedGrpc := grpcweb.WrapServer(s.grpcServer, options...)
e.Any("/memos.api.v2.*", echo.WrapHandler(wrappedGrpc))
return nil
}
......@@ -13,6 +13,7 @@ require (
github.com/google/uuid v1.3.0
github.com/gorilla/feeds v1.1.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2
github.com/improbable-eng/grpc-web v0.15.0
github.com/labstack/echo/v4 v4.11.1
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.6.1
......@@ -35,6 +36,8 @@ require (
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
......@@ -42,9 +45,11 @@ require (
github.com/go-openapi/swag v0.22.4 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.11.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/swaggo/files/v2 v2.0.0 // indirect
golang.org/x/image v0.7.0 // indirect
......@@ -60,6 +65,7 @@ require (
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
)
require (
......
This diff is collapsed.
......@@ -21,6 +21,16 @@ plugins:
# Build the TypeScript definitions for the web.
- plugin: buf.build/bufbuild/es:v1.3.0
out: ../web/src/types/proto
- plugin: buf.build/community/stephenh-ts-proto:v1.152.1
out: ../web/src/types/proto-grpcweb
# reference: https://github.com/deeplay-io/nice-grpc/blob/master/packages/nice-grpc-web/README.md#using-ts-proto
opt:
- env=browser
- useOptionals=messages
- outputServices=generic-definitions
- outputJsonMethods=false
- useExactTypes=false
- esModuleInterop=true
- plugin: buf.build/community/pseudomuto-doc:v1.5.1
out: gen
opt:
......
......@@ -7,6 +7,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/usememos/memos/common/util"
)
//go:embed dist
......@@ -43,3 +44,8 @@ func embedFrontend(e *echo.Echo) {
Filesystem: getFileSystem("dist/assets"),
}))
}
func defaultAPIRequestSkipper(c echo.Context) bool {
path := c.Request().URL.Path
return util.HasPrefixes(path, "/api", "/memos.api.v2")
}
......@@ -6,6 +6,7 @@ import (
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/google/uuid"
......@@ -16,7 +17,6 @@ import (
apiv1 "github.com/usememos/memos/api/v1"
apiv2 "github.com/usememos/memos/api/v2"
"github.com/usememos/memos/common/log"
"github.com/usememos/memos/common/util"
"github.com/usememos/memos/plugin/telegram"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/server/service"
......@@ -65,13 +65,13 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
e.Use(middleware.Gzip())
e.Use(middleware.CORS())
e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
Skipper: grpcRequestSkipper,
Timeout: 30 * time.Second,
}))
e.Use(middleware.RateLimiterWithConfig(middleware.RateLimiterConfig{
Skipper: grpcRequestSkipper,
Store: middleware.NewRateLimiterMemoryStoreWithConfig(
middleware.RateLimiterMemoryStoreConfig{Rate: 30, Burst: 60, ExpiresIn: 3 * time.Minute},
),
......@@ -225,11 +225,6 @@ func (s *Server) createServerStartActivity(ctx context.Context) error {
return err
}
func defaultGetRequestSkipper(c echo.Context) bool {
return c.Request().Method == http.MethodGet
}
func defaultAPIRequestSkipper(c echo.Context) bool {
path := c.Request().URL.Path
return util.HasPrefixes(path, "/api", "/api/v1", "api/v2")
func grpcRequestSkipper(c echo.Context) bool {
return strings.HasPrefix(c.Request().URL.Path, "/memos.api.v2.")
}
......@@ -22,7 +22,11 @@
"i18next-browser-languagedetector": "^7.1.0",
"katex": "^0.16.8",
"lodash-es": "^4.17.21",
"long": "^5.2.3",
"lucide-react": "^0.263.1",
"nice-grpc-common": "^2.0.2",
"nice-grpc-web": "^3.3.1",
"protobufjs": "^7.2.5",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
......
......@@ -47,9 +47,21 @@ dependencies:
lodash-es:
specifier: ^4.17.21
version: 4.17.21
long:
specifier: ^5.2.3
version: 5.2.3
lucide-react:
specifier: ^0.263.1
version: 0.263.1(react@18.2.0)
nice-grpc-common:
specifier: ^2.0.2
version: 2.0.2
nice-grpc-web:
specifier: ^3.3.1
version: 3.3.1(ws@8.14.1)
protobufjs:
specifier: ^7.2.5
version: 7.2.5
qrcode.react:
specifier: ^3.1.0
version: 3.1.0(react@18.2.0)
......@@ -1024,6 +1036,49 @@ packages:
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
dev: false
/@protobufjs/aspromise@1.1.2:
resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==}
dev: false
/@protobufjs/base64@1.1.2:
resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==}
dev: false
/@protobufjs/codegen@2.0.4:
resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==}
dev: false
/@protobufjs/eventemitter@1.1.0:
resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==}
dev: false
/@protobufjs/fetch@1.1.0:
resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==}
dependencies:
'@protobufjs/aspromise': 1.1.2
'@protobufjs/inquire': 1.1.0
dev: false
/@protobufjs/float@1.0.2:
resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==}
dev: false
/@protobufjs/inquire@1.1.0:
resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==}
dev: false
/@protobufjs/path@1.1.2:
resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==}
dev: false
/@protobufjs/pool@1.1.0:
resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==}
dev: false
/@protobufjs/utf8@1.1.0:
resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
dev: false
/@reduxjs/toolkit@1.9.5(react-redux@8.1.2)(react@18.2.0):
resolution: {integrity: sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==}
peerDependencies:
......@@ -1215,7 +1270,6 @@ packages:
/@types/node@18.17.16:
resolution: {integrity: sha512-e0zgs7qe1XH/X3KEPnldfkD07LH9O1B9T31U8qoO7lqGSjj3/IrBuvqMeJ1aYejXRK3KOphIUDw6pLIplEW17A==}
dev: true
/@types/parse-json@4.0.0:
resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
......@@ -1456,6 +1510,10 @@ packages:
resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==}
dev: false
/abort-controller-x@0.4.3:
resolution: {integrity: sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==}
dev: false
/acorn-jsx@5.3.2(acorn@8.10.0):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
......@@ -2783,6 +2841,14 @@ packages:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/isomorphic-ws@5.0.0(ws@8.14.1):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.14.1
dev: false
/iterator.prototype@1.1.2:
resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==}
dependencies:
......@@ -2802,6 +2868,10 @@ packages:
hasBin: true
dev: false
/js-base64@3.7.5:
resolution: {integrity: sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==}
dev: false
/js-cookie@2.2.1:
resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
dev: false
......@@ -2923,6 +2993,10 @@ packages:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: true
/long@5.2.3:
resolution: {integrity: sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==}
dev: false
/loose-envify@1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
......@@ -3069,6 +3143,23 @@ packages:
dev: true
optional: true
/nice-grpc-common@2.0.2:
resolution: {integrity: sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==}
dependencies:
ts-error: 1.0.6
dev: false
/nice-grpc-web@3.3.1(ws@8.14.1):
resolution: {integrity: sha512-KXListAFLjJ7L/GsrRW5YWT+2oZDaF8Lu19ms7+HMykDGtIksqvZwR6+EzVmunFJciiNDShJ4EXr1W6eaiZoDQ==}
dependencies:
abort-controller-x: 0.4.3
isomorphic-ws: 5.0.0(ws@8.14.1)
js-base64: 3.7.5
nice-grpc-common: 2.0.2
transitivePeerDependencies:
- ws
dev: false
/node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
dev: true
......@@ -3335,6 +3426,25 @@ packages:
object-assign: 4.1.1
react-is: 16.13.1
/protobufjs@7.2.5:
resolution: {integrity: sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==}
engines: {node: '>=12.0.0'}
requiresBuild: true
dependencies:
'@protobufjs/aspromise': 1.1.2
'@protobufjs/base64': 1.1.2
'@protobufjs/codegen': 2.0.4
'@protobufjs/eventemitter': 1.1.0
'@protobufjs/fetch': 1.1.0
'@protobufjs/float': 1.0.2
'@protobufjs/inquire': 1.1.0
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 18.17.16
long: 5.2.3
dev: false
/prr@1.0.1:
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
requiresBuild: true
......@@ -3947,6 +4057,10 @@ packages:
resolution: {integrity: sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==}
dev: false
/ts-error@1.0.6:
resolution: {integrity: sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==}
dev: false
/ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
dev: false
......@@ -4169,6 +4283,19 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
/ws@8.14.1:
resolution: {integrity: sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
dev: true
......
import { createChannel, createClientFactory, FetchTransport } from "nice-grpc-web";
import { UserServiceDefinition } from "./types/proto-grpcweb/api/v2/user_service";
const address = import.meta.env.MODE === "development" ? "http://localhost:8081" : window.location.origin;
const channel = createChannel(
address,
FetchTransport({
credentials: "include",
})
);
const clientFactory = createClientFactory();
export const userServiceClient = clientFactory.create(UserServiceDefinition, channel);
......@@ -7,7 +7,7 @@ import UserAvatar from "@/components/UserAvatar";
import useLoading from "@/hooks/useLoading";
import { useMemoStore } from "@/store/module";
import { useUserV1Store } from "@/store/v1";
import { User } from "@/types/proto/api/v2/user_service_pb";
import { User } from "@/types/proto-grpcweb/api/v2/user_service";
const MemoDetail = () => {
const params = useParams();
......
......@@ -7,7 +7,7 @@ import UserAvatar from "@/components/UserAvatar";
import useLoading from "@/hooks/useLoading";
import { useUserStore } from "@/store/module";
import { useUserV1Store } from "@/store/v1";
import { User } from "@/types/proto/api/v2/user_service_pb";
import { User } from "@/types/proto-grpcweb/api/v2/user_service";
import { useTranslate } from "@/utils/i18n";
const UserProfile = () => {
......
import axios from "axios";
import { create } from "zustand";
import * as api from "@/helpers/api";
import { UpdateUserResponse, User } from "@/types/proto/api/v2/user_service_pb";
import { userServiceClient } from "@/grpcweb";
import { User } from "@/types/proto-grpcweb/api/v2/user_service";
interface UserV1Store {
userMapByUsername: Record<string, User>;
......@@ -24,11 +23,11 @@ const useUserV1Store = create<UserV1Store>()((set, get) => ({
return await requestCache.get(username);
}
const promise = api.getUserByUsername(username);
const promise = userServiceClient.getUser({
username: username,
});
requestCache.set(username, promise);
const {
data: { user: user },
} = await promise;
const { user } = await promise;
if (!user) {
throw new Error("User not found");
}
......@@ -42,11 +41,10 @@ const useUserV1Store = create<UserV1Store>()((set, get) => ({
return userMap[username];
},
updateUser: async (user: Partial<User>, updateMask: string[]) => {
const {
data: { user: updatedUser },
} = await axios.post<UpdateUserResponse>(`/api/v2/users/${user.username}`, {
user,
updateMask,
const { user: updatedUser } = await userServiceClient.updateUser({
username: user.username,
user: user,
updateMask: updateMask,
});
if (!updatedUser) {
throw new Error("User not found");
......
/* eslint-disable */
export const protobufPackage = "memos.api.v2";
export enum RowStatus {
ROW_STATUS_UNSPECIFIED = 0,
ACTIVE = 1,
ARCHIVED = 2,
UNRECOGNIZED = -1,
}
This diff is collapsed.
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
import { Timestamp } from "../../google/protobuf/timestamp";
export const protobufPackage = "memos.api.v2";
export interface Resource {
id: number;
createdTs?: Date | undefined;
filename: string;
externalLink: string;
type: string;
size: number;
relatedMemoId?: number | undefined;
}
export interface ListResourcesRequest {
}
export interface ListResourcesResponse {
resources: Resource[];
}
function createBaseResource(): Resource {
return { id: 0, createdTs: undefined, filename: "", externalLink: "", type: "", size: 0, relatedMemoId: undefined };
}
export const Resource = {
encode(message: Resource, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.id !== 0) {
writer.uint32(8).int32(message.id);
}
if (message.createdTs !== undefined) {
Timestamp.encode(toTimestamp(message.createdTs), writer.uint32(18).fork()).ldelim();
}
if (message.filename !== "") {
writer.uint32(26).string(message.filename);
}
if (message.externalLink !== "") {
writer.uint32(34).string(message.externalLink);
}
if (message.type !== "") {
writer.uint32(42).string(message.type);
}
if (message.size !== 0) {
writer.uint32(48).int64(message.size);
}
if (message.relatedMemoId !== undefined) {
writer.uint32(56).int32(message.relatedMemoId);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): Resource {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseResource();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 8) {
break;
}
message.id = reader.int32();
continue;
case 2:
if (tag !== 18) {
break;
}
message.createdTs = fromTimestamp(Timestamp.decode(reader, reader.uint32()));
continue;
case 3:
if (tag !== 26) {
break;
}
message.filename = reader.string();
continue;
case 4:
if (tag !== 34) {
break;
}
message.externalLink = reader.string();
continue;
case 5:
if (tag !== 42) {
break;
}
message.type = reader.string();
continue;
case 6:
if (tag !== 48) {
break;
}
message.size = longToNumber(reader.int64() as Long);
continue;
case 7:
if (tag !== 56) {
break;
}
message.relatedMemoId = reader.int32();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<Resource>): Resource {
return Resource.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<Resource>): Resource {
const message = createBaseResource();
message.id = object.id ?? 0;
message.createdTs = object.createdTs ?? undefined;
message.filename = object.filename ?? "";
message.externalLink = object.externalLink ?? "";
message.type = object.type ?? "";
message.size = object.size ?? 0;
message.relatedMemoId = object.relatedMemoId ?? undefined;
return message;
},
};
function createBaseListResourcesRequest(): ListResourcesRequest {
return {};
}
export const ListResourcesRequest = {
encode(_: ListResourcesRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): ListResourcesRequest {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseListResourcesRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<ListResourcesRequest>): ListResourcesRequest {
return ListResourcesRequest.fromPartial(base ?? {});
},
fromPartial(_: DeepPartial<ListResourcesRequest>): ListResourcesRequest {
const message = createBaseListResourcesRequest();
return message;
},
};
function createBaseListResourcesResponse(): ListResourcesResponse {
return { resources: [] };
}
export const ListResourcesResponse = {
encode(message: ListResourcesResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
for (const v of message.resources) {
Resource.encode(v!, writer.uint32(10).fork()).ldelim();
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): ListResourcesResponse {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseListResourcesResponse();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.resources.push(Resource.decode(reader, reader.uint32()));
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<ListResourcesResponse>): ListResourcesResponse {
return ListResourcesResponse.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<ListResourcesResponse>): ListResourcesResponse {
const message = createBaseListResourcesResponse();
message.resources = object.resources?.map((e) => Resource.fromPartial(e)) || [];
return message;
},
};
export type ResourceServiceDefinition = typeof ResourceServiceDefinition;
export const ResourceServiceDefinition = {
name: "ResourceService",
fullName: "memos.api.v2.ResourceService",
methods: {
listResources: {
name: "ListResources",
requestType: ListResourcesRequest,
requestStream: false,
responseType: ListResourcesResponse,
responseStream: false,
options: {
_unknownFields: {
578365826: [
new Uint8Array([19, 18, 17, 47, 97, 112, 105, 47, 118, 50, 47, 114, 101, 115, 111, 117, 114, 99, 101, 115]),
],
},
},
},
},
} as const;
declare const self: any | undefined;
declare const window: any | undefined;
declare const global: any | undefined;
const tsProtoGlobalThis: any = (() => {
if (typeof globalThis !== "undefined") {
return globalThis;
}
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw "Unable to locate global object";
})();
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
function toTimestamp(date: Date): Timestamp {
const seconds = date.getTime() / 1_000;
const nanos = (date.getTime() % 1_000) * 1_000_000;
return { seconds, nanos };
}
function fromTimestamp(t: Timestamp): Date {
let millis = (t.seconds || 0) * 1_000;
millis += (t.nanos || 0) / 1_000_000;
return new Date(millis);
}
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
}
return long.toNumber();
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
}
This diff is collapsed.
/* eslint-disable */
import _m0 from "protobufjs/minimal";
export const protobufPackage = "memos.api.v2";
export interface Tag {
name: string;
creatorId: number;
}
export interface ListTagsRequest {
creatorId: number;
}
export interface ListTagsResponse {
tags: Tag[];
}
function createBaseTag(): Tag {
return { name: "", creatorId: 0 };
}
export const Tag = {
encode(message: Tag, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.name !== "") {
writer.uint32(10).string(message.name);
}
if (message.creatorId !== 0) {
writer.uint32(16).int32(message.creatorId);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): Tag {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseTag();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.name = reader.string();
continue;
case 2:
if (tag !== 16) {
break;
}
message.creatorId = reader.int32();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<Tag>): Tag {
return Tag.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<Tag>): Tag {
const message = createBaseTag();
message.name = object.name ?? "";
message.creatorId = object.creatorId ?? 0;
return message;
},
};
function createBaseListTagsRequest(): ListTagsRequest {
return { creatorId: 0 };
}
export const ListTagsRequest = {
encode(message: ListTagsRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.creatorId !== 0) {
writer.uint32(8).int32(message.creatorId);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): ListTagsRequest {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseListTagsRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 8) {
break;
}
message.creatorId = reader.int32();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<ListTagsRequest>): ListTagsRequest {
return ListTagsRequest.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<ListTagsRequest>): ListTagsRequest {
const message = createBaseListTagsRequest();
message.creatorId = object.creatorId ?? 0;
return message;
},
};
function createBaseListTagsResponse(): ListTagsResponse {
return { tags: [] };
}
export const ListTagsResponse = {
encode(message: ListTagsResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
for (const v of message.tags) {
Tag.encode(v!, writer.uint32(10).fork()).ldelim();
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): ListTagsResponse {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseListTagsResponse();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.tags.push(Tag.decode(reader, reader.uint32()));
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<ListTagsResponse>): ListTagsResponse {
return ListTagsResponse.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<ListTagsResponse>): ListTagsResponse {
const message = createBaseListTagsResponse();
message.tags = object.tags?.map((e) => Tag.fromPartial(e)) || [];
return message;
},
};
export type TagServiceDefinition = typeof TagServiceDefinition;
export const TagServiceDefinition = {
name: "TagService",
fullName: "memos.api.v2.TagService",
methods: {
listTags: {
name: "ListTags",
requestType: ListTagsRequest,
requestStream: false,
responseType: ListTagsResponse,
responseStream: false,
options: {
_unknownFields: {
578365826: [new Uint8Array([14, 18, 12, 47, 97, 112, 105, 47, 118, 50, 47, 116, 97, 103, 115])],
},
},
},
},
} as const;
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
This diff is collapsed.
/* eslint-disable */
import Long from "long";
import _m0 from "protobufjs/minimal";
export const protobufPackage = "google.protobuf";
/**
* A Timestamp represents a point in time independent of any time zone or local
* calendar, encoded as a count of seconds and fractions of seconds at
* nanosecond resolution. The count is relative to an epoch at UTC midnight on
* January 1, 1970, in the proleptic Gregorian calendar which extends the
* Gregorian calendar backwards to year one.
*
* All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
* second table is needed for interpretation, using a [24-hour linear
* smear](https://developers.google.com/time/smear).
*
* The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
* restricting to that range, we ensure that we can convert to and from [RFC
* 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
*
* # Examples
*
* Example 1: Compute Timestamp from POSIX `time()`.
*
* Timestamp timestamp;
* timestamp.set_seconds(time(NULL));
* timestamp.set_nanos(0);
*
* Example 2: Compute Timestamp from POSIX `gettimeofday()`.
*
* struct timeval tv;
* gettimeofday(&tv, NULL);
*
* Timestamp timestamp;
* timestamp.set_seconds(tv.tv_sec);
* timestamp.set_nanos(tv.tv_usec * 1000);
*
* Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
*
* FILETIME ft;
* GetSystemTimeAsFileTime(&ft);
* UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
*
* // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
* // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
* Timestamp timestamp;
* timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
* timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
*
* Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
*
* long millis = System.currentTimeMillis();
*
* Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
* .setNanos((int) ((millis % 1000) * 1000000)).build();
*
* Example 5: Compute Timestamp from Java `Instant.now()`.
*
* Instant now = Instant.now();
*
* Timestamp timestamp =
* Timestamp.newBuilder().setSeconds(now.getEpochSecond())
* .setNanos(now.getNano()).build();
*
* Example 6: Compute Timestamp from current time in Python.
*
* timestamp = Timestamp()
* timestamp.GetCurrentTime()
*
* # JSON Mapping
*
* In JSON format, the Timestamp type is encoded as a string in the
* [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
* format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
* where {year} is always expressed using four digits while {month}, {day},
* {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
* seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
* are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
* is required. A proto3 JSON serializer should always use UTC (as indicated by
* "Z") when printing the Timestamp type and a proto3 JSON parser should be
* able to accept both UTC and other timezones (as indicated by an offset).
*
* For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
* 01:30 UTC on January 15, 2017.
*
* In JavaScript, one can convert a Date object to this format using the
* standard
* [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
* method. In Python, a standard `datetime.datetime` object can be converted
* to this format using
* [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
* the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
* the Joda Time's [`ISODateTimeFormat.dateTime()`](
* http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
* ) to obtain a formatter capable of generating timestamps in this format.
*/
export interface Timestamp {
/**
* Represents seconds of UTC time since Unix epoch
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
* 9999-12-31T23:59:59Z inclusive.
*/
seconds: number;
/**
* Non-negative fractions of a second at nanosecond resolution. Negative
* second values with fractions must still have non-negative nanos values
* that count forward in time. Must be from 0 to 999,999,999
* inclusive.
*/
nanos: number;
}
function createBaseTimestamp(): Timestamp {
return { seconds: 0, nanos: 0 };
}
export const Timestamp = {
encode(message: Timestamp, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.seconds !== 0) {
writer.uint32(8).int64(message.seconds);
}
if (message.nanos !== 0) {
writer.uint32(16).int32(message.nanos);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): Timestamp {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseTimestamp();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 8) {
break;
}
message.seconds = longToNumber(reader.int64() as Long);
continue;
case 2:
if (tag !== 16) {
break;
}
message.nanos = reader.int32();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
create(base?: DeepPartial<Timestamp>): Timestamp {
return Timestamp.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<Timestamp>): Timestamp {
const message = createBaseTimestamp();
message.seconds = object.seconds ?? 0;
message.nanos = object.nanos ?? 0;
return message;
},
};
declare const self: any | undefined;
declare const window: any | undefined;
declare const global: any | undefined;
const tsProtoGlobalThis: any = (() => {
if (typeof globalThis !== "undefined") {
return globalThis;
}
if (typeof self !== "undefined") {
return self;
}
if (typeof window !== "undefined") {
return window;
}
if (typeof global !== "undefined") {
return global;
}
throw "Unable to locate global object";
})();
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
: T extends Array<infer U> ? Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
function longToNumber(long: Long): number {
if (long.gt(Number.MAX_SAFE_INTEGER)) {
throw new tsProtoGlobalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
}
return long.toNumber();
}
if (_m0.util.Long !== Long) {
_m0.util.Long = Long as any;
_m0.configure();
}
import react from "@vitejs/plugin-react-swc";
import { resolve } from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
let devProxyServer = "http://localhost:8081/";
if (process.env.DEV_PROXY_SERVER && process.env.DEV_PROXY_SERVER.length > 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment