Compare commits

...

74 Commits

Author SHA1 Message Date
YunShu c49e49cf33
chore: upgrade Go version to 1.18 (#612)
Packages A and B use the `any` keyword, so the minimum requirement for casibase is 1.18.
2023-08-17 02:47:55 +08:00
Yang Luo 032ee3a6b1 Fix renderSigninIfNotSignedIn() 2023-08-15 17:35:41 +08:00
Yang Luo bf22093cde Add getModelProviderFromContext() 2023-08-15 16:43:20 +08:00
Yang Luo 8c79294a7b Add ModelProvider to Store 2023-08-15 16:20:31 +08:00
Kelvin Chiu 83a4697c9d fix: update knowledge retrieval function (#609)
* fix: fix redirect not working error

* feat: update knowledge retrieval function

* fix: optimized the logic of retrieve function
2023-08-15 15:34:10 +08:00
Yang Luo 2ad4e9b5ba Fix ai_test.go 2023-08-14 11:17:19 +08:00
Yang Luo c85b305661 Improve TextArea 2023-08-14 02:53:19 +08:00
Yang Luo 66a5021eb7 Improve filterTextFiles() 2023-08-14 02:47:44 +08:00
Yang Luo 081b88a2be Fix getAccount() bug 2023-08-14 02:44:28 +08:00
Kelvin Chiu 737dd4df4e feat: add refresh store vectors (#608)
* feat: add refresh store vectors

* fix: clean the object.Url from casdoorsdk
2023-08-14 02:26:25 +08:00
Yang Luo 12d4afc0d9 Change vector data to []float32 2023-08-14 01:54:49 +08:00
Yang Luo 3037214b93 Use casdoorsdk to call API 2023-08-04 00:09:50 +08:00
yehong a5c4d250f9
feat: change chat box style (#606) 2023-08-02 15:36:31 +08:00
Yang Luo 6a218f8258 Add getStorageProviders() 2023-07-31 00:09:13 +08:00
Yang Luo 195d9cfdca Remove resource.go 2023-07-30 23:51:45 +08:00
Yang Luo da3193673c Add empty provider check 2023-07-30 23:43:10 +08:00
Yang Luo b099e837f9 Fix res naming 2023-07-30 23:31:15 +08:00
Yang Luo 960f08188f Add user, parent and tag 2023-07-30 23:19:57 +08:00
Yang Luo 15dbed335e Fix file URL 2023-07-30 22:58:11 +08:00
Yang Luo f93d3f90dd ListObjects() works now 2023-07-30 22:05:04 +08:00
Yang Luo 23a2de182f Rename bucket to storage provider 2023-07-30 19:08:01 +08:00
Yang Luo 9c3f8aed8b Fix ListObjects() 2023-07-30 16:46:52 +08:00
Yang Luo ec45d9e5eb Refactor the storage code 2023-07-30 15:58:45 +08:00
Yang Luo 2a2e8f66d7 Add license headers 2023-07-30 15:24:24 +08:00
Yang Luo 61d2b70116 Remove rclone code 2023-07-30 14:52:13 +08:00
WintBit 789241364c
feat: support Casdoor storage API (#594)
* feat: Casdoor storage API

* chore: fmt casdoor.go using gofumpt

* feat: add global casdoor config variables
2023-07-29 19:24:38 +08:00
TieStone 95db4c2edd
docs: Resolve broken image display in README.md (#604) 2023-07-26 10:41:21 +08:00
Yang Luo 28c24c51f7 Improve initServerUrl() 2023-07-24 10:59:56 +08:00
yehong b27a9a925d
feat: add Dockerfile (#600) 2023-07-23 22:19:47 +08:00
Kelvin Chiu b185161aa9
fix: set default value for the message owner (#597) 2023-07-23 09:38:52 +08:00
Yang Luo 43e8dabc2c Add getDefaultModelProvider() 2023-07-22 23:22:38 +08:00
Yang Luo f478db4af8 Remove tree's scrollbar 2023-07-22 23:15:56 +08:00
Yang Luo 444e3a3841 Add GetMaskedProvider() 2023-07-22 23:09:08 +08:00
Yang Luo 31bface6bd Adjust tree height 2023-07-22 22:16:25 +08:00
Yang Luo 46209eb83f Improve default store logic 2023-07-22 22:11:56 +08:00
github-actions[bot] 65d3fc6341
refactor: New Crowdin translations by Github Action (#596)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-07-22 21:23:02 +08:00
YunShu a5723e1a52
ci: add crowdin configuration file and i18n files (#595)
* ci: add crowdin configuration file and i18n files

* fix: update i18n regex
2023-07-22 21:10:14 +08:00
yehong 854213baae
feat: add CI (#593)
* feat: add CI

* Update semantic.yml

* Update .releaserc.json

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-07-22 18:42:02 +08:00
Yang Luo 23a56d8623 ci: fix crowdin configs 2023-07-22 12:39:01 +08:00
Kelvin Chiu fe0df16ac1
feat: add chat page (#589)
* feat: add chat page

* feat: add chat page

* Update ai.go

* Update ai_test.go

* Update message.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-07-22 11:14:07 +08:00
yehong 96af811a12
feat: add Github CI (#590)
* feat: add CI

* feat: add CI and run gofumpt

* Update conf.go

* Delete migrate.yml

* Update sync.yml

* Update conf.go

* Update file_cache.go

* Update adapter.go

* Update semantic.yml

* Update storage_test.go

* Update file_cache.go

* Update conf.go

* Update adapter.go

* Update conf.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-07-22 10:17:17 +08:00
Kelvin Chiu d6e982c89a
feat: update antd to v5.2.3 (#586)
* feat: update antd to v5.2.3

* fix: rightdropdown className

* feat: modify frontend appearance

* fix: fix ResizeObserver loop error in action

* fix: modify frontend codes style

* fix: modify frontend codes style
2023-07-21 13:04:29 +08:00
Yang Luo c68ccd739f Add vector pages 2023-07-17 14:46:39 +08:00
Kelvin Chiu 084c36d4af
feat: add message list (#18) 2023-07-16 19:01:15 +08:00
Yang Luo 8e6880bdc0 Add renderExternalLink() 2023-07-16 16:42:58 +08:00
Yang Luo f89602338e Add EnableExtraPages 2023-07-16 16:40:32 +08:00
Yang Luo fb87ef67a3 Rename vector to factor 2023-07-16 16:27:37 +08:00
Yang Luo 9bb5846360 Update provider categories 2023-07-16 16:14:56 +08:00
Kelvin Chiu 67dd3dc260 feat: add chats list (#17) 2023-07-16 16:03:45 +08:00
Yang Luo d74a763224 Add getCurrentStore() 2023-07-16 14:39:18 +08:00
Yang Luo 480194e1eb Add rclone.go 2023-07-16 13:22:06 +08:00
Yang Luo af135a7469 Add license headers 2023-07-16 12:51:52 +08:00
Yang Luo d08776146a Add updateAllHeaders() 2023-07-16 12:50:14 +08:00
Yang Luo 5dd0581a0e Improve load default store in home 2023-07-16 10:41:44 +08:00
Yang Luo ac76b1fb9b Add provider pages 2023-07-16 02:55:36 +08:00
Yang Luo e59f9e5664 Improve randomName 2023-07-16 02:44:18 +08:00
Yang Luo 10a99d2e1c Improve action column width 2023-07-16 02:28:27 +08:00
Kelvin Chiu 49d8ae8918
feat: Improve language UI element and support more UI languages (#15)
* feat: Improve language UI element and support more UI languages

* feat: Improve language UI element and support more UI languages
2023-07-08 14:46:10 +08:00
Yang Luo 414aa0a377 Fix store edit links 2023-07-08 11:47:51 +08:00
Yang Luo 01494c40bb Depress the plugin-proposal-private-property-in-object warning 2023-07-08 11:44:51 +08:00
Yang Luo 8d717a8b93 Add Go error handlings 2023-07-08 11:42:56 +08:00
Yang Luo b3f5d9ea06 Fix getPermissions() crash issue. 2023-07-08 11:23:05 +08:00
Kelvin Chiu 98113c7663
feat: Add ResponseError to show error message in frontend (#14) 2023-07-08 11:19:56 +08:00
Yang Luo 4f2bb85535 Regenerate yarn.lock 2023-07-07 23:47:22 +08:00
Yang Luo 8379aeef46 Update react to 18.2.0 2023-07-07 23:29:48 +08:00
Yang Luo c6a130039c Add some eslint rules, refer to: https://github.com/casdoor/casdoor/pull/973 2023-07-07 23:13:58 +08:00
YunShu f9221e7a81
docs: replace gitter links with discord (#12) 2023-07-06 18:18:20 +08:00
Yang Luo 9600a5a9a1 Add eslint-plugin-unused-imports dependency 2023-06-26 10:29:10 +08:00
Xinhao Yuan 3aa25da75b
feat: add .eslintrc and format all code (#11) 2023-06-26 10:17:56 +08:00
Kelvin Chiu 7c56c63893
docs: Add introduction to frontend conf (#8) 2023-06-23 21:53:12 +08:00
Kelvin Chiu 3205ac7dc5
docs: created a draft version of README.md (#7) 2023-06-23 15:10:16 +08:00
Yang Luo 0b9c3ab502 Set initial store name to "default" 2023-06-23 01:29:46 +08:00
Yang Luo b857398c80 Fix panic in ListObjects() 2023-06-23 00:03:51 +08:00
Yang Luo b453e60eb8 Rename to casibase 2023-06-23 00:03:29 +08:00
184 changed files with 15441 additions and 5497 deletions

12
.github/semantic.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# Always validate the PR title AND all the commits
titleAndCommits: true
# Require at least one commit to be valid
# this is only relevant when using commitsOnly: true or titleAndCommits: true,
# which validate all commits by default
anyCommit: true
# Allow use of Merge commits (eg on github: "Merge branch 'master' into feature/ride-unicorns")
# this is only relevant when using commitsOnly: true (or titleAndCommits: true)
allowMergeCommits: false
# Allow use of Revert commits (eg on github: "Revert "feat: ride unicorns"")
# this is only relevant when using commitsOnly: true (or titleAndCommits: true)
allowRevertCommits: false

154
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,154 @@
name: Build
on: [push, pull_request]
jobs:
go-tests:
name: Running Go tests
runs-on: ubuntu-latest
services:
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
cache-dependency-path: ./go.mod
- name: Tests
run: |
# go test -v $(go list ./...) -tags skipCi
working-directory: ./
frontend:
name: Front-end
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: ./web/yarn.lock
- run: yarn install && CI=false yarn run build
working-directory: ./web
backend:
name: Back-end
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
cache-dependency-path: ./go.mod
- run: go version
- name: Build
run: |
go build -race -ldflags "-extldflags '-static'"
working-directory: ./
linter:
name: Go-Linter
runs-on: ubuntu-latest
needs: [ go-tests ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v4
with:
go-version: '^1.18.0'
cache: false
# gen a dummy config file
- run: touch dummy.yml
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --disable-all -c dummy.yml -E=gofumpt --max-same-issues=0 --timeout 5m --modules-download-mode=mod
release-and-push:
name: Release And Push
runs-on: ubuntu-latest
if: github.repository == 'casbin/casibase' && github.event_name == 'push'
needs: [ frontend, backend, linter]
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: -1
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Fetch Previous version
id: get-previous-tag
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
- name: Release
run: yarn global add semantic-release@17.4.4 && semantic-release
env:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
- name: Fetch Current version
id: get-current-tag
uses: actions-ecosystem/action-get-latest-tag@v1.6.0
- name: Decide Should_Push Or Not
id: should_push
run: |
old_version=${{steps.get-previous-tag.outputs.tag}}
new_version=${{steps.get-current-tag.outputs.tag }}
old_array=(${old_version//\./ })
new_array=(${new_version//\./ })
if [ ${old_array[0]} != ${new_array[0]} ]
then
echo ::set-output name=push::'true'
elif [ ${old_array[1]} != ${new_array[1]} ]
then
echo ::set-output name=push::'true'
else
echo ::set-output name=push::'false'
fi
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
if: github.repository == 'casbin/casibase' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Push to Docker Hub
uses: docker/build-push-action@v3
if: github.repository == 'casbin/casibase' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
context: .
target: STANDARD
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casibase:${{steps.get-current-tag.outputs.tag }},casbin/casibase:latest

56
.github/workflows/sync.yml vendored Normal file
View File

@ -0,0 +1,56 @@
name: Crowdin Action
on:
push:
branches: [ master ]
jobs:
synchronize-with-crowdin:
runs-on: ubuntu-latest
if: github.repository == 'casbin/casibase' && github.event_name == 'push'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: crowdin action
uses: crowdin/github-action@1.4.8
with:
upload_translations: true
download_translations: true
push_translations: true
commit_message: 'refactor: New Crowdin translations by Github Action'
localization_branch_name: l10n_crowdin_action
create_pull_request: true
pull_request_title: 'refactor: New Crowdin translations'
crowdin_branch_name: l10n_branch
config: './web/crowdin.yml'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: '603051'
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
# - name: crowdin backend action
# uses: crowdin/github-action@1.4.8
# with:
# upload_translations: true
# download_translations: true
# push_translations: true
# commit_message: 'refactor: New Crowdin Backend translations by Github Action'
# localization_branch_name: l10n_crowdin_action
# create_pull_request: true
# pull_request_title: 'refactor: New Crowdin Backend translations'
# crowdin_branch_name: l10n_branch
# config: './crowdin.yml'
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# CROWDIN_PROJECT_ID: '603051'
# CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
*.dll
*.so
*.dylib
casibase
# Test binary, built with `go test -c`
*.test

23
.releaserc.json Normal file
View File

@ -0,0 +1,23 @@
{
"debug": true,
"branches": [
"+([0-9])?(.{+([0-9]),x}).x",
"master",
{
"name": "rc"
},
{
"name": "beta",
"prerelease": true
},
{
"name": "alpha",
"prerelease": true
}
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/github"
]
}

18
Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM golang:1.19 AS BACK
WORKDIR /go/src/casibase
COPY . .
RUN go build -o server ./main.go
FROM debian:latest AS STANDARD
LABEL MAINTAINER="https://casibase.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
WORKDIR /
COPY --from=BACK /go/src/casibase/ ./
ENTRYPOINT ["/bin/bash"]
CMD ["/docker-entrypoint.sh"]

160
README.md
View File

@ -1 +1,159 @@
# casbase
<h1 align="center" style="border-bottom: none;">📦⚡️ Casibase</h1>
<h3 align="center">A pioneering customizable open-source Domain Knowledge Base (DKB)
powered by ChatGPT, Casbin, and Casdoor.</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casibase">
<img alt="docker pull casbin/casibase" src="https://img.shields.io/docker/pulls/casbin/casibase.svg">
</a>
<a href="https://github.com/casbin/casibase/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casibase/casibase/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casbin/casibase.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casibase">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
<!-- waiting for changing -->
<!-- <a href="https://hub.docker.com/r/casbin/casibase"> -->
<!-- <a href="https://github.com/casbin/casibase/actions/workflows/build.yml"> -->
<!-- <a href="https://github.com/casibase/casibase/releases/latest"> -->
<!-- <a href="https://hub.docker.com/repository/docker/casbin/casibase"> -->
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casbin/casibase">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casbin/casibase?style=flat-square">
</a>
<a href="https://github.com/casbin/casibase/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casbin/casibase?style=flat-square" alt="license">
</a>
<a href="https://github.com/casbin/casibase/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casbin/casibase?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casbin/casibase?style=flat-square">
</a>
<a href="https://github.com/casbin/casibase/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casbin/casibase?style=flat-square">
</a>
<a href="https://crowdin.com/project/casibase">
<img alt="Crowdin" src="https://badges.crowdin.net/casibase/localized.svg">
</a>
<a href="https://discord.gg/devUNrWXrh">
<img alt="Discord" src="https://img.shields.io/discord/1022748306096537660?logo=discord&label=discord&color=5865F2">
</a>
</p>
## Architecture
casibase contains 4 parts:
| **Name** | **Description** | **Language** |
|----------------|---------------------------------------------------|-----------------------------------------|
| Frontend | User interface for the casibase application | JavaScript + React |
| Backend | Server-side logic and API for casibase | Golang + Beego + Python + Flask + MySQL |
| AI Model | Artificial intelligence model | Python + OpenAI |
| Knowledge Base | Storage for casibase application domain knowledge | pgvector |
![0-Architecture-casibase](assets/0-Architecture-casibase.png)
## Demo Installation
casibase uses Casdoor to manage members. So you need to create an organization and an application for casibase in a Casdoor instance.
### Casdoor configuration
```shell
git clone https://github.com/casdoor/casdoor.git
```
refer to: https://casdoor.org/docs/basic/server-installation
Follow these steps to setup Casdoor for casibase:
- Create an **Organization**![1-Add-organization](assets/1-Add-organization.png)
- Configure information about the **Organization**![2-Configure-information-organization](assets/2-Configure-information-organization.png)
- Add a member to a newly created organization![3-Check-user](assets/3-Check-user.png)![4-Add-member-to-organization](assets/4-Add-member-to-organization.png)
- Configure member information (remember its **Name** as well as **Password**)![5-Configure-new-user](assets/5-Configure-new-user.png)
- Create a new **Application**![6-Add-application](assets/6-Add-application.png)
- Configuring **Application** Information (Remember **Name, ClientID** and **ClientSecret**. Change **RedirectURLs** to http://localhost:14000/callback) ![7-Configure-new-application](assets/7-Configure-new-application.png)
### casibase configuration
#### Get the code
```shell
git clone https://github.com/casbin/casibase.git
```
#### Setup database
casibase will store its users, nodes and topics informations in a MySQL database named: `casibase`, will create it if not existed. The DB connection string can be specified at: https://github.com/casbin/casibase/blob/master/conf/app.conf
```ini
dataSourceName = root:123@tcp(localhost:3306)/
```
Casnode uses XORM to connect to DB, so all DBs supported by XORM can also be used.
#### Custom config
- #### Backend (`casibase\conf\app.conf`)
```ini
casdoorEndpoint = <Your_Casdoor_endpoint>
clientId = <Your_clientId_in_Casdoor_configuration>
clientSecret = <Your_clientSecret_in_Casdoor_configuration>
casdoorOrganization = "casibase"
casdoorApplication = "app-casibase"
```
- #### Frontend (`casibase\web\src\Conf.js`)
```ini
export const AuthConfig = {
......
clientId: <Your_clientId_in_Casdoor_configuration>,
......
};
```
#### Run casnode
- #### Backend (`casibase`)
```shell
go run main.go
```
- #### Frontend (`casibase\web`)
```shell
yarn install
yarn start
```
#### Preview
Access the login view via the following link:
```shell
http://localhost:13001
```
![8-Preview-base-wordsets](assets/8-Preview-base-wordsets.png)
![9-Preview-casibase-stores](assets/9-Preview-casibase-stores.png)
The **casibase** demo is shown above, and in the future users can upload various **knowledge** files, **wordsets**, and **factorsets** to achieve a **customized domain knowledge base**.

148
ai/ai.go Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/sashabaranov/go-openai"
)
func queryAnswer(authToken string, question string, timeout int) (string, error) {
// fmt.Printf("Question: %s\n", question)
client := getProxyClientFromToken(authToken)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(2+timeout*2)*time.Second)
defer cancel()
resp, err := client.CreateChatCompletion(
ctx,
openai.ChatCompletionRequest{
Model: openai.GPT3Dot5Turbo,
Messages: []openai.ChatCompletionMessage{
{
Role: openai.ChatMessageRoleUser,
Content: question,
},
},
},
)
if err != nil {
return "", err
}
res := resp.Choices[0].Message.Content
res = strings.Trim(res, "\n")
// fmt.Printf("Answer: %s\n\n", res)
return res, nil
}
func QueryAnswerSafe(authToken string, question string) string {
var res string
var err error
for i := 0; i < 10; i++ {
res, err = queryAnswer(authToken, question, i)
if err != nil {
if i > 0 {
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
}
} else {
break
}
}
if err != nil {
panic(err)
}
return res
}
func QueryAnswerStream(authToken string, question string, writer io.Writer, builder *strings.Builder) error {
client := getProxyClientFromToken(authToken)
ctx := context.Background()
flusher, ok := writer.(http.Flusher)
if !ok {
return fmt.Errorf("writer does not implement http.Flusher")
}
// https://platform.openai.com/tokenizer
// https://github.com/pkoukk/tiktoken-go#available-encodings
promptTokens, err := GetTokenSize(openai.GPT3TextDavinci003, question)
if err != nil {
return err
}
// https://platform.openai.com/docs/models/gpt-3-5
maxTokens := 4097 - promptTokens
respStream, err := client.CreateCompletionStream(
ctx,
openai.CompletionRequest{
Model: openai.GPT3TextDavinci003,
Prompt: question,
MaxTokens: maxTokens,
Stream: true,
},
)
if err != nil {
return err
}
defer respStream.Close()
isLeadingReturn := true
for {
completion, streamErr := respStream.Recv()
if streamErr != nil {
if streamErr == io.EOF {
break
}
return streamErr
}
data := completion.Choices[0].Text
if isLeadingReturn && len(data) != 0 {
if strings.Count(data, "\n") == len(data) {
continue
} else {
isLeadingReturn = false
}
}
fmt.Printf("%s", data)
// Write the streamed data as Server-Sent Events
if _, err = fmt.Fprintf(writer, "event: message\ndata: %s\n\n", data); err != nil {
return err
}
flusher.Flush()
// Append the response to the strings.Builder
builder.WriteString(data)
}
return nil
}
func GetQuestionWithKnowledge(knowledge string, question string) string {
return fmt.Sprintf(`paragraph: %s
You are a reading comprehension expert. Please answer the following questions based on the provided content. The content may be in a different language from the questions, so you need to understand the content according to the language of the questions and ensure that your answers are translated into the same language as the questions:
Q1: %s`, knowledge, question)
}

39
ai/ai_test.go Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !skipCi
// +build !skipCi
package ai_test
import (
"testing"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/proxy"
"github.com/sashabaranov/go-openai"
)
func TestRun(t *testing.T) {
object.InitConfig()
proxy.InitHttpClient()
text := ai.QueryAnswerSafe("", "hi")
println(text)
}
func TestToken(t *testing.T) {
println(ai.GetTokenSize(openai.GPT3TextDavinci003, ""))
}

105
ai/embedding.go Normal file
View File

@ -0,0 +1,105 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
import (
"bufio"
"context"
"fmt"
"io"
"time"
"github.com/sashabaranov/go-openai"
)
func splitTxt(f io.ReadCloser) []string {
const maxLength = 210 * 3
scanner := bufio.NewScanner(f)
var res []string
var temp string
for scanner.Scan() {
line := scanner.Text()
if len(temp)+len(line) <= maxLength {
temp += line
} else {
res = append(res, temp)
temp = line
}
}
if len(temp) > 0 {
res = append(res, temp)
}
return res
}
func GetSplitTxt(f io.ReadCloser) []string {
return splitTxt(f)
}
func getEmbedding(authToken string, text string, timeout int) ([]float32, error) {
client := getProxyClientFromToken(authToken)
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(30+timeout*2)*time.Second)
defer cancel()
resp, err := client.CreateEmbeddings(ctx, openai.EmbeddingRequest{
Input: []string{text},
Model: openai.AdaEmbeddingV2,
})
if err != nil {
return nil, err
}
return resp.Data[0].Embedding, nil
}
func GetEmbeddingSafe(authToken string, text string) ([]float32, error) {
var embedding []float32
var err error
for i := 0; i < 10; i++ {
embedding, err = getEmbedding(authToken, text, i)
if err != nil {
if i > 0 {
fmt.Printf("\tFailed (%d): %s\n", i+1, err.Error())
}
} else {
break
}
}
if err != nil {
return nil, err
} else {
return embedding, nil
}
}
func GetNearestVectorIndex(target []float32, vectors [][]float32) int {
targetNorm := norm(target)
var res int
max := float32(-1.0)
for i, vector := range vectors {
similarity := cosineSimilarity(target, vector, targetNorm)
if similarity > max {
max = similarity
res = i
}
}
return res
}

28
ai/proxy.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
import (
"github.com/casbin/casibase/proxy"
"github.com/sashabaranov/go-openai"
)
func getProxyClientFromToken(authToken string) *openai.Client {
config := openai.DefaultConfig(authToken)
config.HTTPClient = proxy.ProxyHttpClient
c := openai.NewClientWithConfig(config)
return c
}

61
ai/util.go Normal file
View File

@ -0,0 +1,61 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ai
import (
"math"
"github.com/pkoukk/tiktoken-go"
)
func GetTokenSize(model string, prompt string) (int, error) {
tkm, err := tiktoken.EncodingForModel(model)
if err != nil {
return 0, err
}
token := tkm.Encode(prompt, nil, nil)
res := len(token)
return res, nil
}
func cosineSimilarity(vec1, vec2 []float32, vec1Norm float32) float32 {
dotProduct := dot(vec1, vec2)
vec2Norm := norm(vec2)
if vec2Norm == 0 {
return 0.0
}
return dotProduct / (vec1Norm * vec2Norm)
}
func dot(vec1, vec2 []float32) float32 {
if len(vec1) != len(vec2) {
panic("Vector lengths do not match")
}
dotProduct := float32(0.0)
for i := range vec1 {
dotProduct += vec1[i] * vec2[i]
}
return dotProduct
}
func norm(vec []float32) float32 {
normSquared := float32(0.0)
for _, val := range vec {
normSquared += val * val
}
return float32(math.Sqrt(float64(normSquared)))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
assets/3-Check-user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -1,75 +0,0 @@
package casdoor
import (
"runtime"
"github.com/astaxie/beego"
_ "github.com/go-sql-driver/mysql"
"xorm.io/xorm"
)
var adapter *Adapter = nil
var CasdoorOrganization string
type Session struct {
SessionKey string `xorm:"char(64) notnull pk"`
SessionData []uint8 `xorm:"blob"`
SessionExpiry int `xorm:"notnull"`
}
func InitCasdoorAdapter() {
casdoorDbName := beego.AppConfig.String("casdoorDbName")
if casdoorDbName == "" {
return
}
adapter = NewAdapter(beego.AppConfig.String("driverName"), beego.AppConfig.String("dataSourceName"), beego.AppConfig.String("casdoorDbName"))
CasdoorOrganization = beego.AppConfig.String("casdoorOrganization")
}
// Adapter represents the MySQL adapter for policy storage.
type Adapter struct {
driverName string
dataSourceName string
dbName string
Engine *xorm.Engine
}
// finalizer is the destructor for Adapter.
func finalizer(a *Adapter) {
err := a.Engine.Close()
if err != nil {
panic(err)
}
}
// NewAdapter is the constructor for Adapter.
func NewAdapter(driverName string, dataSourceName string, dbName string) *Adapter {
a := &Adapter{}
a.driverName = driverName
a.dataSourceName = dataSourceName
a.dbName = dbName
// Open the DB, create it if not existed.
a.open()
// Call the destructor when the object is released.
runtime.SetFinalizer(a, finalizer)
return a
}
func (a *Adapter) open() {
Engine, err := xorm.NewEngine(a.driverName, a.dataSourceName+a.dbName)
if err != nil {
panic(err)
}
a.Engine = Engine
}
func (a *Adapter) close() {
a.Engine.Close()
a.Engine = nil
}

View File

@ -1,95 +0,0 @@
package casdoor
import (
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type Permission struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Users []string `xorm:"mediumtext" json:"users"`
Roles []string `xorm:"mediumtext" json:"roles"`
Domains []string `xorm:"mediumtext" json:"domains"`
Model string `xorm:"varchar(100)" json:"model"`
ResourceType string `xorm:"varchar(100)" json:"resourceType"`
Resources []string `xorm:"mediumtext" json:"resources"`
Actions []string `xorm:"mediumtext" json:"actions"`
Effect string `xorm:"varchar(100)" json:"effect"`
IsEnabled bool `json:"isEnabled"`
Submitter string `xorm:"varchar(100)" json:"submitter"`
Approver string `xorm:"varchar(100)" json:"approver"`
ApproveTime string `xorm:"varchar(100)" json:"approveTime"`
State string `xorm:"varchar(100)" json:"state"`
}
func GetPermissions(owner string) []*Permission {
permissions := []*Permission{}
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner})
if err != nil {
panic(err)
}
return permissions
}
func getPermission(owner string, name string) *Permission {
if owner == "" || name == "" {
return nil
}
permission := Permission{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&permission)
if err != nil {
panic(err)
}
if existed {
return &permission
} else {
return nil
}
}
func GetPermission(id string) *Permission {
owner, name := util.GetOwnerAndNameFromId(id)
return getPermission(owner, name)
}
func UpdatePermission(id string, permission *Permission) bool {
owner, name := util.GetOwnerAndNameFromId(id)
oldPermission := getPermission(owner, name)
if oldPermission == nil {
return false
}
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(permission)
if err != nil {
panic(err)
}
return affected != 0
}
func AddPermission(permission *Permission) bool {
affected, err := adapter.Engine.Insert(permission)
if err != nil {
panic(err)
}
return affected != 0
}
func DeletePermission(permission *Permission) bool {
affected, err := adapter.Engine.ID(core.PK{permission.Owner, permission.Name}).Delete(&Permission{})
if err != nil {
panic(err)
}
return affected != 0
}

View File

@ -1,18 +1,18 @@
appname = casbase
appname = casibase
httpport = 14000
runmode = dev
SessionOn = true
copyrequestbody = true
driverName = mysql
dataSourceName = root:123@tcp(localhost:3306)/
dbName = casbase
dbName = casibase
redisEndpoint =
landingFolder = casbase-landing
landingFolder = casibase-landing
casdoorEndpoint = http://localhost:8000
clientId = af6b5aa958822fb9dc33
clientSecret = 8bc3010c1c951c8d876b1f311a901ff8deeb93bc
casdoorDbName = casdoor
casdoorOrganization = "casbin"
casdoorApplication = "app-casbase"
cacheDir = "C:/casbase_cache"
appDir = ""
casdoorApplication = "app-casibase"
cacheDir = "C:/casibase_cache"
appDir = ""
socks5Proxy = "127.0.0.1:10808"

119
conf/conf.go Normal file
View File

@ -0,0 +1,119 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package conf
import (
"os"
"runtime"
"strconv"
"strings"
"github.com/astaxie/beego"
)
func init() {
// this array contains the beego configuration items that may be modified via env
presetConfigItems := []string{"httpport", "appname"}
for _, key := range presetConfigItems {
if value, ok := os.LookupEnv(key); ok {
err := beego.AppConfig.Set(key, value)
if err != nil {
panic(err)
}
}
}
}
func GetConfigString(key string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
res := beego.AppConfig.String(key)
if res == "" {
if key == "staticBaseUrl" {
res = "https://cdn.casbin.org"
} else if key == "logConfig" {
res = "{\"filename\": \"logs/casdoor.log\", \"maxdays\":99999, \"perm\":\"0770\"}"
}
}
return res
}
func GetConfigBool(key string) bool {
value := GetConfigString(key)
if value == "true" {
return true
} else {
return false
}
}
func GetConfigInt64(key string) (int64, error) {
value := GetConfigString(key)
num, err := strconv.ParseInt(value, 10, 64)
return num, err
}
func GetConfigDataSourceName() string {
dataSourceName := GetConfigString("dataSourceName")
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
if runningInDocker == "true" {
// https://stackoverflow.com/questions/48546124/what-is-linux-equivalent-of-host-docker-internal
if runtime.GOOS == "linux" {
dataSourceName = strings.ReplaceAll(dataSourceName, "localhost", "172.17.0.1")
} else {
dataSourceName = strings.ReplaceAll(dataSourceName, "localhost", "host.docker.internal")
}
}
return dataSourceName
}
func GetLanguage(language string) string {
if language == "" || language == "*" {
return "en"
}
if len(language) != 2 || language == "nu" {
return "en"
} else {
return language
}
}
func IsDemoMode() bool {
return strings.ToLower(GetConfigString("isDemoMode")) == "true"
}
func GetConfigBatchSize() int {
res, err := strconv.Atoi(GetConfigString("batchSize"))
if err != nil {
res = 100
}
return res
}
func GetConfigRealDataSourceName(driverName string) string {
var dataSourceName string
if driverName != "mysql" {
dataSourceName = GetConfigDataSourceName()
} else {
dataSourceName = GetConfigDataSourceName() + GetConfigString("dbName")
}
return dataSourceName
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (

108
controllers/chat.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casibase/object"
)
func (c *ApiController) GetGlobalChats() {
chats, err := object.GetGlobalChats()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(chats)
}
func (c *ApiController) GetChats() {
owner := "admin"
chats, err := object.GetChats(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(chats)
}
func (c *ApiController) GetChat() {
id := c.Input().Get("id")
chat, err := object.GetChat(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(chat)
}
func (c *ApiController) UpdateChat() {
id := c.Input().Get("id")
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateChat(id, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddChat() {
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
chat.Owner = "admin"
success, err := object.AddChat(&chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteChat() {
var chat object.Chat
err := json.Unmarshal(c.Ctx.Input.RequestBody, &chat)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteChat(&chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

108
controllers/factorset.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casibase/object"
)
func (c *ApiController) GetGlobalFactorsets() {
factorsets, err := object.GetGlobalFactorsets()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(factorsets)
}
func (c *ApiController) GetFactorsets() {
owner := c.Input().Get("owner")
factorsets, err := object.GetFactorsets(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(factorsets)
}
func (c *ApiController) GetFactorset() {
id := c.Input().Get("id")
factorset, err := object.GetFactorset(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(factorset)
}
func (c *ApiController) UpdateFactorset() {
id := c.Input().Get("id")
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateFactorset(id, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddFactorset() {
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.AddFactorset(&factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteFactorset() {
var factorset object.Factorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteFactorset(&factorset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -1,10 +1,24 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"mime/multipart"
"github.com/casbin/casbase/object"
"github.com/casbin/casibase/object"
)
func (c *ApiController) UpdateFile() {
@ -19,7 +33,8 @@ func (c *ApiController) UpdateFile() {
var file object.File
err := json.Unmarshal(c.Ctx.Input.RequestBody, &file)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
res := object.UpdateFile(storeId, key, &file)
@ -27,8 +42,7 @@ func (c *ApiController) UpdateFile() {
addRecordForFile(c, userName, "Update", storeId, key, "", true)
}
c.Data["json"] = res
c.ServeJSON()
c.ResponseOk(res)
}
func (c *ApiController) AddFile() {
@ -53,14 +67,18 @@ func (c *ApiController) AddFile() {
defer file.Close()
}
res, bs := object.AddFile(storeId, key, isLeaf, filename, file)
res, bs, err := object.AddFile(storeId, userName, key, isLeaf, filename, file)
if err != nil {
c.ResponseError(err.Error())
return
}
if res {
addFileToCache(key, filename, bs)
addRecordForFile(c, userName, "Add", storeId, key, filename, isLeaf)
}
c.Data["json"] = res
c.ServeJSON()
c.ResponseOk(res)
}
func (c *ApiController) DeleteFile() {
@ -73,11 +91,15 @@ func (c *ApiController) DeleteFile() {
key := c.Input().Get("key")
isLeaf := c.Input().Get("isLeaf") == "1"
res := object.DeleteFile(storeId, key, isLeaf)
res, err := object.DeleteFile(storeId, key, isLeaf)
if err != nil {
c.ResponseError(err.Error())
return
}
if res {
addRecordForFile(c, userName, "Delete", storeId, key, "", isLeaf)
}
c.Data["json"] = res
c.ServeJSON()
c.ResponseOk(res)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
@ -5,12 +19,14 @@ import (
"strings"
"github.com/astaxie/beego"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
)
var cacheDir string
var appDir string
var cacheMap = map[string]string{}
var (
cacheDir string
appDir string
cacheMap = map[string]string{}
)
func init() {
cacheDir = beego.AppConfig.String("cacheDir")
@ -53,8 +69,7 @@ func (c *ApiController) ActivateFile() {
prefix := getCachePrefix(filename)
if prefix == "" {
c.Data["json"] = false
c.ServeJSON()
c.ResponseOk(false)
return
}
@ -66,8 +81,7 @@ func (c *ApiController) ActivateFile() {
util.CopyFile(getAppPath(filename), getAppPath(prefix))
}
c.Data["json"] = true
c.ServeJSON()
c.ResponseOk(true)
}
func (c *ApiController) GetActiveFile() {
@ -78,6 +92,5 @@ func (c *ApiController) GetActiveFile() {
res = v
}
c.Data["json"] = res
c.ServeJSON()
c.ResponseOk(res)
}

299
controllers/message.go Normal file
View File

@ -0,0 +1,299 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"fmt"
"strings"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/util"
)
func (c *ApiController) GetGlobalMessages() {
messages, err := object.GetGlobalMessages()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(messages)
}
func (c *ApiController) GetMessages() {
owner := "admin"
chat := c.Input().Get("chat")
if chat == "" {
messages, err := object.GetMessages(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(messages)
return
}
messages, err := object.GetChatMessages(chat)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(messages)
}
func (c *ApiController) GetMessage() {
id := c.Input().Get("id")
message, err := object.GetMessage(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(message)
}
func (c *ApiController) ResponseErrorStream(errorText string) {
event := fmt.Sprintf("event: myerror\ndata: %s\n\n", errorText)
_, err := c.Ctx.ResponseWriter.Write([]byte(event))
if err != nil {
c.ResponseError(err.Error())
return
}
}
func getModelProviderFromContext(owner string, name string) (*object.Provider, error) {
var providerName string
if name != "" {
providerName = name
} else {
store, err := object.GetDefaultStore(owner)
if err != nil {
return nil, err
}
if store.ModelProvider != "" {
providerName = store.ModelProvider
}
}
var provider *object.Provider
var err error
if providerName != "" {
providerId := util.GetIdFromOwnerAndName(owner, providerName)
provider, err = object.GetProvider(providerId)
} else {
provider, err = object.GetDefaultModelProvider()
}
if provider == nil && err == nil {
return nil, fmt.Errorf("The provider: %s is not found", providerName)
} else {
return provider, err
}
}
func (c *ApiController) GetMessageAnswer() {
id := c.Input().Get("id")
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
message, err := object.GetMessage(id)
if err != nil {
c.ResponseError(err.Error())
return
}
if message == nil {
c.ResponseErrorStream(fmt.Sprintf("The message: %s is not found", id))
return
}
if message.Author != "AI" || message.ReplyTo == "" || message.Text != "" {
c.ResponseErrorStream("The message is invalid")
return
}
chatId := util.GetIdFromOwnerAndName("admin", message.Chat)
chat, err := object.GetChat(chatId)
if err != nil {
c.ResponseError(err.Error())
return
}
//if chat == nil || chat.Organization != message.Organization {
// c.ResponseErrorStream(fmt.Sprintf("The chat: %s is not found", chatId))
// return
//}
if chat.Type != "AI" {
c.ResponseErrorStream("The chat type must be \"AI\"")
return
}
questionMessage, err := object.GetMessage(message.ReplyTo)
if questionMessage == nil {
c.ResponseErrorStream(fmt.Sprintf("The message: %s is not found", id))
return
}
provider, err := getModelProviderFromContext(chat.Owner, chat.User2)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider.Category != "Model" || provider.ClientSecret == "" {
c.ResponseErrorStream(fmt.Sprintf("The provider: %s is invalid", provider.GetId()))
return
}
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
authToken := provider.ClientSecret
question := questionMessage.Text
var stringBuilder strings.Builder
nearestText, err := object.GetNearestVectorText(authToken, chat.Owner, question)
if err != nil {
c.ResponseErrorStream(err.Error())
return
}
realQuestion := ai.GetQuestionWithKnowledge(nearestText, question)
fmt.Printf("Question: [%s]\n", question)
fmt.Printf("Context: [%s]\n", nearestText)
fmt.Printf("Answer: [")
err = ai.QueryAnswerStream(authToken, realQuestion, c.Ctx.ResponseWriter, &stringBuilder)
if err != nil {
c.ResponseErrorStream(err.Error())
return
}
fmt.Printf("]\n")
event := fmt.Sprintf("event: end\ndata: %s\n\n", "end")
_, err = c.Ctx.ResponseWriter.Write([]byte(event))
if err != nil {
c.ResponseError(err.Error())
return
}
answer := stringBuilder.String()
message.Text = answer
_, err = object.UpdateMessage(message.GetId(), message)
if err != nil {
c.ResponseError(err.Error())
return
}
}
func (c *ApiController) UpdateMessage() {
id := c.Input().Get("id")
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateMessage(id, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddMessage() {
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
var chat *object.Chat
if message.Chat != "" {
chatId := util.GetId("admin", message.Chat)
chat, err = object.GetChat(chatId)
if err != nil {
c.ResponseError(err.Error())
return
}
if chat == nil {
c.ResponseError(fmt.Sprintf("chat:The chat: %s is not found", chatId))
return
}
}
success, err := object.AddMessage(&message)
if err != nil {
c.ResponseError(err.Error())
return
}
if success {
if chat != nil && chat.Type == "AI" {
answerMessage := &object.Message{
Owner: message.Owner,
Name: fmt.Sprintf("message_%s", util.GetRandomName()),
CreatedTime: util.GetCurrentTimeEx(message.CreatedTime),
// Organization: message.Organization,
Chat: message.Chat,
ReplyTo: message.GetId(),
Author: "AI",
Text: "",
}
_, err = object.AddMessage(answerMessage)
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteMessage() {
var message object.Message
err := json.Unmarshal(c.Ctx.Input.RequestBody, &message)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteMessage(&message)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -1,56 +1,95 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/casdoor"
"github.com/casbin/casibase/util"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
func (c *ApiController) GetPermissions() {
owner := c.Input().Get("owner")
permissions, err := casdoorsdk.GetPermissions()
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = casdoor.GetPermissions(owner)
c.ServeJSON()
c.ResponseOk(permissions)
}
func (c *ApiController) GetPermission() {
id := c.Input().Get("id")
_, name := util.GetOwnerAndNameFromId(id)
c.Data["json"] = casdoor.GetPermission(id)
c.ServeJSON()
permission, err := casdoorsdk.GetPermission(name)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(permission)
}
func (c *ApiController) UpdatePermission() {
id := c.Input().Get("id")
var permission casdoor.Permission
var permission casdoorsdk.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
}
c.Data["json"] = casdoor.UpdatePermission(id, &permission)
c.ServeJSON()
success, err := casdoorsdk.UpdatePermission(&permission)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddPermission() {
var permission casdoor.Permission
var permission casdoorsdk.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = casdoor.AddPermission(&permission)
c.ServeJSON()
success, err := casdoorsdk.AddPermission(&permission)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeletePermission() {
var permission casdoor.Permission
var permission casdoorsdk.Permission
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permission)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = casdoor.DeletePermission(&permission)
c.ServeJSON()
success, err := casdoorsdk.DeletePermission(&permission)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

109
controllers/provider.go Normal file
View File

@ -0,0 +1,109 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casibase/object"
)
func (c *ApiController) GetGlobalProviders() {
providers, err := object.GetGlobalProviders()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedProviders(providers, true))
}
func (c *ApiController) GetProviders() {
owner := "admin"
providers, err := object.GetProviders(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedProviders(providers, true))
}
func (c *ApiController) GetProvider() {
id := c.Input().Get("id")
provider, err := object.GetProvider(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetMaskedProvider(provider, true))
}
func (c *ApiController) UpdateProvider() {
id := c.Input().Get("id")
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateProvider(id, &provider)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
c.ResponseError(err.Error())
return
}
provider.Owner = "admin"
success, err := object.AddProvider(&provider)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteProvider() {
var provider object.Provider
err := json.Unmarshal(c.Ctx.Input.RequestBody, &provider)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteProvider(&provider)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -0,0 +1,44 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import "github.com/casdoor/casdoor-go-sdk/casdoorsdk"
func getStorageProviders() ([]*casdoorsdk.Provider, error) {
providers, err := casdoorsdk.GetProviders()
if err != nil {
return providers, err
}
res := []*casdoorsdk.Provider{}
for _, provider := range providers {
if provider.Category == "Storage" {
res = append(res, provider)
}
}
return res, nil
}
func (c *ApiController) GetStorageProviders() {
// owner := c.Input().Get("owner")
providers, err := getStorageProviders()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(providers)
}

View File

@ -1,36 +1,74 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
"github.com/casbin/casibase/object"
)
func (c *ApiController) GetGlobalStores() {
c.Data["json"] = object.GetGlobalStores()
c.ServeJSON()
stores, err := object.GetGlobalStores()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(stores)
}
func (c *ApiController) GetStores() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetStores(owner)
c.ServeJSON()
stores, err := object.GetStores(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(stores)
}
func (c *ApiController) GetStore() {
id := c.Input().Get("id")
store := object.GetStore(id)
var store *object.Store
var err error
if id == "admin/_casibase_default_store_" {
store, err = object.GetDefaultStore("admin")
} else {
store, err = object.GetStore(id)
}
if err != nil {
c.ResponseError(err.Error())
return
}
if store == nil {
c.ResponseError("store is empty")
return
}
store.Populate()
err = store.Populate()
if err != nil {
// gentle error
c.ResponseOk(store, err.Error())
return
}
c.Data["json"] = store
c.ServeJSON()
c.ResponseOk(store)
}
func (c *ApiController) UpdateStore() {
@ -39,31 +77,66 @@ func (c *ApiController) UpdateStore() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.UpdateStore(id, &store)
c.ServeJSON()
success, err := object.UpdateStore(id, &store)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddStore() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.AddStore(&store)
c.ServeJSON()
sucess, err := object.AddStore(&store)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(sucess)
}
func (c *ApiController) DeleteStore() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.DeleteStore(&store)
c.ServeJSON()
sucess, err := object.DeleteStore(&store)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(sucess)
}
func (c *ApiController) RefreshStoreVectors() {
var store object.Store
err := json.Unmarshal(c.Ctx.Input.RequestBody, &store)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.RefreshStoreVectors(&store)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
type Response struct {

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
@ -5,7 +19,7 @@ import (
"strings"
"github.com/astaxie/beego/context"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
@ -37,7 +51,12 @@ func addRecord(c *ApiController, userName string, requestUri string) {
record.RequestUri = requestUri
}
util.SafeGoroutine(func() { casdoorsdk.AddRecord(record) })
util.SafeGoroutine(func() {
_, err := casdoorsdk.AddRecord(record)
if err != nil {
panic(err)
}
})
}
func addRecordForFile(c *ApiController, userName string, action string, storeId string, key string, filename string, isLeaf bool) {

108
controllers/vector.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casibase/object"
)
func (c *ApiController) GetGlobalVectors() {
vectors, err := object.GetGlobalVectors()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(vectors)
}
func (c *ApiController) GetVectors() {
owner := c.Input().Get("owner")
vectors, err := object.GetVectors(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(vectors)
}
func (c *ApiController) GetVector() {
id := c.Input().Get("id")
vector, err := object.GetVector(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(vector)
}
func (c *ApiController) UpdateVector() {
id := c.Input().Get("id")
var vector object.Vector
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vector)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.UpdateVector(id, &vector)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddVector() {
var vector object.Vector
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vector)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.AddVector(&vector)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteVector() {
var vector object.Vector
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vector)
if err != nil {
c.ResponseError(err.Error())
return
}
success, err := object.DeleteVector(&vector)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

View File

@ -1,61 +0,0 @@
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
)
func (c *ApiController) GetGlobalVectorsets() {
c.Data["json"] = object.GetGlobalVectorsets()
c.ServeJSON()
}
func (c *ApiController) GetVectorsets() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetVectorsets(owner)
c.ServeJSON()
}
func (c *ApiController) GetVectorset() {
id := c.Input().Get("id")
c.Data["json"] = object.GetVectorset(id)
c.ServeJSON()
}
func (c *ApiController) UpdateVectorset() {
id := c.Input().Get("id")
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.UpdateVectorset(id, &vectorset)
c.ServeJSON()
}
func (c *ApiController) AddVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.AddVectorset(&vectorset)
c.ServeJSON()
}
func (c *ApiController) DeleteVectorset() {
var vectorset object.Vectorset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &vectorset)
if err != nil {
panic(err)
}
c.Data["json"] = object.DeleteVectorset(&vectorset)
c.ServeJSON()
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
@ -7,31 +21,49 @@ import (
"io"
"time"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/video"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/util"
"github.com/casbin/casibase/video"
)
func (c *ApiController) GetGlobalVideos() {
c.Data["json"] = object.GetGlobalVideos()
c.ServeJSON()
videos, err := object.GetGlobalVideos()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(videos)
}
func (c *ApiController) GetVideos() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetVideos(owner)
c.ServeJSON()
videos, err := object.GetVideos(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(videos)
}
func (c *ApiController) GetVideo() {
id := c.Input().Get("id")
video := object.GetVideo(id)
video.Populate()
video, err := object.GetVideo(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = video
c.ServeJSON()
err = video.Populate()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(video)
}
func (c *ApiController) UpdateVideo() {
@ -40,33 +72,51 @@ func (c *ApiController) UpdateVideo() {
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.UpdateVideo(id, &video)
c.ServeJSON()
success, err := object.UpdateVideo(id, &video)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddVideo() {
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.AddVideo(&video)
c.ServeJSON()
success, err := object.AddVideo(&video)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteVideo() {
var video object.Video
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.DeleteVideo(&video)
c.ServeJSON()
success, err := object.DeleteVideo(&video)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func startCoverUrlJob(owner string, name string, videoId string) {
@ -74,7 +124,7 @@ func startCoverUrlJob(owner string, name string, videoId string) {
for i := 0; i < 20; i++ {
coverUrl := video.GetVideoCoverUrl(videoId)
if coverUrl != "" {
video := object.GetVideo(util.GetIdFromOwnerAndName(owner, name))
video, _ := object.GetVideo(util.GetIdFromOwnerAndName(owner, name))
if video.CoverUrl != "" {
break
}
@ -94,7 +144,8 @@ func (c *ApiController) UploadVideo() {
file, header, err := c.GetFile("file")
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
defer file.Close()
@ -129,7 +180,12 @@ func (c *ApiController) UploadVideo() {
Labels: []*object.Label{},
DataUrls: []string{},
}
object.AddVideo(video)
_, err = object.AddVideo(video)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(fileId)
} else {
c.ResponseError("videoId is empty")

View File

@ -1,29 +1,55 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/util"
)
func (c *ApiController) GetGlobalWordsets() {
c.Data["json"] = object.GetGlobalWordsets()
c.ServeJSON()
wordsets, err := object.GetGlobalWordsets()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(wordsets)
}
func (c *ApiController) GetWordsets() {
owner := c.Input().Get("owner")
c.Data["json"] = object.GetWordsets(owner)
c.ServeJSON()
wordsets, err := object.GetWordsets(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(wordsets)
}
func (c *ApiController) GetWordset() {
id := c.Input().Get("id")
c.Data["json"] = object.GetWordset(id)
c.ServeJSON()
wordset, err := object.GetWordset(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(wordset)
}
func (c *ApiController) GetWordsetGraph() {
@ -31,15 +57,23 @@ func (c *ApiController) GetWordsetGraph() {
clusterNumber := util.ParseInt(c.Input().Get("clusterNumber"))
distanceLimit := util.ParseInt(c.Input().Get("distanceLimit"))
c.Data["json"] = object.GetWordsetGraph(id, clusterNumber, distanceLimit)
c.ServeJSON()
g, err := object.GetWordsetGraph(id, clusterNumber, distanceLimit)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(g)
}
func (c *ApiController) GetWordsetMatch() {
id := c.Input().Get("id")
c.Data["json"] = object.GetWordsetMatch(id)
c.ServeJSON()
wordset, err := object.GetWordsetMatch(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(wordset)
}
func (c *ApiController) UpdateWordset() {
@ -48,31 +82,46 @@ func (c *ApiController) UpdateWordset() {
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.UpdateWordset(id, &wordset)
c.ServeJSON()
success, err := object.UpdateWordset(id, &wordset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) AddWordset() {
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.AddWordset(&wordset)
c.ServeJSON()
success, err := object.AddWordset(&wordset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}
func (c *ApiController) DeleteWordset() {
var wordset object.Wordset
err := json.Unmarshal(c.Ctx.Input.RequestBody, &wordset)
if err != nil {
panic(err)
c.ResponseError(err.Error())
return
}
c.Data["json"] = object.DeleteWordset(&wordset)
c.ServeJSON()
success, err := object.DeleteWordset(&wordset)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(success)
}

8
docker-entrypoint.sh Normal file
View File

@ -0,0 +1,8 @@
#!/bin/bash
if [ "${MYSQL_ROOT_PASSWORD}" = "" ] ;then MYSQL_ROOT_PASSWORD=123456 ;fi
service mariadb start
mysqladmin -u root password ${MYSQL_ROOT_PASSWORD}
exec /server --createDatabase=true

74
go.mod
View File

@ -1,31 +1,71 @@
module github.com/casbin/casbase
module github.com/casbin/casibase
go 1.16
go 1.18
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible
github.com/astaxie/beego v1.12.3
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/casdoor/casdoor-go-sdk v0.9.1
github.com/casdoor/casdoor-go-sdk v0.28.1
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/google/uuid v1.2.0
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/google/uuid v1.3.0
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762
github.com/muesli/kmeans v0.3.0
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/pkoukk/tiktoken-go v0.1.1
github.com/sashabaranov/go-openai v1.12.0
github.com/tealeg/xlsx v1.0.5
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 // indirect
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
gonum.org/v1/gonum v0.9.3
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
golang.org/x/net v0.8.0
golang.org/x/time v0.3.0
gonum.org/v1/gonum v0.11.0
xorm.io/core v0.7.3
xorm.io/xorm v1.2.5
)
require (
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/dlclark/regexp2 v1.8.1 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/gomega v1.27.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.36.3 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.17.1 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.18.1 // indirect
modernc.org/strutil v1.1.3 // indirect
xorm.io/builder v0.3.9 // indirect
)

231
go.sum
View File

@ -31,7 +31,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@ -44,11 +43,11 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 h1:ECnkjykkSn3Gsibjd8FrcC+8SMDJcUbJOP4iT2hItrw=
@ -75,16 +74,17 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/casdoor/casdoor-go-sdk v0.9.1 h1:z+5nJ4IvP9cNUodLf8wS42AYtDoUCvN6McRB5M+1SAQ=
github.com/casdoor/casdoor-go-sdk v0.9.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/casdoor/casdoor-go-sdk v0.28.1 h1:z0b36oEsU9PzCxHlYWmRY1ZMLSnUW3MVRDv6I7hWy9E=
github.com/casdoor/casdoor-go-sdk v0.28.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -114,6 +114,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@ -130,27 +132,26 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@ -158,8 +159,10 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.7.4 h1:B44qRUFwz/vxPKPISQ1KhvzRi9kZ28RAf6YtjriBZ5k=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
@ -168,8 +171,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@ -197,11 +200,15 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -213,8 +220,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -227,8 +237,8 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -261,7 +271,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -320,25 +329,27 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -369,8 +380,9 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
@ -391,14 +403,16 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 h1:p4A2Jx7Lm3NV98VRMKlyWd3nqf8obft8NfXlAUmqd3I=
github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY=
github.com/muesli/kmeans v0.3.0 h1:cI2cpeS8m3pm+gTOdzl+7SlzZYSe+x0XoqXUyUvb1ro=
github.com/muesli/kmeans v0.3.0/go.mod h1:eNyybq0tX9/iBEP6EMU4Y7dpmGK0uEhODdZpnG1a/iQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
@ -407,16 +421,23 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.27.1 h1:rfztXRbg6nv/5f+Raen9RcGoSecHIFgBBLQK3Wdj754=
github.com/onsi/gomega v1.27.1/go.mod h1:aHX5xOykVYzWOV4WqQy0sy8BQptgukenXpCXfadcIAw=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@ -433,15 +454,14 @@ github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkoukk/tiktoken-go v0.1.1 h1:jtkYlIECjyM9OW1w4rjPmTohK4arORP9V25y6TM6nXo=
github.com/pkoukk/tiktoken-go v0.1.1/go.mod h1:boMWvk9pQCOTx11pgu0DrIdrAKgQzzJKUP6vLXaz7Rw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@ -449,41 +469,53 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sashabaranov/go-openai v1.12.0 h1:aRNHH0gtVfrpIaEolD0sWrLLRnYQNK4cH/bIAHwL8Rk=
github.com/sashabaranov/go-openai v1.12.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@ -499,6 +531,7 @@ github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@ -516,8 +549,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
@ -574,33 +607,23 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -618,8 +641,8 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -650,23 +673,27 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 h1:3B43BWw0xEBsLZ/NO1VALz6fppU3481pik+2Ksv45z8=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -676,6 +703,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -697,7 +725,9 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -718,16 +748,23 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -737,22 +774,20 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
@ -768,7 +803,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -798,23 +832,17 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78 h1:M8tBwCtWD/cZV9DZpFYRUgaymAYAr+aIUTWzDaM3uPs=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
gonum.org/v1/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s=
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY=
gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E=
gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -839,8 +867,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -897,8 +926,11 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -908,7 +940,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
@ -925,11 +956,12 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -938,35 +970,48 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g=
modernc.org/ccgo/v3 v3.9.5 h1:dEuUSf8WN51rDkprFuAqjfchKEzN0WttP/Py3enBwjk=
modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg=
modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60=
modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM=
modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.9.11 h1:QUxZMs48Ahg2F7SN41aERvMfGLY2HU/ADnB9DC4Yts8=
modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q=
modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0=
modernc.org/libc v1.17.1 h1:Q8/Cpi36V/QBfuQaFVeisEBs3WqoGAJprZzmf7TfEYI=
modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.0 h1:GCjoRaBew8ECCKINQA2nYjzvufFW9YiEuuB+rQ9bn2E=
modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/memory v1.2.1 h1:dkRh86wgmq/bJu2cAS2oqBCz/KsMZU7TUM4CibQ7eBs=
modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import (
@ -7,7 +21,7 @@ import (
"regexp"
"strings"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
)
type I18nData map[string]map[string]string
@ -15,7 +29,7 @@ type I18nData map[string]map[string]string
var reI18n *regexp.Regexp
func init() {
reI18n, _ = regexp.Compile("i18next.t\\(\"(.*)\"\\)")
reI18n, _ = regexp.Compile("i18next.t\\(\"(.*?)\"\\)")
}
func getAllI18nStrings(fileContent string) []string {

View File

@ -1,14 +1,39 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import "testing"
func applyToOtherLanguage(dataEn *I18nData, lang string) {
dataOther := readI18nFile(lang)
println(dataOther)
applyData(dataEn, dataOther)
writeI18nFile(lang, dataEn)
}
func TestGenerateI18nStrings(t *testing.T) {
dataEn := parseToData()
writeI18nFile("en", dataEn)
dataZh := readI18nFile("zh")
println(dataZh)
applyData(dataEn, dataZh)
writeI18nFile("zh", dataEn)
applyToOtherLanguage(dataEn, "zh")
applyToOtherLanguage(dataEn, "fr")
applyToOtherLanguage(dataEn, "de")
applyToOtherLanguage(dataEn, "id")
applyToOtherLanguage(dataEn, "ja")
applyToOtherLanguage(dataEn, "ko")
applyToOtherLanguage(dataEn, "ru")
applyToOtherLanguage(dataEn, "es")
}

View File

@ -1,9 +1,23 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import (
"fmt"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
)
func getI18nFilePath(language string) string {

24
main.go
View File

@ -1,17 +1,31 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/plugins/cors"
_ "github.com/astaxie/beego/session/redis"
"github.com/casbin/casbase/casdoor"
"github.com/casbin/casbase/object"
"github.com/casbin/casbase/routers"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/proxy"
"github.com/casbin/casibase/routers"
)
func main() {
object.InitAdapter()
casdoor.InitCasdoorAdapter()
proxy.InitHttpClient()
beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
AllowOrigins: []string{"*"},
@ -21,7 +35,7 @@ func main() {
AllowCredentials: true,
}))
//beego.DelStaticPath("/static")
// beego.DelStaticPath("/static")
beego.SetStaticPath("/static", "web/build/static")
// https://studygolang.com/articles/2303
beego.InsertFilter("/", beego.BeforeRouter, routers.TransparentStatic) // must has this for default page

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
@ -62,7 +76,11 @@ func (a *Adapter) createDatabase() error {
defer engine.Close()
_, err = engine.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s default charset utf8 COLLATE utf8_general_ci", beego.AppConfig.String("dbName")))
return err
if err != nil {
return err
}
return nil
}
func (a *Adapter) open() {
@ -90,7 +108,7 @@ func (a *Adapter) createTable() {
panic(err)
}
err = a.engine.Sync2(new(Vectorset))
err = a.engine.Sync2(new(Factorset))
if err != nil {
panic(err)
}
@ -104,4 +122,24 @@ func (a *Adapter) createTable() {
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Provider))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Vector))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Chat))
if err != nil {
panic(err)
}
err = a.engine.Sync2(new(Message))
if err != nil {
panic(err)
}
}

129
object/chat.go Normal file
View File

@ -0,0 +1,129 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
type Chat struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
// Organization string `xorm:"varchar(100)" json:"organization"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
User1 string `xorm:"varchar(100)" json:"user1"`
User2 string `xorm:"varchar(100)" json:"user2"`
Users []string `xorm:"varchar(100)" json:"users"`
MessageCount int `json:"messageCount"`
}
func GetGlobalChats() ([]*Chat, error) {
chats := []*Chat{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&chats)
if err != nil {
return chats, err
}
return chats, nil
}
func GetChats(owner string) ([]*Chat, error) {
chats := []*Chat{}
err := adapter.engine.Desc("created_time").Find(&chats, &Chat{Owner: owner})
if err != nil {
return chats, err
}
return chats, nil
}
func getChat(owner, name string) (*Chat, error) {
chat := Chat{Owner: "admin", Name: name}
existed, err := adapter.engine.Get(&chat)
if err != nil {
return nil, err
}
if existed {
return &chat, nil
} else {
return nil, nil
}
}
func GetChat(id string) (*Chat, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getChat(owner, name)
}
func UpdateChat(id string, chat *Chat) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getChat(owner, name)
if err != nil {
return false, err
}
if chat == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(chat)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddChat(chat *Chat) (bool, error) {
if chat.Type == "AI" && chat.User2 == "" {
provider, err := GetDefaultModelProvider()
if err != nil {
return false, err
}
if provider != nil {
chat.User2 = provider.Name
}
}
affected, err := adapter.engine.Insert(chat)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteChat(chat *Chat) (bool, error) {
affected, err := adapter.engine.ID(core.PK{chat.Owner, chat.Name}).Delete(&Chat{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (chat *Chat) GetId() string {
return fmt.Sprintf("%s/%s", chat.Owner, chat.Name)
}

35
object/factor.go Normal file
View File

@ -0,0 +1,35 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
)
type Factor struct {
Name string `xorm:"varchar(100)" json:"name"`
Category string `xorm:"varchar(100)" json:"category"`
Color string `xorm:"varchar(100)" json:"color"`
Data []float64 `xorm:"varchar(1000)" json:"data"`
}
func (factor *Factor) GetDataKey() string {
sData := []string{}
for _, f := range factor.Data {
sData = append(sData, fmt.Sprintf("%f", f))
}
return strings.Join(sData, "|")
}

119
object/factorset.go Normal file
View File

@ -0,0 +1,119 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
type Factorset struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(500)" json:"displayName"`
Url string `xorm:"varchar(100)" json:"url"`
FileName string `xorm:"varchar(100)" json:"fileName"`
FileSize string `xorm:"varchar(100)" json:"fileSize"`
Dimension int `json:"dimension"`
Count int `json:"count"`
Factors []*Factor `xorm:"mediumtext" json:"factors"`
AllFactors []*Factor `xorm:"-" json:"allFactors"`
FactorMap map[string]*Factor `xorm:"-" json:"factorMap"`
}
func GetGlobalFactorsets() ([]*Factorset, error) {
factorsets := []*Factorset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&factorsets)
if err != nil {
return factorsets, err
}
return factorsets, nil
}
func GetFactorsets(owner string) ([]*Factorset, error) {
factorsets := []*Factorset{}
err := adapter.engine.Desc("created_time").Find(&factorsets, &Factorset{Owner: owner})
if err != nil {
return factorsets, err
}
return factorsets, nil
}
func getFactorset(owner string, name string) (*Factorset, error) {
factorset := Factorset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&factorset)
if err != nil {
return &factorset, err
}
if existed {
return &factorset, nil
} else {
return nil, nil
}
}
func GetFactorset(id string) (*Factorset, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getFactorset(owner, name)
}
func UpdateFactorset(id string, factorset *Factorset) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getFactorset(owner, name)
if err != nil {
return false, err
}
if factorset == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(factorset)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddFactorset(factorset *Factorset) (bool, error) {
affected, err := adapter.engine.Insert(factorset)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteFactorset(factorset *Factorset) (bool, error) {
affected, err := adapter.engine.ID(core.PK{factorset.Owner, factorset.Name}).Delete(&Factorset{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (factorset *Factorset) GetId() string {
return fmt.Sprintf("%s/%s", factorset.Owner, factorset.Name)
}

73
object/factorset_tsne.go Normal file
View File

@ -0,0 +1,73 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/danaugrs/go-tsne/tsne"
"gonum.org/v1/gonum/mat"
)
func testTsne() {
b := mat.NewDense(5, 3, []float64{
0.1, 0.1, 0.1,
0.7, 0.7, 0.7,
0.1, 0.7, 0.5,
0.7, 0.1, 0.2,
0.1, 0.7, 0.5,
})
t := tsne.NewTSNE(2, 300, 100, 300, true)
Y := t.EmbedData(b, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
println(Y)
}
func (factorset *Factorset) DoTsne(dimension int) {
floatArray := []float64{}
for _, factor := range factorset.AllFactors {
floatArray = append(floatArray, factor.Data...)
}
X := mat.NewDense(len(factorset.AllFactors), factorset.Dimension, floatArray)
t := tsne.NewTSNE(dimension, 300, 100, 300, true)
Y := t.EmbedData(X, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
rowCount, columnCount := Y.Dims()
if rowCount != len(factorset.AllFactors) {
panic("rowCount != len(factorset.AllFactors)")
}
if columnCount != dimension {
panic("columnCount != dimension")
}
for i, factor := range factorset.AllFactors {
arr := []float64{}
for j := 0; j < dimension; j++ {
arr = append(arr, Y.At(i, j))
}
factor.Data = arr
}
}

View File

@ -0,0 +1,38 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"testing"
)
func TestDoFactorsetTsne(t *testing.T) {
InitConfig()
dimension := 50
// factorset := getFactorset("admin", "wikipedia")
factorset, _ := getFactorset("admin", "wordFactor_utf-8")
factorset.LoadFactors("../../tmpFiles/")
factorset.DoTsne(dimension)
factorset.Name = fmt.Sprintf("%s_Dim_%d", factorset.Name, dimension)
factorset.FileName = fmt.Sprintf("%s_Dim_%d.csv", factorset.FileName, dimension)
factorset.FileSize = ""
factorset.Dimension = dimension
factorset.WriteFactors("../../tmpFiles/")
AddFactorset(factorset)
}

View File

@ -0,0 +1,71 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"github.com/casbin/casibase/util"
)
func (factorset *Factorset) LoadFactors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, factorset.FileName))
var nameArray []string
var dataArray [][]float64
if strings.HasSuffix(factorset.FileName, ".csv") {
if strings.Contains(factorset.FileName, "_Dim_") {
nameArray, dataArray = util.LoadFactorFileByCsv2(path)
} else {
nameArray, dataArray = util.LoadFactorFileByCsv(path)
}
} else {
nameArray, dataArray = util.LoadFactorFileBySpace(path)
}
exampleFactors := []*Factor{}
factors := []*Factor{}
factorMap := map[string]*Factor{}
for i := 0; i < len(nameArray); i++ {
factor := &Factor{
Name: nameArray[i],
Data: dataArray[i],
}
if i < 100 {
exampleFactors = append(exampleFactors, factor)
}
factors = append(factors, factor)
factorMap[factor.Name] = factor
}
factorset.Factors = exampleFactors
factorset.AllFactors = factors
factorset.FactorMap = factorMap
}
func (factorset *Factorset) WriteFactors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, factorset.FileName))
rows := [][]string{}
for _, factor := range factorset.AllFactors {
row := util.FloatsToStrings(factor.Data)
row = append([]string{factor.Name}, row...)
rows = append(rows, row)
}
util.WriteCsvFile(path, &rows)
}

View File

@ -0,0 +1,26 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import "testing"
func TestUpdateFactorsetFactors(t *testing.T) {
InitConfig()
// factorset := getFactorset("admin", "wikipedia")
factorset, _ := getFactorset("admin", "wordFactor_utf-8")
factorset.LoadFactors("../../tmpFiles/")
UpdateFactorset(factorset.GetId(), factorset)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
@ -7,17 +21,20 @@ import (
"mime/multipart"
"strings"
"github.com/casbin/casbase/storage"
"github.com/casbin/casibase/storage"
)
func UpdateFile(storeId string, key string, file *File) bool {
return true
}
func AddFile(storeId string, key string, isLeaf bool, filename string, file multipart.File) (bool, []byte) {
store := GetStore(storeId)
func AddFile(storeId string, userName string, key string, isLeaf bool, filename string, file multipart.File) (bool, []byte, error) {
store, err := GetStore(storeId)
if err != nil {
return false, nil, err
}
if store == nil {
return false, nil
return false, nil, nil
}
var objectKey string
@ -26,33 +43,58 @@ func AddFile(storeId string, key string, isLeaf bool, filename string, file mult
objectKey = fmt.Sprintf("%s/%s", key, filename)
objectKey = strings.TrimLeft(objectKey, "/")
fileBuffer = bytes.NewBuffer(nil)
if _, err := io.Copy(fileBuffer, file); err != nil {
panic(err)
_, err = io.Copy(fileBuffer, file)
if err != nil {
return false, nil, err
}
bs := fileBuffer.Bytes()
err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer)
if err != nil {
return false, nil, err
}
return true, bs, nil
} else {
objectKey = fmt.Sprintf("%s/%s/_hidden.ini", key, filename)
objectKey = strings.TrimLeft(objectKey, "/")
fileBuffer = bytes.NewBuffer(nil)
}
bs := fileBuffer.Bytes()
err = storage.PutObject(store.StorageProvider, userName, store.Name, objectKey, fileBuffer)
if err != nil {
return false, nil, err
}
bs := fileBuffer.Bytes()
storage.PutObject(store.Bucket, objectKey, fileBuffer)
return true, bs
return true, bs, nil
}
}
func DeleteFile(storeId string, key string, isLeaf bool) bool {
store := GetStore(storeId)
func DeleteFile(storeId string, key string, isLeaf bool) (bool, error) {
store, err := GetStore(storeId)
if err != nil {
return false, err
}
if store == nil {
return false
return false, nil
}
if isLeaf {
storage.DeleteObject(store.Bucket, key)
err = storage.DeleteObject(store.StorageProvider, key)
if err != nil {
return false, err
}
} else {
objects := storage.ListObjects(store.Bucket, key)
objects, err := storage.ListObjects(store.StorageProvider, key)
if err != nil {
return false, err
}
for _, object := range objects {
storage.DeleteObject(store.Bucket, object.Key)
err = storage.DeleteObject(store.StorageProvider, object.Key)
if err != nil {
return false, err
}
}
}
return true
return true, nil
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
type Node struct {

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
@ -5,7 +19,7 @@ import (
"strconv"
"strings"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
"github.com/muesli/clusters"
"github.com/muesli/kmeans"
)
@ -18,19 +32,19 @@ func fa2Str(floatArray []float64) string {
return strings.Join(sData, "|")
}
func runKmeans(vectors []*Vector, clusterNumber int) {
vectorMap := map[string]*Vector{}
func runKmeans(factors []*Factor, clusterNumber int) {
factorMap := map[string]*Factor{}
var d clusters.Observations
for _, vector := range vectors {
if len(vector.Data) == 0 {
for _, factor := range factors {
if len(factor.Data) == 0 {
continue
}
dataKey := vector.GetDataKey()
vectorMap[dataKey] = vector
dataKey := factor.GetDataKey()
factorMap[dataKey] = factor
d = append(d, clusters.Coordinates(vector.Data))
d = append(d, clusters.Coordinates(factor.Data))
}
km := kmeans.New()
@ -48,20 +62,20 @@ func runKmeans(vectors []*Vector, clusterNumber int) {
floatArray := observation.Coordinates()
dataKey := fa2Str(floatArray)
vector, ok := vectorMap[dataKey]
factor, ok := factorMap[dataKey]
if !ok {
panic(fmt.Errorf("vectorMap vector not found, dataKey = %s", dataKey))
panic(fmt.Errorf("factorMap factor not found, dataKey = %s", dataKey))
}
vector.Category = strconv.Itoa(i)
vector.Color = color
factor.Category = strconv.Itoa(i)
factor.Color = color
}
}
}
func updateWordsetVectorCategories(owner string, wordsetName string) {
wordset := getWordset(owner, wordsetName)
func updateWordsetFactorCategories(owner string, wordsetName string) {
wordset, _ := getWordset(owner, wordsetName)
runKmeans(wordset.Vectors, 100)
runKmeans(wordset.Factors, 100)
UpdateWordset(wordset.GetId(), wordset)
}

View File

@ -1,9 +1,23 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import "testing"
func TestUpdateWordsetVectorCategories(t *testing.T) {
func TestUpdateWordsetFactorCategories(t *testing.T) {
InitConfig()
updateWordsetVectorCategories("admin", "word")
updateWordsetFactorCategories("admin", "word")
}

123
object/message.go Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
type Message struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
// Organization string `xorm:"varchar(100)" json:"organization"`
Chat string `xorm:"varchar(100) index" json:"chat"`
ReplyTo string `xorm:"varchar(100) index" json:"replyTo"`
Author string `xorm:"varchar(100)" json:"author"`
Text string `xorm:"mediumtext" json:"text"`
}
func GetGlobalMessages() ([]*Message, error) {
messages := []*Message{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&messages)
if err != nil {
return messages, err
}
return messages, nil
}
func GetChatMessages(chat string) ([]*Message, error) {
messages := []*Message{}
err := adapter.engine.Asc("created_time").Find(&messages, &Message{Chat: chat})
if err != nil {
return messages, err
}
return messages, nil
}
func GetMessages(owner string) ([]*Message, error) {
messages := []*Message{}
err := adapter.engine.Desc("created_time").Find(&messages, &Message{Owner: owner})
if err != nil {
return messages, err
}
return messages, nil
}
func getMessage(owner, name string) (*Message, error) {
message := Message{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&message)
if err != nil {
return &message, err
}
if existed {
return &message, nil
} else {
return nil, nil
}
}
func GetMessage(id string) (*Message, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getMessage(owner, name)
}
func UpdateMessage(id string, message *Message) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getMessage(owner, name)
if err != nil {
return false, err
}
if message == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(message)
if err != nil {
return false, err
}
return true, nil
}
func AddMessage(message *Message) (bool, error) {
affected, err := adapter.engine.Insert(message)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteMessage(message *Message) (bool, error) {
affected, err := adapter.engine.ID(core.PK{message.Owner, message.Name}).Delete(&Message{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (message *Message) GetId() string {
return fmt.Sprintf("%s/%s", message.Owner, message.Name)
}

156
object/provider.go Normal file
View File

@ -0,0 +1,156 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
type Provider struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Category string `xorm:"varchar(100)" json:"category"`
Type string `xorm:"varchar(100)" json:"type"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
ProviderUrl string `xorm:"varchar(200)" json:"providerUrl"`
}
func GetMaskedProvider(provider *Provider, isMaskEnabled bool) *Provider {
if !isMaskEnabled {
return provider
}
if provider == nil {
return nil
}
if provider.ClientSecret != "" {
provider.ClientSecret = "***"
}
return provider
}
func GetMaskedProviders(providers []*Provider, isMaskEnabled bool) []*Provider {
if !isMaskEnabled {
return providers
}
for _, provider := range providers {
provider = GetMaskedProvider(provider, isMaskEnabled)
}
return providers
}
func GetGlobalProviders() ([]*Provider, error) {
providers := []*Provider{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&providers)
if err != nil {
return providers, err
}
return providers, nil
}
func GetProviders(owner string) ([]*Provider, error) {
providers := []*Provider{}
err := adapter.engine.Desc("created_time").Find(&providers, &Provider{Owner: owner})
if err != nil {
return providers, err
}
return providers, nil
}
func getProvider(owner string, name string) (*Provider, error) {
provider := Provider{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&provider)
if err != nil {
return &provider, err
}
if existed {
return &provider, nil
} else {
return nil, nil
}
}
func GetProvider(id string) (*Provider, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getProvider(owner, name)
}
func GetDefaultModelProvider() (*Provider, error) {
provider := Provider{Owner: "admin", Category: "Model"}
existed, err := adapter.engine.Get(&provider)
if err != nil {
return &provider, err
}
if !existed {
return nil, nil
}
return &provider, nil
}
func UpdateProvider(id string, provider *Provider) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getProvider(owner, name)
if err != nil {
return false, err
}
if provider == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(provider)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddProvider(provider *Provider) (bool, error) {
affected, err := adapter.engine.Insert(provider)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteProvider(provider *Provider) (bool, error) {
affected, err := adapter.engine.ID(core.PK{provider.Owner, provider.Name}).Delete(&Provider{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (provider *Provider) GetId() string {
return fmt.Sprintf("%s/%s", provider.Owner, provider.Name)
}

View File

@ -1,9 +1,23 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
@ -13,6 +27,7 @@ type File struct {
Size int64 `json:"size"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
IsLeaf bool `json:"isLeaf"`
Url string `xorm:"varchar(255)" json:"url"`
Children []*File `xorm:"varchar(1000)" json:"children"`
ChildrenMap map[string]*File `xorm:"-" json:"-"`
@ -29,85 +44,125 @@ type Store struct {
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Bucket string `xorm:"varchar(100)" json:"bucket"`
Domain string `xorm:"varchar(100)" json:"domain"`
StorageProvider string `xorm:"varchar(100)" json:"storageProvider"`
ModelProvider string `xorm:"varchar(100)" json:"modelProvider"`
FileTree *File `xorm:"mediumtext" json:"fileTree"`
PropertiesMap map[string]*Properties `xorm:"mediumtext" json:"propertiesMap"`
}
func GetGlobalStores() []*Store {
func GetGlobalStores() ([]*Store, error) {
stores := []*Store{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&stores)
if err != nil {
panic(err)
return stores, err
}
return stores
return stores, nil
}
func GetStores(owner string) []*Store {
func GetStores(owner string) ([]*Store, error) {
stores := []*Store{}
err := adapter.engine.Desc("created_time").Find(&stores, &Store{Owner: owner})
if err != nil {
panic(err)
return stores, err
}
return stores
return stores, nil
}
func getStore(owner string, name string) *Store {
func GetDefaultStore(owner string) (*Store, error) {
stores, err := GetStores(owner)
if err != nil {
return nil, err
}
for _, store := range stores {
if store.StorageProvider != "" {
return store, nil
}
}
if len(stores) > 0 {
return stores[0], nil
}
return nil, nil
}
func getStore(owner string, name string) (*Store, error) {
store := Store{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&store)
if err != nil {
panic(err)
return &store, err
}
if existed {
return &store
return &store, nil
} else {
return nil
return nil, nil
}
}
func GetStore(id string) *Store {
func GetStore(id string) (*Store, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getStore(owner, name)
}
func UpdateStore(id string, store *Store) bool {
func UpdateStore(id string, store *Store) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if getStore(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(store)
_, err := getStore(owner, name)
if err != nil {
panic(err)
return false, err
}
if store == nil {
return false, nil
}
//return affected != 0
return true
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(store)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddStore(store *Store) bool {
func AddStore(store *Store) (bool, error) {
affected, err := adapter.engine.Insert(store)
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func DeleteStore(store *Store) bool {
func DeleteStore(store *Store) (bool, error) {
affected, err := adapter.engine.ID(core.PK{store.Owner, store.Name}).Delete(&Store{})
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func (store *Store) GetId() string {
return fmt.Sprintf("%s/%s", store.Owner, store.Name)
}
func RefreshStoreVectors(store *Store) (bool, error) {
provider, err := GetDefaultModelProvider()
if err != nil {
return false, err
}
authToken := provider.ClientSecret
success, err := setTxtObjectVector(authToken, store.StorageProvider, "", store.Name)
if err != nil {
return false, err
}
if !success {
return false, nil
}
return true, nil
}

View File

@ -1,15 +1,27 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
"github.com/casbin/casbase/storage"
"github.com/casbin/casibase/storage"
)
func (store *Store) createPathIfNotExisted(tokens []string, size int64, lastModifiedTime string, isLeaf bool) {
func (store *Store) createPathIfNotExisted(tokens []string, size int64, url string, lastModifiedTime string, isLeaf bool) {
currentFile := store.FileTree
for i, token := range tokens {
if currentFile.Children == nil {
@ -35,6 +47,7 @@ func (store *Store) createPathIfNotExisted(tokens []string, size int64, lastModi
Key: key,
Title: token,
IsLeaf: isLeafTmp,
Url: url,
Children: []*File{},
ChildrenMap: map[string]*File{},
}
@ -58,7 +71,7 @@ func (store *Store) createPathIfNotExisted(tokens []string, size int64, lastModi
}
}
func isObjectLeaf(object *oss.ObjectProperties) bool {
func isObjectLeaf(object *storage.Object) bool {
isLeaf := true
if object.Key[len(object.Key)-1] == '/' {
isLeaf = false
@ -66,8 +79,11 @@ func isObjectLeaf(object *oss.ObjectProperties) bool {
return isLeaf
}
func (store *Store) Populate() {
objects := storage.ListObjects(store.Bucket, "")
func (store *Store) Populate() error {
objects, err := storage.ListObjects(store.StorageProvider, "")
if err != nil {
return err
}
if store.FileTree == nil {
store.FileTree = &File{
@ -75,12 +91,13 @@ func (store *Store) Populate() {
Title: store.DisplayName,
CreatedTime: store.CreatedTime,
IsLeaf: false,
Url: "",
Children: []*File{},
ChildrenMap: map[string]*File{},
}
}
sortedObjects := []oss.ObjectProperties{}
sortedObjects := []*storage.Object{}
for _, object := range objects {
if strings.HasSuffix(object.Key, "/_hidden.ini") {
sortedObjects = append(sortedObjects, object)
@ -93,19 +110,25 @@ func (store *Store) Populate() {
}
for _, object := range sortedObjects {
lastModifiedTime := object.LastModified.Local().Format(time.RFC3339)
isLeaf := isObjectLeaf(&object)
lastModifiedTime := object.LastModified
isLeaf := isObjectLeaf(object)
size := object.Size
url := object.Url
tokens := strings.Split(strings.Trim(object.Key, "/"), "/")
store.createPathIfNotExisted(tokens, size, lastModifiedTime, isLeaf)
store.createPathIfNotExisted(tokens, size, url, lastModifiedTime, isLeaf)
//fmt.Printf("%s, %d, %v\n", object.Key, object.Size, object.LastModified)
// fmt.Printf("%s, %d, %v\n", object.Key, object.Size, object.LastModified)
}
return nil
}
func (store *Store) GetVideoData() []string {
objects := storage.ListObjects(store.Bucket, "2023/视频附件")
func (store *Store) GetVideoData() ([]string, error) {
objects, err := storage.ListObjects(store.StorageProvider, "2023/视频附件")
if err != nil {
return nil, err
}
res := []string{}
for _, object := range objects {
@ -113,9 +136,9 @@ func (store *Store) GetVideoData() []string {
continue
}
url := fmt.Sprintf("%s/%s", store.Domain, object.Key)
url := fmt.Sprintf("%s/%s", store.StorageProvider, object.Key)
res = append(res, url)
}
return res
return res, nil
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import "testing"
@ -5,7 +19,18 @@ import "testing"
func TestUpdateStoreFolders(t *testing.T) {
InitConfig()
store := getStore("admin", "default")
//store.Populate()
store.GetVideoData()
store, err := getStore("admin", "default")
if err != nil {
panic(err)
}
//err = store.Populate()
//if err != nil {
// panic(err)
//}
_, err = store.GetVideoData()
if err != nil {
panic(err)
}
}

View File

@ -1,21 +1,114 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"strings"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
type Vector struct {
Name string `xorm:"varchar(100)" json:"name"`
Category string `xorm:"varchar(100)" json:"category"`
Color string `xorm:"varchar(100)" json:"color"`
Data []float64 `xorm:"varchar(1000)" json:"data"`
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
Store string `xorm:"varchar(100)" json:"store"`
File string `xorm:"varchar(100)" json:"file"`
Text string `xorm:"mediumtext" json:"text"`
Data []float32 `xorm:"mediumtext" json:"data"`
}
func (vector *Vector) GetDataKey() string {
sData := []string{}
for _, f := range vector.Data {
sData = append(sData, fmt.Sprintf("%f", f))
func GetGlobalVectors() ([]*Vector, error) {
vectors := []*Vector{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&vectors)
if err != nil {
return vectors, err
}
return strings.Join(sData, "|")
return vectors, nil
}
func GetVectors(owner string) ([]*Vector, error) {
vectors := []*Vector{}
err := adapter.engine.Desc("created_time").Find(&vectors, &Vector{Owner: owner})
if err != nil {
return vectors, err
}
return vectors, nil
}
func getVector(owner string, name string) (*Vector, error) {
vector := Vector{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&vector)
if err != nil {
return &vector, err
}
if existed {
return &vector, nil
} else {
return nil, nil
}
}
func GetVector(id string) (*Vector, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getVector(owner, name)
}
func UpdateVector(id string, vector *Vector) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
_, err := getVector(owner, name)
if err != nil {
return false, err
}
if vector == nil {
return false, nil
}
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(vector)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddVector(vector *Vector) (bool, error) {
affected, err := adapter.engine.Insert(vector)
if err != nil {
return false, err
}
return affected != 0, nil
}
func DeleteVector(vector *Vector) (bool, error) {
affected, err := adapter.engine.ID(core.PK{vector.Owner, vector.Name}).Delete(&Vector{})
if err != nil {
return false, err
}
return affected != 0, nil
}
func (vector *Vector) GetId() string {
return fmt.Sprintf("%s/%s", vector.Owner, vector.Name)
}

168
object/vector_embedding.go Normal file
View File

@ -0,0 +1,168 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"context"
"fmt"
"io"
"net/http"
"strings"
"time"
"github.com/casbin/casibase/ai"
"github.com/casbin/casibase/storage"
"github.com/casbin/casibase/util"
"golang.org/x/time/rate"
)
func filterTextFiles(files []*storage.Object) []*storage.Object {
var res []*storage.Object
for _, file := range files {
if strings.HasSuffix(file.Key, ".txt") || strings.HasSuffix(file.Key, ".md") {
res = append(res, file)
}
}
return res
}
func getTextFiles(provider string, prefix string) ([]*storage.Object, error) {
files, err := storage.ListObjects(provider, prefix)
if err != nil {
return nil, err
}
return filterTextFiles(files), nil
}
func getObjectReadCloser(object *storage.Object) (io.ReadCloser, error) {
resp, err := http.Get(object.Url)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, fmt.Errorf("HTTP request failed with status code: %d", resp.StatusCode)
}
return resp.Body, nil
}
func addEmbeddedVector(authToken string, text string, storeName string, fileName string) (bool, error) {
embedding, err := ai.GetEmbeddingSafe(authToken, text)
if err != nil {
return false, err
}
displayName := text
if len(text) > 25 {
displayName = text[:25]
}
vector := &Vector{
Owner: "admin",
Name: fmt.Sprintf("vector_%s", util.GetRandomName()),
CreatedTime: util.GetCurrentTime(),
DisplayName: displayName,
Store: storeName,
File: fileName,
Text: text,
Data: embedding,
}
return AddVector(vector)
}
func setTxtObjectVector(authToken string, provider string, key string, storeName string) (bool, error) {
lb := rate.NewLimiter(rate.Every(time.Minute), 3)
txtObjects, err := getTextFiles(provider, key)
if err != nil {
return false, err
}
if len(txtObjects) == 0 {
return false, nil
}
for _, txtObject := range txtObjects {
readCloser, err := getObjectReadCloser(txtObject)
if err != nil {
return false, err
}
defer readCloser.Close()
splitTxts := ai.GetSplitTxt(readCloser)
for _, splitTxt := range splitTxts {
if lb.Allow() {
success, err := addEmbeddedVector(authToken, splitTxt, storeName, txtObject.Key)
if err != nil {
return false, err
}
if !success {
return false, nil
}
} else {
err := lb.Wait(context.Background())
if err != nil {
return false, err
}
success, err := addEmbeddedVector(authToken, splitTxt, storeName, txtObject.Key)
if err != nil {
return false, err
}
if !success {
return false, nil
}
}
}
}
return true, nil
}
func getRelatedVectors(owner string) ([]*Vector, error) {
vectors, err := GetVectors(owner)
if err != nil {
return nil, err
}
if len(vectors) == 0 {
return nil, fmt.Errorf("no knowledge vectors found")
}
return vectors, nil
}
func GetNearestVectorText(authToken string, owner string, question string) (string, error) {
qVector, err := ai.GetEmbeddingSafe(authToken, question)
if err != nil {
return "", err
}
if qVector == nil {
return "", fmt.Errorf("no qVector found")
}
vectors, err := getRelatedVectors(owner)
if err != nil {
return "", err
}
var nVectors [][]float32
for _, candidate := range vectors {
nVectors = append(nVectors, candidate.Data)
}
i := ai.GetNearestVectorIndex(qVector, nVectors)
return vectors[i].Text, nil
}

View File

@ -1,101 +0,0 @@
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"xorm.io/core"
)
type Vectorset struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(500)" json:"displayName"`
Url string `xorm:"varchar(100)" json:"url"`
FileName string `xorm:"varchar(100)" json:"fileName"`
FileSize string `xorm:"varchar(100)" json:"fileSize"`
Dimension int `json:"dimension"`
Count int `json:"count"`
Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
AllVectors []*Vector `xorm:"-" json:"allVectors"`
VectorMap map[string]*Vector `xorm:"-" json:"vectorMap"`
}
func GetGlobalVectorsets() []*Vectorset {
vectorsets := []*Vectorset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&vectorsets)
if err != nil {
panic(err)
}
return vectorsets
}
func GetVectorsets(owner string) []*Vectorset {
vectorsets := []*Vectorset{}
err := adapter.engine.Desc("created_time").Find(&vectorsets, &Vectorset{Owner: owner})
if err != nil {
panic(err)
}
return vectorsets
}
func getVectorset(owner string, name string) *Vectorset {
vectorset := Vectorset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&vectorset)
if err != nil {
panic(err)
}
if existed {
return &vectorset
} else {
return nil
}
}
func GetVectorset(id string) *Vectorset {
owner, name := util.GetOwnerAndNameFromId(id)
return getVectorset(owner, name)
}
func UpdateVectorset(id string, vectorset *Vectorset) bool {
owner, name := util.GetOwnerAndNameFromId(id)
if getVectorset(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(vectorset)
if err != nil {
panic(err)
}
//return affected != 0
return true
}
func AddVectorset(vectorset *Vectorset) bool {
affected, err := adapter.engine.Insert(vectorset)
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteVectorset(vectorset *Vectorset) bool {
affected, err := adapter.engine.ID(core.PK{vectorset.Owner, vectorset.Name}).Delete(&Vectorset{})
if err != nil {
panic(err)
}
return affected != 0
}
func (vectorset *Vectorset) GetId() string {
return fmt.Sprintf("%s/%s", vectorset.Owner, vectorset.Name)
}

View File

@ -1,59 +0,0 @@
package object
import (
"fmt"
"github.com/danaugrs/go-tsne/tsne"
"gonum.org/v1/gonum/mat"
)
func testTsne() {
b := mat.NewDense(5, 3, []float64{
0.1, 0.1, 0.1,
0.7, 0.7, 0.7,
0.1, 0.7, 0.5,
0.7, 0.1, 0.2,
0.1, 0.7, 0.5,
})
t := tsne.NewTSNE(2, 300, 100, 300, true)
Y := t.EmbedData(b, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
println(Y)
}
func (vectorset *Vectorset) DoTsne(dimension int) {
floatArray := []float64{}
for _, vector := range vectorset.AllVectors {
floatArray = append(floatArray, vector.Data...)
}
X := mat.NewDense(len(vectorset.AllVectors), vectorset.Dimension, floatArray)
t := tsne.NewTSNE(dimension, 300, 100, 300, true)
Y := t.EmbedData(X, func(iter int, divergence float64, embedding mat.Matrix) bool {
fmt.Printf("Iteration %d: divergence is %v\n", iter, divergence)
return false
})
rowCount, columnCount := Y.Dims()
if rowCount != len(vectorset.AllVectors) {
panic("rowCount != len(vectorset.AllVectors)")
}
if columnCount != dimension {
panic("columnCount != dimension")
}
for i, vector := range vectorset.AllVectors {
arr := []float64{}
for j := 0; j < dimension; j++ {
arr = append(arr, Y.At(i, j))
}
vector.Data = arr
}
}

View File

@ -1,24 +0,0 @@
package object
import (
"fmt"
"testing"
)
func TestDoVectorsetTsne(t *testing.T) {
InitConfig()
dimension := 50
//vectorset := getVectorset("admin", "wikipedia")
vectorset := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
vectorset.DoTsne(dimension)
vectorset.Name = fmt.Sprintf("%s_Dim_%d", vectorset.Name, dimension)
vectorset.FileName = fmt.Sprintf("%s_Dim_%d.csv", vectorset.FileName, dimension)
vectorset.FileSize = ""
vectorset.Dimension = dimension
vectorset.WriteVectors("../../tmpFiles/")
AddVectorset(vectorset)
}

View File

@ -1,57 +0,0 @@
package object
import (
"fmt"
"strings"
"github.com/casbin/casbase/util"
)
func (vectorset *Vectorset) LoadVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
var nameArray []string
var dataArray [][]float64
if strings.HasSuffix(vectorset.FileName, ".csv") {
if strings.Contains(vectorset.FileName, "_Dim_") {
nameArray, dataArray = util.LoadVectorFileByCsv2(path)
} else {
nameArray, dataArray = util.LoadVectorFileByCsv(path)
}
} else {
nameArray, dataArray = util.LoadVectorFileBySpace(path)
}
exampleVectors := []*Vector{}
vectors := []*Vector{}
vectorMap := map[string]*Vector{}
for i := 0; i < len(nameArray); i++ {
vector := &Vector{
Name: nameArray[i],
Data: dataArray[i],
}
if i < 100 {
exampleVectors = append(exampleVectors, vector)
}
vectors = append(vectors, vector)
vectorMap[vector.Name] = vector
}
vectorset.Vectors = exampleVectors
vectorset.AllVectors = vectors
vectorset.VectorMap = vectorMap
}
func (vectorset *Vectorset) WriteVectors(pathPrefix string) {
path := util.GetUploadFilePath(fmt.Sprintf("%s%s", pathPrefix, vectorset.FileName))
rows := [][]string{}
for _, vector := range vectorset.AllVectors {
row := util.FloatsToStrings(vector.Data)
row = append([]string{vector.Name}, row...)
rows = append(rows, row)
}
util.WriteCsvFile(path, &rows)
}

View File

@ -1,12 +0,0 @@
package object
import "testing"
func TestUpdateVectorsetVectors(t *testing.T) {
InitConfig()
//vectorset := getVectorset("admin", "wikipedia")
vectorset := getVectorset("admin", "wordVector_utf-8")
vectorset.LoadVectors("../../tmpFiles/")
UpdateVectorset(vectorset.GetId(), vectorset)
}

View File

@ -1,10 +1,24 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/video"
"github.com/casbin/casibase/util"
"github.com/casbin/casibase/video"
"xorm.io/core"
)
@ -31,86 +45,103 @@ type Video struct {
PlayAuth string `xorm:"-" json:"playAuth"`
}
func GetGlobalVideos() []*Video {
func GetGlobalVideos() ([]*Video, error) {
videos := []*Video{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&videos)
if err != nil {
panic(err)
return videos, err
}
return videos
return videos, nil
}
func GetVideos(owner string) []*Video {
func GetVideos(owner string) ([]*Video, error) {
videos := []*Video{}
err := adapter.engine.Desc("created_time").Find(&videos, &Video{Owner: owner})
if err != nil {
panic(err)
return videos, err
}
return videos
return videos, nil
}
func getVideo(owner string, name string) *Video {
func getVideo(owner string, name string) (*Video, error) {
v := Video{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&v)
if err != nil {
panic(err)
return &v, err
}
if existed {
if v.VideoId != "" {
v.PlayAuth = video.GetVideoPlayAuth(v.VideoId)
}
return &v
return &v, nil
} else {
return nil
return nil, nil
}
}
func GetVideo(id string) *Video {
func GetVideo(id string) (*Video, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getVideo(owner, name)
}
func UpdateVideo(id string, video *Video) bool {
func UpdateVideo(id string, video *Video) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if getVideo(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(video)
_, err := getVideo(owner, name)
if err != nil {
panic(err)
return false, err
}
if video == nil {
return false, nil
}
//return affected != 0
return true
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(video)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddVideo(video *Video) bool {
func AddVideo(video *Video) (bool, error) {
affected, err := adapter.engine.Insert(video)
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func DeleteVideo(video *Video) bool {
func DeleteVideo(video *Video) (bool, error) {
affected, err := adapter.engine.ID(core.PK{video.Owner, video.Name}).Delete(&Video{})
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func (video *Video) GetId() string {
return fmt.Sprintf("%s/%s", video.Owner, video.Name)
}
func (video *Video) Populate() {
store := getStore("admin", "default")
video.DataUrls = store.GetVideoData()
func (video *Video) Populate() error {
store, err := GetDefaultStore("admin")
if err != nil {
return err
}
if store == nil {
return nil
}
dataUrls, err := store.GetVideoData()
if err != nil {
return err
}
video.DataUrls = dataUrls
return nil
}

View File

@ -1,9 +1,23 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
"xorm.io/core"
)
@ -14,81 +28,85 @@ type Wordset struct {
DisplayName string `xorm:"varchar(100)" json:"displayName"`
DistanceLimit int `json:"distanceLimit"`
Vectorset string `xorm:"varchar(100)" json:"vectorset"`
Factorset string `xorm:"varchar(100)" json:"factorset"`
Vectors []*Vector `xorm:"mediumtext" json:"vectors"`
Factors []*Factor `xorm:"mediumtext" json:"factors"`
}
func GetGlobalWordsets() []*Wordset {
func GetGlobalWordsets() ([]*Wordset, error) {
wordsets := []*Wordset{}
err := adapter.engine.Asc("owner").Desc("created_time").Find(&wordsets)
if err != nil {
panic(err)
return wordsets, err
}
return wordsets
return wordsets, nil
}
func GetWordsets(owner string) []*Wordset {
func GetWordsets(owner string) ([]*Wordset, error) {
wordsets := []*Wordset{}
err := adapter.engine.Desc("created_time").Find(&wordsets, &Wordset{Owner: owner})
if err != nil {
panic(err)
return wordsets, err
}
return wordsets
return wordsets, nil
}
func getWordset(owner string, name string) *Wordset {
func getWordset(owner string, name string) (*Wordset, error) {
wordset := Wordset{Owner: owner, Name: name}
existed, err := adapter.engine.Get(&wordset)
if err != nil {
panic(err)
return &wordset, err
}
if existed {
return &wordset
return &wordset, nil
} else {
return nil
return nil, nil
}
}
func GetWordset(id string) *Wordset {
func GetWordset(id string) (*Wordset, error) {
owner, name := util.GetOwnerAndNameFromId(id)
return getWordset(owner, name)
}
func UpdateWordset(id string, wordset *Wordset) bool {
func UpdateWordset(id string, wordset *Wordset) (bool, error) {
owner, name := util.GetOwnerAndNameFromId(id)
if getWordset(owner, name) == nil {
return false
}
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(wordset)
_, err := getWordset(owner, name)
if err != nil {
panic(err)
return false, err
}
if wordset == nil {
return false, nil
}
//return affected != 0
return true
_, err = adapter.engine.ID(core.PK{owner, name}).AllCols().Update(wordset)
if err != nil {
return false, err
}
// return affected != 0
return true, nil
}
func AddWordset(wordset *Wordset) bool {
func AddWordset(wordset *Wordset) (bool, error) {
affected, err := adapter.engine.Insert(wordset)
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func DeleteWordset(wordset *Wordset) bool {
func DeleteWordset(wordset *Wordset) (bool, error) {
affected, err := adapter.engine.ID(core.PK{wordset.Owner, wordset.Name}).Delete(&Wordset{})
if err != nil {
panic(err)
return false, err
}
return affected != 0
return affected != 0, nil
}
func (wordset *Wordset) GetId() string {

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
@ -6,7 +20,7 @@ import (
"math"
"strconv"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
)
var graphCache map[string]*Graph
@ -15,42 +29,45 @@ func init() {
graphCache = map[string]*Graph{}
}
func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) *Graph {
func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) (*Graph, error) {
cacheId := fmt.Sprintf("%s|%d|%d", id, clusterNumber, distanceLimit)
g, ok := graphCache[cacheId]
if ok {
return g
return g, nil
}
wordset := GetWordset(id)
wordset, err := GetWordset(id)
if err != nil {
return nil, err
}
if wordset == nil {
return nil
return nil, nil
}
if len(wordset.Vectors) == 0 {
return nil
if len(wordset.Factors) == 0 {
return nil, nil
}
allZero := true
for _, vector := range wordset.Vectors {
if len(vector.Data) != 0 {
for _, factor := range wordset.Factors {
if len(factor.Data) != 0 {
allZero = false
break
}
}
if allZero {
return nil
return nil, nil
}
runKmeans(wordset.Vectors, clusterNumber)
runKmeans(wordset.Factors, clusterNumber)
g = generateGraph(wordset.Vectors, distanceLimit)
//graphCache[cacheId] = g
return g
g = generateGraph(wordset.Factors, distanceLimit)
// graphCache[cacheId] = g
return g, nil
}
func getDistance(v1 *Vector, v2 *Vector) float64 {
func getDistance(v1 *Factor, v2 *Factor) float64 {
res := 0.0
for i := range v1.Data {
res += (v1.Data[i] - v2.Data[i]) * (v1.Data[i] - v2.Data[i])
@ -58,11 +75,11 @@ func getDistance(v1 *Vector, v2 *Vector) float64 {
return math.Sqrt(res)
}
func refineVectors(vectors []*Vector) []*Vector {
res := []*Vector{}
for _, vector := range vectors {
if len(vector.Data) > 0 {
res = append(res, vector)
func refineFactors(factors []*Factor) []*Factor {
res := []*Factor{}
for _, factor := range factors {
if len(factor.Data) > 0 {
res = append(res, factor)
}
}
return res
@ -80,19 +97,19 @@ func getNodeColor(weight int) string {
return fmt.Sprintf("rgb(%d,%d,%d)", myColor.R, myColor.G, myColor.B)
}
func generateGraph(vectors []*Vector, distanceLimit int) *Graph {
vectors = refineVectors(vectors)
//vectors = vectors[:100]
func generateGraph(factors []*Factor, distanceLimit int) *Graph {
factors = refineFactors(factors)
// factors = factors[:100]
g := newGraph()
g.Nodes = []*Node{}
g.Links = []*Link{}
nodeWeightMap := map[string]int{}
for i := 0; i < len(vectors); i++ {
for j := i + 1; j < len(vectors); j++ {
v1 := vectors[i]
v2 := vectors[j]
for i := 0; i < len(factors); i++ {
for j := i + 1; j < len(factors); j++ {
v1 := factors[i]
v2 := factors[j]
distance := int(getDistance(v1, v2))
if distance >= distanceLimit {
continue
@ -117,17 +134,17 @@ func generateGraph(vectors []*Vector, distanceLimit int) *Graph {
}
}
for _, vector := range vectors {
//value := 5
value := int(math.Sqrt(float64(nodeWeightMap[vector.Name]))) + 3
weight := nodeWeightMap[vector.Name]
for _, factor := range factors {
// value := 5
value := int(math.Sqrt(float64(nodeWeightMap[factor.Name]))) + 3
weight := nodeWeightMap[factor.Name]
//nodeColor := "rgb(232,67,62)"
//nodeColor := getNodeColor(value)
nodeColor := vector.Color
// nodeColor := "rgb(232,67,62)"
// nodeColor := getNodeColor(value)
nodeColor := factor.Color
fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", vector.Name, nodeWeightMap[vector.Name], value)
g.addNode(vector.Name, vector.Name, value, nodeColor, vector.Category, weight)
fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", factor.Name, nodeWeightMap[factor.Name], value)
g.addNode(factor.Name, factor.Name, value, nodeColor, factor.Category, weight)
}
return g

View File

@ -1,26 +1,46 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
func GetWordsetMatch(id string) *Wordset {
wordset := GetWordset(id)
func GetWordsetMatch(id string) (*Wordset, error) {
wordset, err := GetWordset(id)
if err != nil {
return nil, err
}
if wordset == nil {
return nil
return nil, nil
}
vectorset := getVectorset(wordset.Owner, wordset.Vectorset)
if vectorset == nil {
return nil
factorset, err := getFactorset(wordset.Owner, wordset.Factorset)
if err != nil {
return nil, err
}
if factorset == nil {
return nil, nil
}
vectorset.LoadVectors("")
factorset.LoadFactors("")
for _, vector := range wordset.Vectors {
if trueVector, ok := vectorset.VectorMap[vector.Name]; ok {
vector.Data = trueVector.Data
for _, factor := range wordset.Factors {
if trueFactor, ok := factorset.FactorMap[factor.Name]; ok {
factor.Data = trueFactor.Data
} else {
vector.Data = []float64{}
factor.Data = []float64{}
}
}
UpdateWordset(wordset.GetId(), wordset)
return wordset
return wordset, nil
}

View File

@ -1,27 +1,41 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/xlsx"
"github.com/casbin/casibase/util"
"github.com/casbin/casibase/xlsx"
)
func uploadVectorNames(owner string, fileId string) bool {
func uploadFactorNames(owner string, fileId string) (bool, error) {
table := xlsx.ReadXlsxFile(fileId)
vectorMap := map[string]int{}
vectors := []*Vector{}
factorMap := map[string]int{}
factors := []*Factor{}
for _, line := range table {
if _, ok := vectorMap[line[0]]; ok {
if _, ok := factorMap[line[0]]; ok {
continue
} else {
vectorMap[line[0]] = 1
factorMap[line[0]] = 1
}
vector := &Vector{
factor := &Factor{
Name: line[0],
Data: []float64{},
}
vectors = append(vectors, vector)
factors = append(factors, factor)
}
wordset := &Wordset{
@ -30,7 +44,7 @@ func uploadVectorNames(owner string, fileId string) bool {
CreatedTime: util.GetCurrentTime(),
DisplayName: "word",
DistanceLimit: 14,
Vectors: vectors,
Factors: factors,
}
return AddWordset(wordset)
}

View File

@ -1,9 +1,23 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import "testing"
func TestUploadVectorNames(t *testing.T) {
func TestUploadFactorNames(t *testing.T) {
InitConfig()
uploadVectorNames("admin", "../../tmpFiles/filename")
uploadFactorNames("admin", "../../tmpFiles/filename")
}

87
proxy/proxy.go Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proxy
import (
"crypto/tls"
"fmt"
"net"
"net/http"
"strings"
"time"
"github.com/casbin/casibase/conf"
"golang.org/x/net/proxy"
)
var (
DefaultHttpClient *http.Client
ProxyHttpClient *http.Client
)
func InitHttpClient() {
// not use proxy
DefaultHttpClient = http.DefaultClient
// use proxy
ProxyHttpClient = getProxyHttpClient()
}
func isAddressOpen(address string) bool {
timeout := time.Millisecond * 100
conn, err := net.DialTimeout("tcp", address, timeout)
if err != nil {
// cannot connect to address, proxy is not active
return false
}
if conn != nil {
defer conn.Close()
fmt.Printf("Socks5 proxy enabled: %s\n", address)
return true
}
return false
}
func getProxyHttpClient() *http.Client {
socks5Proxy := conf.GetConfigString("socks5Proxy")
if socks5Proxy == "" {
return &http.Client{}
}
if !isAddressOpen(socks5Proxy) {
return &http.Client{}
}
// https://stackoverflow.com/questions/33585587/creating-a-go-socks5-client
dialer, err := proxy.SOCKS5("tcp", socks5Proxy, nil, proxy.Direct)
if err != nil {
panic(err)
}
tr := &http.Transport{Dial: dialer.Dial, TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
return &http.Client{
Transport: tr,
}
}
func GetHttpClient(url string) *http.Client {
if strings.Contains(url, "githubusercontent.com") || strings.Contains(url, "googleusercontent.com") {
return ProxyHttpClient
} else {
return DefaultHttpClient
}
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routers
import (
@ -7,7 +21,7 @@ import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/casbin/casbase/util"
"github.com/casbin/casibase/util"
)
func TransparentStatic(ctx *context.Context) {

View File

@ -1,8 +1,22 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package routers
import (
"github.com/astaxie/beego"
"github.com/casbin/casbase/controllers"
"github.com/casbin/casibase/controllers"
)
func init() {
@ -10,12 +24,11 @@ func init() {
}
func initAPI() {
ns :=
beego.NewNamespace("/api",
beego.NSInclude(
&controllers.ApiController{},
),
)
ns := beego.NewNamespace("/api",
beego.NSInclude(
&controllers.ApiController{},
),
)
beego.AddNamespace(ns)
beego.Router("/api/signin", &controllers.ApiController{}, "POST:Signin")
@ -31,12 +44,12 @@ func initAPI() {
beego.Router("/api/add-wordset", &controllers.ApiController{}, "POST:AddWordset")
beego.Router("/api/delete-wordset", &controllers.ApiController{}, "POST:DeleteWordset")
beego.Router("/api/get-global-vectorsets", &controllers.ApiController{}, "GET:GetGlobalVectorsets")
beego.Router("/api/get-vectorsets", &controllers.ApiController{}, "GET:GetVectorsets")
beego.Router("/api/get-vectorset", &controllers.ApiController{}, "GET:GetVectorset")
beego.Router("/api/update-vectorset", &controllers.ApiController{}, "POST:UpdateVectorset")
beego.Router("/api/add-vectorset", &controllers.ApiController{}, "POST:AddVectorset")
beego.Router("/api/delete-vectorset", &controllers.ApiController{}, "POST:DeleteVectorset")
beego.Router("/api/get-global-factorsets", &controllers.ApiController{}, "GET:GetGlobalFactorsets")
beego.Router("/api/get-factorsets", &controllers.ApiController{}, "GET:GetFactorsets")
beego.Router("/api/get-factorset", &controllers.ApiController{}, "GET:GetFactorset")
beego.Router("/api/update-factorset", &controllers.ApiController{}, "POST:UpdateFactorset")
beego.Router("/api/add-factorset", &controllers.ApiController{}, "POST:AddFactorset")
beego.Router("/api/delete-factorset", &controllers.ApiController{}, "POST:DeleteFactorset")
beego.Router("/api/get-global-videos", &controllers.ApiController{}, "GET:GetGlobalVideos")
beego.Router("/api/get-videos", &controllers.ApiController{}, "GET:GetVideos")
@ -52,6 +65,38 @@ func initAPI() {
beego.Router("/api/update-store", &controllers.ApiController{}, "POST:UpdateStore")
beego.Router("/api/add-store", &controllers.ApiController{}, "POST:AddStore")
beego.Router("/api/delete-store", &controllers.ApiController{}, "POST:DeleteStore")
beego.Router("/api/refresh-store-vectors", &controllers.ApiController{}, "POST:RefreshStoreVectors")
beego.Router("/api/get-storage-providers", &controllers.ApiController{}, "GET:GetStorageProviders")
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")
beego.Router("/api/get-global-vectors", &controllers.ApiController{}, "GET:GetGlobalVectors")
beego.Router("/api/get-vectors", &controllers.ApiController{}, "GET:GetVectors")
beego.Router("/api/get-vector", &controllers.ApiController{}, "GET:GetVector")
beego.Router("/api/update-vector", &controllers.ApiController{}, "POST:UpdateVector")
beego.Router("/api/add-vector", &controllers.ApiController{}, "POST:AddVector")
beego.Router("/api/delete-vector", &controllers.ApiController{}, "POST:DeleteVector")
beego.Router("/api/get-global-chats", &controllers.ApiController{}, "GET:GetGlobalChats")
beego.Router("/api/get-chats", &controllers.ApiController{}, "GET:GetChats")
beego.Router("/api/get-chat", &controllers.ApiController{}, "GET:GetChat")
beego.Router("/api/update-chat", &controllers.ApiController{}, "POST:UpdateChat")
beego.Router("/api/add-chat", &controllers.ApiController{}, "POST:AddChat")
beego.Router("/api/delete-chat", &controllers.ApiController{}, "POST:DeleteChat")
beego.Router("/api/get-global-messages", &controllers.ApiController{}, "GET:GetGlobalMessages")
beego.Router("/api/get-messages", &controllers.ApiController{}, "GET:GetMessages")
beego.Router("/api/get-message", &controllers.ApiController{}, "GET:GetMessage")
beego.Router("/api/get-message-answer", &controllers.ApiController{}, "GET:GetMessageAnswer")
beego.Router("/api/update-message", &controllers.ApiController{}, "POST:UpdateMessage")
beego.Router("/api/add-message", &controllers.ApiController{}, "POST:AddMessage")
beego.Router("/api/delete-message", &controllers.ApiController{}, "POST:DeleteMessage")
beego.Router("/api/update-file", &controllers.ApiController{}, "POST:UpdateFile")
beego.Router("/api/add-file", &controllers.ApiController{}, "POST:AddFile")

View File

@ -1,72 +0,0 @@
package storage
import (
"bytes"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func getBucket(bucketName string) *oss.Bucket {
client, err := oss.New(endpoint, clientId, clientSecret)
if err != nil {
panic(err)
}
bucket, err := client.Bucket(bucketName)
if err != nil {
panic(err)
}
return bucket
}
func ListObjects(bucketName string, prefix string) []oss.ObjectProperties {
res := []oss.ObjectProperties{}
if bucketName == "" {
return res
}
bucket := getBucket(bucketName)
marker := oss.Marker("")
i := 0
for {
resp, err := bucket.ListObjects(oss.Prefix(prefix), oss.MaxKeys(1000), marker)
if err != nil {
panic(err)
}
marker = oss.Marker(resp.NextMarker)
for _, object := range resp.Objects {
res = append(res, object)
//fmt.Printf("[%d] %s\n", i, object.Key)
i += 1
}
if !resp.IsTruncated {
break
}
}
return res
}
func PutObject(bucketName string, key string, fileBuffer *bytes.Buffer) {
bucket := getBucket(bucketName)
err := bucket.PutObject(key, fileBuffer)
if err != nil {
panic(err)
}
}
func DeleteObject(bucketName string, key string) {
bucket := getBucket(bucketName)
err := bucket.DeleteObject(key)
if err != nil {
panic(err)
}
}

View File

@ -1,5 +0,0 @@
package storage
var endpoint = ""
var clientId = ""
var clientSecret = ""

78
storage/storage.go Normal file
View File

@ -0,0 +1,78 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package storage
import (
"bytes"
"fmt"
"github.com/astaxie/beego"
"github.com/casdoor/casdoor-go-sdk/casdoorsdk"
)
type Object struct {
Key string
LastModified string
Size int64
Url string
}
func ListObjects(provider string, prefix string) ([]*Object, error) {
if provider == "" {
return nil, fmt.Errorf("storage provider is empty")
}
casdoorOrganization := beego.AppConfig.String("casdoorOrganization")
casdoorApplication := beego.AppConfig.String("casdoorApplication")
resources, err := casdoorsdk.GetResources(casdoorOrganization, casdoorApplication, "provider", provider, "Direct", prefix)
if err != nil {
return nil, err
}
res := []*Object{}
for _, resource := range resources {
res = append(res, &Object{
Key: resource.Name,
LastModified: resource.CreatedTime,
Size: int64(resource.FileSize),
Url: resource.Url,
})
}
return res, nil
}
func PutObject(provider string, user string, parent string, key string, fileBuffer *bytes.Buffer) error {
if provider == "" {
return fmt.Errorf("storage provider is empty")
}
_, _, err := casdoorsdk.UploadResource(user, "Casibase", parent, fmt.Sprintf("Direct/%s/%s", provider, key), fileBuffer.Bytes())
if err != nil {
return err
}
return nil
}
func DeleteObject(provider string, key string) error {
if provider == "" {
return fmt.Errorf("storage provider is empty")
}
_, err := casdoorsdk.DeleteResource(fmt.Sprintf("Direct/%s/%s", provider, key))
if err != nil {
return err
}
return nil
}

View File

@ -1,7 +1,42 @@
package storage
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import "testing"
//go:build !skipCi
// +build !skipCi
package storage_test
import (
"fmt"
"testing"
"github.com/casbin/casibase/controllers"
"github.com/casbin/casibase/object"
"github.com/casbin/casibase/storage"
)
func TestStorage(t *testing.T) {
ListObjects("casbase", "")
object.InitConfig()
controllers.InitAuthConfig()
provider := "provider_storage_casibase"
objects, err := storage.ListObjects(provider, "")
if err != nil {
panic(err)
}
for i, obj := range objects {
fmt.Printf("[%d] %v\n", i, obj)
}
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "fmt"

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
@ -24,7 +38,7 @@ func parseJsonToFloats(s string) []float64 {
return res
}
func LoadVectorFileByCsv(path string) ([]string, [][]float64) {
func LoadFactorFileByCsv(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}
@ -49,7 +63,7 @@ func LoadVectorFileByCsv(path string) ([]string, [][]float64) {
return nameArray, dataArray
}
func LoadVectorFileByCsv2(path string) ([]string, [][]float64) {
func LoadFactorFileByCsv2(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}
@ -70,7 +84,7 @@ func LoadVectorFileByCsv2(path string) ([]string, [][]float64) {
return nameArray, dataArray
}
func LoadVectorFileBySpace(path string) ([]string, [][]float64) {
func LoadFactorFileBySpace(path string) ([]string, [][]float64) {
nameArray := []string{}
dataArray := [][]float64{}

67
util/header.go Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"fmt"
"os"
"path/filepath"
"strings"
)
var licenseText = `// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`
func updateAllHeaders() {
err := filepath.Walk("../", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && (strings.HasSuffix(path, ".go") || strings.HasSuffix(path, ".js") && !strings.Contains(path, "node_modules")) {
data, err := os.ReadFile(path)
if err != nil {
return err
}
if !strings.Contains(string(data), "Licensed under the Apache License") {
newData := licenseText + string(data)
err = os.WriteFile(path, []byte(newData), info.Mode())
if err != nil {
return err
}
fmt.Printf("Handled path: [%s]\n", path)
}
}
return nil
})
if err != nil {
panic(err)
}
}

21
util/header_test.go Normal file
View File

@ -0,0 +1,21 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "testing"
func TestUpdateAllHeaders(t *testing.T) {
updateAllHeaders()
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (

View File

@ -1,10 +1,24 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "encoding/json"
func StructToJson(v interface{}) string {
data, err := json.MarshalIndent(v, "", " ")
//data, err := json.Marshal(v)
// data, err := json.Marshal(v)
if err != nil {
panic(err)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
@ -84,7 +98,7 @@ func CopyFile(dest string, src string) {
panic(err)
}
err = os.WriteFile(dest, bs, 0644)
err = os.WriteFile(dest, bs, 0o644)
if err != nil {
panic(err)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "fmt"

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
@ -5,8 +19,10 @@ import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"strconv"
"strings"
"time"
"github.com/google/uuid"
)
@ -56,7 +72,7 @@ func GetOwnerAndNameFromId(id string) (string, string) {
panic(errors.New("GetOwnerAndNameFromId() error, wrong token count for ID: " + id))
}
return tokens[0], tokens[1]
return "admin", tokens[1]
}
func GetOwnerAndNameFromId3(id string) (string, string, string) {
@ -95,7 +111,7 @@ func ReadStringFromPath(path string) string {
}
func WriteStringToPath(s string, path string) {
err := ioutil.WriteFile(path, []byte(s), 0644)
err := ioutil.WriteFile(path, []byte(s), 0o644)
if err != nil {
panic(err)
}
@ -111,7 +127,7 @@ func ReadBytesFromPath(path string) []byte {
}
func WriteBytesToPath(b []byte, path string) {
err := ioutil.WriteFile(path, b, 0644)
err := ioutil.WriteFile(path, b, 0o644)
if err != nil {
panic(err)
}
@ -125,3 +141,17 @@ func DecodeBase64(s string) string {
return string(res)
}
func GetRandomName() string {
rand.Seed(time.Now().UnixNano())
const charset = "0123456789abcdefghijklmnopqrstuvwxyz"
result := make([]byte, 6)
for i := range result {
result[i] = charset[rand.Intn(len(charset))]
}
return string(result)
}
func GetId(owner, name string) string {
return fmt.Sprintf("%s/%s", owner, name)
}

View File

@ -1,3 +1,17 @@
// Copyright 2023 The casbin Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import "time"
@ -7,3 +21,17 @@ func GetCurrentTime() string {
tm := time.Unix(timestamp, 0)
return tm.Format(time.RFC3339)
}
func GetCurrentTimeEx(timestamp string) string {
tm := time.Now()
inputTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
panic(err)
}
if !tm.After(inputTime) {
tm = inputTime.Add(1 * time.Millisecond)
}
return tm.Format("2006-01-02T15:04:05.999Z07:00")
}

Some files were not shown because too many files have changed in this diff Show More