mirror of
https://github.com/Li4n0/revsuit.git
synced 2026-09-26 08:31:52 +08:00
feat(rmi): support receive rmi connection (#5)
This commit is contained in:
@@ -8,6 +8,9 @@ http:
|
|||||||
ip_header:
|
ip_header:
|
||||||
dns:
|
dns:
|
||||||
enable: true
|
enable: true
|
||||||
|
rmi:
|
||||||
|
enable: true
|
||||||
|
addr: :1099
|
||||||
mysql:
|
mysql:
|
||||||
enable: true
|
enable: true
|
||||||
addr: :3306
|
addr: :3306
|
||||||
|
|||||||
@@ -17,6 +17,9 @@
|
|||||||
<a-menu-item key="/logs/dns">
|
<a-menu-item key="/logs/dns">
|
||||||
<router-link to="/logs/dns">DNS Logs</router-link>
|
<router-link to="/logs/dns">DNS Logs</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="/logs/rmi">
|
||||||
|
<router-link to="/logs/rmi">RMI Logs</router-link>
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="/logs/mysql">
|
<a-menu-item key="/logs/mysql">
|
||||||
<router-link to="/logs/mysql">MySQL Logs</router-link>
|
<router-link to="/logs/mysql">MySQL Logs</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -29,6 +32,9 @@
|
|||||||
<a-menu-item key="/rules/dns">
|
<a-menu-item key="/rules/dns">
|
||||||
<router-link to="/rules/dns">DNS Rules</router-link>
|
<router-link to="/rules/dns">DNS Rules</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
<a-menu-item key="/rules/rmi">
|
||||||
|
<router-link to="/rules/rmi">RMI Rules</router-link>
|
||||||
|
</a-menu-item>
|
||||||
<a-menu-item key="/rules/mysql">
|
<a-menu-item key="/rules/mysql">
|
||||||
<router-link to="/rules/mysql">MySQL Rules</router-link>
|
<router-link to="/rules/mysql">MySQL Rules</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
|||||||
@@ -31,4 +31,15 @@ export function getMysqlRecord(params) {
|
|||||||
return status >= 200 && status < 300 // 默认的
|
return status >= 200 && status < 300 // 默认的
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRmiRecord(params) {
|
||||||
|
return request({
|
||||||
|
url: '/record/rmi',
|
||||||
|
params: params,
|
||||||
|
method: 'get',
|
||||||
|
validateStatus: function (status) {
|
||||||
|
return status >= 200 && status < 300 // 默认的
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -98,4 +98,37 @@ export function deleteMysqlRule(data) {
|
|||||||
return status >= 200 && status < 300 // 默认的
|
return status >= 200 && status < 300 // 默认的
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRmiRule(params) {
|
||||||
|
return request({
|
||||||
|
url: '/rule/rmi',
|
||||||
|
params: params,
|
||||||
|
method: 'get',
|
||||||
|
validateStatus: function (status) {
|
||||||
|
return status >= 200 && status < 300 // 默认的
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function upsertRmiRule(data) {
|
||||||
|
return request({
|
||||||
|
url: '/rule/rmi',
|
||||||
|
data: data,
|
||||||
|
method: 'post',
|
||||||
|
validateStatus: function (status) {
|
||||||
|
return status >= 200 && status < 300 // 默认的
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteRmiRule(data) {
|
||||||
|
return request({
|
||||||
|
url: '/rule/rmi',
|
||||||
|
data: data,
|
||||||
|
method: 'delete',
|
||||||
|
validateStatus: function (status) {
|
||||||
|
return status >= 200 && status < 300 // 默认的
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,11 @@ const routes = [
|
|||||||
name: 'MysqlLogs',
|
name: 'MysqlLogs',
|
||||||
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Mysql')
|
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Mysql')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/logs/rmi',
|
||||||
|
name: 'RmiLogs',
|
||||||
|
component: () => import(/* webpackChunkName: "about" */ '../views/logs/Rmi')
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/rules/http',
|
path: '/rules/http',
|
||||||
name: 'HttpRules',
|
name: 'HttpRules',
|
||||||
@@ -39,6 +44,11 @@ const routes = [
|
|||||||
path: '/rules/mysql',
|
path: '/rules/mysql',
|
||||||
name: 'MysqlRules',
|
name: 'MysqlRules',
|
||||||
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Mysql')
|
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Mysql')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/rules/rmi',
|
||||||
|
name: 'RmiRules',
|
||||||
|
component: () => import(/* webpackChunkName: "about" */ '../views/rules/Rmi')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ const columns = [
|
|||||||
title: 'PATH',
|
title: 'PATH',
|
||||||
dataIndex: 'path',
|
dataIndex: 'path',
|
||||||
key: 'path',
|
key: 'path',
|
||||||
|
ellipsis: true,
|
||||||
scopedSlots: {
|
scopedSlots: {
|
||||||
filterDropdown: 'filterDropdown',
|
filterDropdown: 'filterDropdown',
|
||||||
filterIcon: 'filterIcon',
|
filterIcon: 'filterIcon',
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
<template>
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="data"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
@change="handleTableChange"
|
||||||
|
:rowClassName="(record, index) => index % 2 === 0 ? '' : 'gray-table-row'"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
slot="filterDropdown"
|
||||||
|
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
|
||||||
|
style="padding: 8px"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
:placeholder="`Search ${column.dataIndex}`"
|
||||||
|
:value="selectedKeys[0]"
|
||||||
|
style="width: 188px; margin-bottom: 8px; display: block;"
|
||||||
|
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||||
|
@pressEnter="() => {
|
||||||
|
filters[column.dataIndex] = selectedKeys[0];
|
||||||
|
fetch()
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
icon="search"
|
||||||
|
size="small"
|
||||||
|
style="width: 90px; margin-right: 8px"
|
||||||
|
@click="() => {
|
||||||
|
filters[column.dataIndex] = selectedKeys[0];
|
||||||
|
fetch()
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</a-button>
|
||||||
|
<a-button size="small" style="width: 90px" @click="() =>{
|
||||||
|
clearFilters();
|
||||||
|
delete filters[column.dataIndex];
|
||||||
|
fetch()
|
||||||
|
}">
|
||||||
|
Reset
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<a-icon
|
||||||
|
slot="filterIcon"
|
||||||
|
slot-scope="filtered"
|
||||||
|
type="search"
|
||||||
|
:style="{ color: filtered ? '#108ee9' : undefined }"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span slot="time" slot-scope="time">
|
||||||
|
{{ new Date(time).format("yyyy-MM-dd hh:mm:ss") }}
|
||||||
|
</span>
|
||||||
|
</a-table>
|
||||||
|
</template>
|
||||||
|
<style>
|
||||||
|
.gray-table-row {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import {getRmiRecord} from '@/api/record'
|
||||||
|
import {store} from '@/main'
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
sorter: true,
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'REQUEST TIME',
|
||||||
|
dataIndex: 'request_time',
|
||||||
|
key: 'request_time',
|
||||||
|
scopedSlots: {customRender: 'time'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'RULE',
|
||||||
|
dataIndex: 'rule_name',
|
||||||
|
key: 'rule_name',
|
||||||
|
scopedSlots: {
|
||||||
|
filterDropdown: 'filterDropdown',
|
||||||
|
filterIcon: 'filterIcon',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'FLAG',
|
||||||
|
dataIndex: 'flag',
|
||||||
|
key: 'flag',
|
||||||
|
scopedSlots: {
|
||||||
|
filterDropdown: 'filterDropdown',
|
||||||
|
filterIcon: 'filterIcon',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'PATH',
|
||||||
|
dataIndex: 'path',
|
||||||
|
key: 'path',
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'REMOTE IP',
|
||||||
|
key: 'remote_ip',
|
||||||
|
dataIndex: 'remote_ip',
|
||||||
|
scopedSlots: {
|
||||||
|
filterDropdown: 'filterDropdown',
|
||||||
|
filterIcon: 'filterIcon',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'IP AREA',
|
||||||
|
key: 'ip_area',
|
||||||
|
dataIndex: 'ip_area'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DnsLogs',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
pagination: {current: 1},
|
||||||
|
filters: {},
|
||||||
|
order: "desc",
|
||||||
|
loading: false,
|
||||||
|
columns,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTableChange(pagination, filters, sorter) {
|
||||||
|
const pager = {...this.pagination};
|
||||||
|
pager.current = pagination.current;
|
||||||
|
this.pagination = pager;
|
||||||
|
this.order = sorter.order === "ascend" ? "asc" : "desc"
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
fetch: function () {
|
||||||
|
this.loading = true;
|
||||||
|
let params = {
|
||||||
|
...this.filters,
|
||||||
|
page: this.pagination.current,
|
||||||
|
order: this.order
|
||||||
|
}
|
||||||
|
getRmiRecord(params).then(res => {
|
||||||
|
let result = res.data.result
|
||||||
|
this.data = result.data
|
||||||
|
const pagination = {...this.pagination};
|
||||||
|
// Read total count from server
|
||||||
|
// pagination.total = data.totalCount;
|
||||||
|
pagination.total = result.count;
|
||||||
|
this.pagination = pagination;
|
||||||
|
this.loading = false
|
||||||
|
}).catch(e => {
|
||||||
|
if (e.response.status === 403) {
|
||||||
|
store.authed = false
|
||||||
|
return []
|
||||||
|
} else {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetch({page: "1"});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -137,11 +137,6 @@
|
|||||||
</a-tag>
|
</a-tag>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span slot="files" slot-scope="files">
|
|
||||||
<!-- eslint-disable-next-line-->
|
|
||||||
{{ files.length > 30 ? files.substr(0, 30) + "..." : files }}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
|
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
|
||||||
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
|
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
|
||||||
</span>
|
</span>
|
||||||
@@ -221,9 +216,7 @@ const columns = [
|
|||||||
title: 'FILES',
|
title: 'FILES',
|
||||||
dataIndex: 'files',
|
dataIndex: 'files',
|
||||||
key: 'files',
|
key: 'files',
|
||||||
scopedSlots: {
|
ellipsis: true
|
||||||
customRender: "files"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'PUSH TO CLIENT',
|
title: 'PUSH TO CLIENT',
|
||||||
|
|||||||
@@ -0,0 +1,337 @@
|
|||||||
|
<template xmlns:a-col="http://www.w3.org/1999/html">
|
||||||
|
<div>
|
||||||
|
<a-button id="add-rule" type="primary" @click="addRule">
|
||||||
|
<a-icon type="plus"/>
|
||||||
|
New Rule
|
||||||
|
</a-button>
|
||||||
|
<!-- rule form-->
|
||||||
|
<a-drawer
|
||||||
|
:title="formAction+ ' Dns rule'"
|
||||||
|
:width="460"
|
||||||
|
:visible="formVisible"
|
||||||
|
:body-style="{ paddingBottom: '80px' }"
|
||||||
|
@close="closeDrawer"
|
||||||
|
>
|
||||||
|
<a-form-model :model="form" ref="form" layout="vertical" @submit="handleSubmit">
|
||||||
|
<BasicRule :form="form" :readOnly="formReadOnly"/>
|
||||||
|
</a-form-model>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
position: 'absolute',
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
width: '100%',
|
||||||
|
borderTop: '1px solid #e9e9e9',
|
||||||
|
padding: '10px 16px',
|
||||||
|
background: '#fff',
|
||||||
|
textAlign: 'right',
|
||||||
|
zIndex: 1,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<a-button :style="{ marginRight: '8px' }" @click="handleCancel">
|
||||||
|
Cancel
|
||||||
|
</a-button>
|
||||||
|
<a-button type="primary" :disabled="formReadOnly" @click="handleSubmit">
|
||||||
|
Submit
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</a-drawer>
|
||||||
|
<!-- rule table -->
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="data"
|
||||||
|
:loading="loading"
|
||||||
|
:pagination="pagination"
|
||||||
|
@change="handleTableChange"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
slot="filterDropdown"
|
||||||
|
slot-scope="{ setSelectedKeys, selectedKeys, clearFilters, column }"
|
||||||
|
style="padding: 8px"
|
||||||
|
>
|
||||||
|
<a-input
|
||||||
|
:placeholder="`Search ${column.dataIndex}`"
|
||||||
|
:value="selectedKeys[0]"
|
||||||
|
style="width: 188px; margin-bottom: 8px; display: block;"
|
||||||
|
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||||
|
@pressEnter="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
|
||||||
|
/>
|
||||||
|
<a-button
|
||||||
|
type="primary"
|
||||||
|
icon="search"
|
||||||
|
size="small"
|
||||||
|
style="width: 90px; margin-right: 8px"
|
||||||
|
@click="() => {filters[column.dataIndex] = selectedKeys[0];fetch()}"
|
||||||
|
>
|
||||||
|
Search
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<a-icon
|
||||||
|
slot="filterIcon"
|
||||||
|
slot-scope="filtered"
|
||||||
|
type="search"
|
||||||
|
:style="{ color: filtered ? '#108ee9' : undefined }"
|
||||||
|
/>
|
||||||
|
<span slot="rank" slot-scope="rank">
|
||||||
|
<a-tag
|
||||||
|
:color="'#'+(0x2db7f5+rank*80).toString(16)"
|
||||||
|
>
|
||||||
|
{{ rank }}
|
||||||
|
</a-tag>
|
||||||
|
</span>
|
||||||
|
<span slot="type" slot-scope="type">
|
||||||
|
<a-tag
|
||||||
|
:color="colors[type]"
|
||||||
|
>
|
||||||
|
{{ resolveTypes[type] }}
|
||||||
|
</a-tag>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span slot="switchRender" slot-scope="checked,record,index,dataIndex">
|
||||||
|
<a-switch :checked="checked" @click="clickSwitch(record,dataIndex.dataIndex)"></a-switch>
|
||||||
|
</span>
|
||||||
|
<span slot="valueRender" slot-scope="values">
|
||||||
|
<span v-for="value in values.split(',')" :key="value">{{ value }}<br/></span>
|
||||||
|
</span>
|
||||||
|
<span slot="action" slot-scope="text,record,index">
|
||||||
|
<!-- <a-button @click="viewRule(record)" style="-->
|
||||||
|
<!-- color: #67C23A;-->
|
||||||
|
<!-- background-color: transparent;-->
|
||||||
|
<!-- border-color: #67C23A;-->
|
||||||
|
<!-- text-shadow: none;-->
|
||||||
|
<!-- margin-right: 10px;-->
|
||||||
|
<!--" size="small" ghost>View</a-button>-->
|
||||||
|
<a-button @click="editRule(record,index)" style="
|
||||||
|
color: #909399;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: #909399;
|
||||||
|
text-shadow: none;
|
||||||
|
margin-right: 10px;
|
||||||
|
" size="small" ghost>Edit</a-button>
|
||||||
|
<a-popconfirm
|
||||||
|
title="Are you sure delete this task?"
|
||||||
|
ok-text="Yes"
|
||||||
|
cancel-text="No"
|
||||||
|
@confirm="deleteRule(record,index)"
|
||||||
|
>
|
||||||
|
<a-button type="danger" size="small" ghost>Delete</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
</span>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
#add-rule {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import {getRmiRule, upsertRmiRule, deleteRmiRule} from '@/api/rule'
|
||||||
|
import {store} from '@/main'
|
||||||
|
import BasicRule from "@/components/BasicRule";
|
||||||
|
|
||||||
|
const VIEW = "View"
|
||||||
|
const EDIT = "Edit"
|
||||||
|
const CREATE = "Create"
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
sorter: true,
|
||||||
|
sortDirections: ['descend', 'ascend'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'NAME',
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
scopedSlots: {
|
||||||
|
filterDropdown: 'filterDropdown',
|
||||||
|
filterIcon: 'filterIcon',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'FLAG FORMAT',
|
||||||
|
dataIndex: 'flag_format',
|
||||||
|
key: 'flag_format',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'RANK',
|
||||||
|
dataIndex: 'rank',
|
||||||
|
key: 'rank',
|
||||||
|
scopedSlots: {
|
||||||
|
customRender: 'rank',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'PUSH TO CLIENT',
|
||||||
|
dataIndex: 'push_to_client',
|
||||||
|
key: 'push_to_client',
|
||||||
|
scopedSlots: {
|
||||||
|
customRender: 'switchRender',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'NOTICE',
|
||||||
|
dataIndex: 'notice',
|
||||||
|
key: 'notice',
|
||||||
|
scopedSlots: {
|
||||||
|
customRender: 'switchRender',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'action',
|
||||||
|
scopedSlots: {customRender: 'action'},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
export default {
|
||||||
|
name: 'RmiRules',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
formVisible: false,
|
||||||
|
pagination: {current: 1},
|
||||||
|
filters: {},
|
||||||
|
loading: false,
|
||||||
|
columns,
|
||||||
|
form: {},
|
||||||
|
formReadOnly: false,
|
||||||
|
formAction: "", // View ,Create or Edit
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTableChange(pagination, filters, sorter) {
|
||||||
|
const pager = {...this.pagination};
|
||||||
|
pager.current = pagination.current;
|
||||||
|
this.pagination = pager;
|
||||||
|
this.order = sorter.order === "ascend" ? "asc" : "desc"
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
fetch: function () {
|
||||||
|
this.loading = true;
|
||||||
|
let params = {
|
||||||
|
...this.filters,
|
||||||
|
page: this.pagination.current,
|
||||||
|
order: this.order
|
||||||
|
}
|
||||||
|
getRmiRule(params).then(res => {
|
||||||
|
let result = res.data.result
|
||||||
|
this.data = result.data
|
||||||
|
const pagination = {...this.pagination};
|
||||||
|
// Read total count from server
|
||||||
|
// pagination.total = data.totalCount;
|
||||||
|
pagination.total = result.count;
|
||||||
|
this.pagination = pagination;
|
||||||
|
this.loading = false
|
||||||
|
}).catch(e => {
|
||||||
|
if (e.response.status === 403) {
|
||||||
|
store.authed = false
|
||||||
|
return []
|
||||||
|
} else {
|
||||||
|
this.$notification.error({
|
||||||
|
message: 'Unknown error: ' + e.response.status,
|
||||||
|
style: {
|
||||||
|
width: '100px',
|
||||||
|
marginLeft: `${335 - 600}px`,
|
||||||
|
},
|
||||||
|
duration: 4
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
clickSwitch(record, prop) {
|
||||||
|
record[prop] = !record[prop]
|
||||||
|
upsertRmiRule(record).then().catch(e => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: 'Edit failed',
|
||||||
|
description:
|
||||||
|
e.response.data.error,
|
||||||
|
style: {
|
||||||
|
width: '600px',
|
||||||
|
marginLeft: `${335 - 600}px`,
|
||||||
|
},
|
||||||
|
duration: 4
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
addRule() {
|
||||||
|
this.form = {}
|
||||||
|
this.showForm(CREATE)
|
||||||
|
},
|
||||||
|
viewRule(record) {
|
||||||
|
this.form = record
|
||||||
|
this.showForm(VIEW)
|
||||||
|
},
|
||||||
|
editRule(record) {
|
||||||
|
this.form = JSON.parse(JSON.stringify(record))
|
||||||
|
this.showForm(EDIT)
|
||||||
|
},
|
||||||
|
deleteRule(record, index) {
|
||||||
|
deleteRmiRule(record).then(() => {
|
||||||
|
this.data.splice(index, 1)
|
||||||
|
}).catch(e => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: 'Error',
|
||||||
|
description:
|
||||||
|
e.response.data.error,
|
||||||
|
style: {
|
||||||
|
width: '600px',
|
||||||
|
marginLeft: `${335 - 600}px`,
|
||||||
|
},
|
||||||
|
duration: 4
|
||||||
|
});
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showForm(action) {
|
||||||
|
this.formAction = action
|
||||||
|
this.formReadOnly = action === VIEW;
|
||||||
|
this.formVisible = true;
|
||||||
|
},
|
||||||
|
closeDrawer() {
|
||||||
|
this.formVisible = false;
|
||||||
|
},
|
||||||
|
handleSubmit() {
|
||||||
|
this.$refs.form.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
upsertRmiRule(this.form).then(() => {
|
||||||
|
this.closeDrawer()
|
||||||
|
this.fetch({page: this.pagination.current});
|
||||||
|
this.$notification.info({
|
||||||
|
message: 'Success',
|
||||||
|
style: {
|
||||||
|
width: '600px',
|
||||||
|
marginLeft: `${335 - 600}px`,
|
||||||
|
},
|
||||||
|
duration: 2.5
|
||||||
|
});
|
||||||
|
}).catch(e => {
|
||||||
|
this.$notification.error({
|
||||||
|
message: this.formAction + ' failed',
|
||||||
|
description:
|
||||||
|
e.response.data.error,
|
||||||
|
style: {
|
||||||
|
width: '600px',
|
||||||
|
marginLeft: `${335 - 600}px`,
|
||||||
|
},
|
||||||
|
duration: 4
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleCancel() {
|
||||||
|
this.form = {}
|
||||||
|
this.closeDrawer()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetch({page: "1"});
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
BasicRule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+1
-1
@@ -82,7 +82,7 @@ func (s *Server) Run() {
|
|||||||
log.Error("DNS record(rule_id:%s) created failed :%s", _rule.Name, err.Error())
|
log.Error("DNS record(rule_id:%s) created failed :%s", _rule.Name, err.Error())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
log.Trace("DNS record(id:%d) has been created", r.ID)
|
log.Info("DNS record(id:%d,rule:%s,remote_ip:%s) has been created", r.ID, _rule.Name, ip)
|
||||||
|
|
||||||
//only send to client when this connection recorded first time.
|
//only send to client when this connection recorded first time.
|
||||||
if _rule.PushToClient {
|
if _rule.PushToClient {
|
||||||
|
|||||||
+6
-1
@@ -42,7 +42,7 @@ func newRecord(rule *Rule, flag, domain, remoteIp, ipArea string) (r *Record, er
|
|||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(c *gin.Context) {
|
func ListRecords(c *gin.Context) {
|
||||||
var (
|
var (
|
||||||
dnsRecord Record
|
dnsRecord Record
|
||||||
res []Record
|
res []Record
|
||||||
@@ -80,6 +80,11 @@ func List(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ func ListRules(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
+3
-3
@@ -125,7 +125,7 @@ func (s *Server) ConnectionClosed(c *vmysql.Conn) {
|
|||||||
log.Error("MySQL record(rule_id:%s) created failed :%s", _rule.Name, err.Error())
|
log.Error("MySQL record(rule_id:%s) created failed :%s", _rule.Name, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("MySQL record(id:%d) has been created", r.ID)
|
log.Info("MySQL record(id:%d,rule:%s,remote_ip:%s) has been created", r.ID, _rule.Name, ip)
|
||||||
|
|
||||||
//only send to client when this connection recorded first time.
|
//only send to client when this connection recorded first time.
|
||||||
if _rule.PushToClient {
|
if _rule.PushToClient {
|
||||||
@@ -267,10 +267,10 @@ func (s *Server) Run() {
|
|||||||
var authServer = &vmysql.AuthServerNone{}
|
var authServer = &vmysql.AuthServerNone{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
log.Info("Starting Mysql Server at %s", s.Addr)
|
log.Info("Starting MySQL Server at %s", s.Addr)
|
||||||
s.listener, err = vmysql.NewListener("tcp", s.Addr, authServer, s, s.VersionString, 0, 0)
|
s.listener, err = vmysql.NewListener("tcp", s.Addr, authServer, s, s.VersionString, 0, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("New Mysql Server failed: %s", err)
|
log.Error("New MySQL Server failed: %s", err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -49,13 +49,14 @@ func newRecord(rule *Rule, flag, username, clientName, clientOS, remoteIp, ipAre
|
|||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func List(c *gin.Context) {
|
func ListRecords(c *gin.Context) {
|
||||||
var (
|
var (
|
||||||
mysqlRecord Record
|
mysqlRecord Record
|
||||||
res []Record
|
res []Record
|
||||||
count int64
|
count int64
|
||||||
order = c.Query("order")
|
order = c.Query("order")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := c.ShouldBind(&mysqlRecord); err != nil {
|
if err := c.ShouldBind(&mysqlRecord); err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
@@ -90,6 +91,11 @@ func List(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Preload("Files").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Preload("Files").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ func ListRules(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
+1
-1
@@ -157,7 +157,7 @@ func (s *Server) Receive(c *gin.Context) {
|
|||||||
c.String(code, compileTpl(c, _rule.ResponseBody))
|
c.String(code, compileTpl(c, _rule.ResponseBody))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("HTTP record(id:%d) has been created", r.ID)
|
log.Info("HTTP record(id:%d,rule:%s,remote_ip:%s) has been created", r.ID, _rule.Name, ip)
|
||||||
|
|
||||||
//only send to client when this connection recorded first time.
|
//only send to client when this connection recorded first time.
|
||||||
if _rule.PushToClient {
|
if _rule.PushToClient {
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ func ListRecords(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
@@ -108,6 +108,10 @@ func ListRules(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
c.JSON(400, gin.H{
|
c.JSON(400, gin.H{
|
||||||
"status": "failed",
|
"status": "failed",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package rmi
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Enable bool
|
||||||
|
Addr string
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package rmi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/li4n0/revsuit/internal/database"
|
||||||
|
"github.com/li4n0/revsuit/internal/notice"
|
||||||
|
"github.com/li4n0/revsuit/internal/record"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ record.Record = (*Record)(nil)
|
||||||
|
|
||||||
|
type Record struct {
|
||||||
|
Path string `form:"path" json:"path"`
|
||||||
|
record.BaseRecord
|
||||||
|
Rule Rule `gorm:"foreignKey:RuleName;references:Name;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;" form:"-" json:"-" notice:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Record) TableName() string {
|
||||||
|
return "rmi_records"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r Record) Notice() {
|
||||||
|
notice.Notice(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRecord(rule *Rule, flag, path, ip, area string) (r *Record, err error) {
|
||||||
|
r = &Record{
|
||||||
|
BaseRecord: record.BaseRecord{
|
||||||
|
Flag: flag,
|
||||||
|
RemoteIP: ip,
|
||||||
|
IpArea: area,
|
||||||
|
RequestTime: time.Now(),
|
||||||
|
},
|
||||||
|
Path: path,
|
||||||
|
Rule: *rule,
|
||||||
|
}
|
||||||
|
err = database.DB.Create(r).Error
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListRecords(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
rmiRecord Record
|
||||||
|
res []Record
|
||||||
|
count int64
|
||||||
|
order = c.Query("order")
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.ShouldBind(&rmiRecord); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err,
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db := database.DB.Model(&rmiRecord)
|
||||||
|
if rmiRecord.Flag != "" {
|
||||||
|
db.Where("flag = ?", rmiRecord.Flag)
|
||||||
|
}
|
||||||
|
if rmiRecord.Path != "" {
|
||||||
|
db.Where("path like ?", "%"+rmiRecord.Path+"%")
|
||||||
|
}
|
||||||
|
if rmiRecord.RemoteIP != "" {
|
||||||
|
db.Where("remote_ip = ?", rmiRecord.RemoteIP)
|
||||||
|
}
|
||||||
|
if rmiRecord.RuleName != "" {
|
||||||
|
db.Where("rule_name = ?", rmiRecord.RuleName)
|
||||||
|
}
|
||||||
|
|
||||||
|
page, err := strconv.Atoi(c.Query("page"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": "succeed",
|
||||||
|
"error": nil,
|
||||||
|
"result": gin.H{"count": count, "data": res},
|
||||||
|
})
|
||||||
|
}
|
||||||
+158
@@ -0,0 +1,158 @@
|
|||||||
|
package rmi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/li4n0/revsuit/internal/database"
|
||||||
|
"github.com/li4n0/revsuit/internal/qqwry"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Config
|
||||||
|
rules []*Rule
|
||||||
|
rulesLock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
server *Server
|
||||||
|
once sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetServer() *Server {
|
||||||
|
once.Do(func() {
|
||||||
|
server = &Server{rulesLock: sync.RWMutex{}}
|
||||||
|
})
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) getRules() []*Rule {
|
||||||
|
defer s.rulesLock.RUnlock()
|
||||||
|
s.rulesLock.RLock()
|
||||||
|
return s.rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) updateRules() error {
|
||||||
|
db := database.DB.Model(new(Rule))
|
||||||
|
s.rulesLock.Lock()
|
||||||
|
db.Order("rank desc").Find(&s.rules)
|
||||||
|
s.rulesLock.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleConnection(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
ip, port, _ := net.SplitHostPort(conn.RemoteAddr().String())
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(time.Second * 30)); err != nil {
|
||||||
|
log.Error("RMI set connection deadline error:%v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, 1024)
|
||||||
|
_, err := conn.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RMI read connection error:%v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Contains(buf, []byte{0x4a, 0x52, 0x4d, 0x49}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
send := []byte{0x4e}
|
||||||
|
bs := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint16(bs, uint16(len(ip)))
|
||||||
|
send = append(send, bs...)
|
||||||
|
send = append(send, []byte(ip)...)
|
||||||
|
send = append(send, []byte{0x00, 0x00}...)
|
||||||
|
uintPort, _ := strconv.Atoi(port)
|
||||||
|
bs = make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint16(bs, uint16(uintPort))
|
||||||
|
send = append(send, bs...)
|
||||||
|
|
||||||
|
_, err = conn.Write(send)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RMI write connection error: %v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]byte, 512)
|
||||||
|
|
||||||
|
for length := 0; length < 50; {
|
||||||
|
n, err := conn.Read(data)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RMI read connection error: %v", err.Error())
|
||||||
|
}
|
||||||
|
length += n
|
||||||
|
}
|
||||||
|
|
||||||
|
frags := bytes.Split(data, []byte{0xdf, 0x74})
|
||||||
|
path := strings.TrimRight(string(frags[len(frags)-1][2:]), "\x00")
|
||||||
|
|
||||||
|
for _, _rule := range s.getRules() {
|
||||||
|
flag, flagGroup := _rule.Match(path)
|
||||||
|
if flag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
area := qqwry.Area(ip)
|
||||||
|
|
||||||
|
// create new record
|
||||||
|
r, err := NewRecord(_rule, flag, path, ip, area)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RMI record(rule_id:%d) created failed :%s", _rule.ID, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Info("RMI record(id:%d,rule:%s,remote_ip:%s) has been created", r.ID, _rule.Name, ip)
|
||||||
|
|
||||||
|
//only send to client when this connection recorded first time.
|
||||||
|
if _rule.PushToClient {
|
||||||
|
if flagGroup != "" {
|
||||||
|
var count int64
|
||||||
|
database.DB.Where("rule_name=? and raw like ?", _rule.Name, "%"+flagGroup+"%").Model(&Record{}).Count(&count)
|
||||||
|
if count <= 1 {
|
||||||
|
r.PushToClient()
|
||||||
|
log.Trace("RMI record(id:%d) has been put to client message queue", r.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r.PushToClient()
|
||||||
|
log.Trace("RMI record(id:%d) has been put to client message queue", r.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
//send notice
|
||||||
|
if _rule.Notice {
|
||||||
|
go func() {
|
||||||
|
r.Notice()
|
||||||
|
log.Trace("RMI record(id:%d) notice has been sent", r.ID)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Run() {
|
||||||
|
if err := s.updateRules(); err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// run server
|
||||||
|
log.Info("Starting RMI Server at %v", s.Addr)
|
||||||
|
|
||||||
|
listener, err := net.Listen("tcp", s.Addr)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
tcpConn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Error("RMI accept connection error: %v", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go s.handleConnection(tcpConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+193
@@ -0,0 +1,193 @@
|
|||||||
|
package rmi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/li4n0/revsuit/internal/database"
|
||||||
|
"github.com/li4n0/revsuit/internal/rule"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
|
log "unknwon.dev/clog/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Http rule struct
|
||||||
|
type Rule struct {
|
||||||
|
rule.BaseRule
|
||||||
|
}
|
||||||
|
|
||||||
|
func (Rule) TableName() string {
|
||||||
|
return "rmi_rules"
|
||||||
|
}
|
||||||
|
|
||||||
|
// New rmi rule struct
|
||||||
|
func NewRule(name, flagFormat string, pushToClient, notice bool) *Rule {
|
||||||
|
return &Rule{
|
||||||
|
BaseRule: rule.BaseRule{
|
||||||
|
Name: name,
|
||||||
|
FlagFormat: flagFormat,
|
||||||
|
PushToClient: pushToClient,
|
||||||
|
Notice: notice,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or update the rmi rule in database and ruleSet
|
||||||
|
func (r *Rule) CreateOrUpdate() (err error) {
|
||||||
|
db := database.DB.Model(r)
|
||||||
|
err = db.Clauses(clause.OnConflict{
|
||||||
|
Columns: []clause.Column{{Name: "id"}},
|
||||||
|
DoUpdates: clause.AssignmentColumns(
|
||||||
|
[]string{
|
||||||
|
"name",
|
||||||
|
"flag_format",
|
||||||
|
"rank",
|
||||||
|
"push_to_client",
|
||||||
|
"notice",
|
||||||
|
}),
|
||||||
|
}).Create(r).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = GetServer().updateRules()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the rmi rule in database and ruleSet
|
||||||
|
func (r *Rule) Delete() (err error) {
|
||||||
|
db := database.DB.Model(r)
|
||||||
|
err = db.Delete(r).Error
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = GetServer().updateRules()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all rmi rules those satisfy the filter
|
||||||
|
func ListRules(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
rmiRule Rule
|
||||||
|
res []Rule
|
||||||
|
count int64
|
||||||
|
order = c.Query("order")
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.ShouldBind(&rmiRule); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err,
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db := database.DB.Model(&rmiRule)
|
||||||
|
if rmiRule.Name != "" {
|
||||||
|
db.Where("name = ?", rmiRule.Name)
|
||||||
|
}
|
||||||
|
db.Count(&count)
|
||||||
|
|
||||||
|
page, err := strconv.Atoi(c.Query("page"))
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if order != "desc" && order != "asc" {
|
||||||
|
order = "desc"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Order("rank desc").Order("id" + " " + order).Count(&count).Offset((page - 1) * 10).Limit(10).Find(&res).Error; err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": "succeed",
|
||||||
|
"error": nil,
|
||||||
|
"result": gin.H{"count": count, "data": res},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or update rmi rule from user submit
|
||||||
|
func UpsertRules(c *gin.Context) {
|
||||||
|
var (
|
||||||
|
rmiRule Rule
|
||||||
|
update bool
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := c.ShouldBind(&rmiRule); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if rmiRule.ID != 0 {
|
||||||
|
update = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rmiRule.CreateOrUpdate(); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if update {
|
||||||
|
log.Trace("RMI rule(id:%d) has been updated", rmiRule.ID)
|
||||||
|
} else {
|
||||||
|
log.Trace("RMI rule(id:%d) has been created", rmiRule.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": "succeed",
|
||||||
|
"error": nil,
|
||||||
|
"result": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete rmi rule from user submit
|
||||||
|
func DeleteRules(c *gin.Context) {
|
||||||
|
var rmiRule Rule
|
||||||
|
|
||||||
|
if err := c.ShouldBind(&rmiRule); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rmiRule.Delete(); err != nil {
|
||||||
|
c.JSON(400, gin.H{
|
||||||
|
"status": "failed",
|
||||||
|
"error": err.Error(),
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Trace("RMI rule(id:%d) has been deleted", rmiRule.ID)
|
||||||
|
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": "succeed",
|
||||||
|
"error": nil,
|
||||||
|
"data": nil,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"github.com/li4n0/revsuit/pkg/dns"
|
"github.com/li4n0/revsuit/pkg/dns"
|
||||||
"github.com/li4n0/revsuit/pkg/mysql"
|
"github.com/li4n0/revsuit/pkg/mysql"
|
||||||
"github.com/li4n0/revsuit/pkg/rhttp"
|
"github.com/li4n0/revsuit/pkg/rhttp"
|
||||||
|
"github.com/li4n0/revsuit/pkg/rmi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type noticeConfig struct {
|
type noticeConfig struct {
|
||||||
@@ -21,5 +22,6 @@ type Config struct {
|
|||||||
Notice noticeConfig
|
Notice noticeConfig
|
||||||
rhttp.Config
|
rhttp.Config
|
||||||
DNS dns.Config
|
DNS dns.Config
|
||||||
Mysql mysql.Config
|
MySQL mysql.Config
|
||||||
|
RMI rmi.Config
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/li4n0/revsuit/pkg/dns"
|
"github.com/li4n0/revsuit/pkg/dns"
|
||||||
"github.com/li4n0/revsuit/pkg/mysql"
|
"github.com/li4n0/revsuit/pkg/mysql"
|
||||||
"github.com/li4n0/revsuit/pkg/rhttp"
|
"github.com/li4n0/revsuit/pkg/rhttp"
|
||||||
|
"github.com/li4n0/revsuit/pkg/rmi"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,10 +53,13 @@ func (revsuit *Revsuit) registerHttpRouter() {
|
|||||||
httpGroup.GET("", rhttp.ListRecords)
|
httpGroup.GET("", rhttp.ListRecords)
|
||||||
|
|
||||||
dnsGroup := recordGroup.Group("/dns")
|
dnsGroup := recordGroup.Group("/dns")
|
||||||
dnsGroup.GET("", dns.List)
|
dnsGroup.GET("", dns.ListRecords)
|
||||||
|
|
||||||
mysqlGroup := recordGroup.Group("/mysql")
|
mysqlGroup := recordGroup.Group("/mysql")
|
||||||
mysqlGroup.GET("", mysql.List)
|
mysqlGroup.GET("", mysql.ListRecords)
|
||||||
|
|
||||||
|
rmiGroup := recordGroup.Group("/rmi")
|
||||||
|
rmiGroup.GET("", rmi.ListRecords)
|
||||||
|
|
||||||
// init rule router group
|
// init rule router group
|
||||||
ruleGroup := revsuit.http.ApiGroup.Group("/rule")
|
ruleGroup := revsuit.http.ApiGroup.Group("/rule")
|
||||||
@@ -75,6 +79,11 @@ func (revsuit *Revsuit) registerHttpRouter() {
|
|||||||
mysqlGroup.POST("", mysql.UpsertRules)
|
mysqlGroup.POST("", mysql.UpsertRules)
|
||||||
mysqlGroup.DELETE("", mysql.DeleteRules)
|
mysqlGroup.DELETE("", mysql.DeleteRules)
|
||||||
|
|
||||||
|
rmiGroup = ruleGroup.Group("/rmi")
|
||||||
|
rmiGroup.GET("", rmi.ListRules)
|
||||||
|
rmiGroup.POST("", rmi.UpsertRules)
|
||||||
|
rmiGroup.DELETE("", rmi.DeleteRules)
|
||||||
|
|
||||||
// init file router group
|
// init file router group
|
||||||
fileGroup := revsuit.http.ApiGroup.Group("/file")
|
fileGroup := revsuit.http.ApiGroup.Group("/file")
|
||||||
fileGroup.GET("/mysql/:id", mysql.GetFile)
|
fileGroup.GET("/mysql/:id", mysql.GetFile)
|
||||||
|
|||||||
+19
-2
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/li4n0/revsuit/pkg/dns"
|
"github.com/li4n0/revsuit/pkg/dns"
|
||||||
"github.com/li4n0/revsuit/pkg/mysql"
|
"github.com/li4n0/revsuit/pkg/mysql"
|
||||||
http "github.com/li4n0/revsuit/pkg/rhttp"
|
http "github.com/li4n0/revsuit/pkg/rhttp"
|
||||||
|
"github.com/li4n0/revsuit/pkg/rmi"
|
||||||
"gorm.io/gorm/logger"
|
"gorm.io/gorm/logger"
|
||||||
log "unknwon.dev/clog/v2"
|
log "unknwon.dev/clog/v2"
|
||||||
)
|
)
|
||||||
@@ -15,6 +16,7 @@ type Revsuit struct {
|
|||||||
http *http.Server
|
http *http.Server
|
||||||
dns *dns.Server
|
dns *dns.Server
|
||||||
mysql *mysql.Server
|
mysql *mysql.Server
|
||||||
|
rmi *rmi.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDatabase(dsn string) {
|
func initDatabase(dsn string) {
|
||||||
@@ -51,6 +53,14 @@ func initDatabase(dsn string) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
err = database.DB.AutoMigrate(&rmi.Record{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
err = database.DB.AutoMigrate(&rmi.Rule{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,9 +132,13 @@ func New(c *Config) *Revsuit {
|
|||||||
if c.DNS.Enable {
|
if c.DNS.Enable {
|
||||||
s.dns = dns.GetServer()
|
s.dns = dns.GetServer()
|
||||||
}
|
}
|
||||||
if c.Mysql.Enable {
|
if c.MySQL.Enable {
|
||||||
s.mysql = mysql.GetServer()
|
s.mysql = mysql.GetServer()
|
||||||
s.mysql.Config = c.Mysql
|
s.mysql.Config = c.MySQL
|
||||||
|
}
|
||||||
|
if c.RMI.Enable {
|
||||||
|
s.rmi = rmi.GetServer()
|
||||||
|
s.rmi.Config = c.RMI
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Addr != "" {
|
if c.Addr != "" {
|
||||||
@@ -149,6 +163,9 @@ func (revsuit *Revsuit) Run() {
|
|||||||
if revsuit.mysql != nil {
|
if revsuit.mysql != nil {
|
||||||
go revsuit.mysql.Run()
|
go revsuit.mysql.Run()
|
||||||
}
|
}
|
||||||
|
if revsuit.rmi != nil {
|
||||||
|
go revsuit.rmi.Run()
|
||||||
|
}
|
||||||
|
|
||||||
revsuit.http.Run()
|
revsuit.http.Run()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user