Skip to content

Commit

Permalink
feat: 优化代码,编写 README
Browse files Browse the repository at this point in the history
  • Loading branch information
nashaofu committed Jun 16, 2023
1 parent 2f152cf commit b5d8e40
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 67 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ WORKDIR /opt/wol
COPY --from=builder /build/wol .

EXPOSE 3000
VOLUME ["/opt/wol/data"]
VOLUME ["/opt/wol"]

ENV RUST_LOG=info \
RUST_BACKTRACE=1 \
Expand Down
115 changes: 114 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,114 @@
# wol
# wol

Wol 是 wake on lan 的简写,是一个轻量、简介的 Wol 管理服务,支持检测设备是否开机成功。

## 功能特性

- 部署简单,且可私有部署。
- 默认使用 yaml 作为配置文件,易于编辑与迁移。
- 主题切换:支持浅色主题与暗黑主题。
- 占用资源少,运行速度快。
- 跨平台:可以在 Linux、macOS 和 Windows 操作系统上运行。

## 安装和使用

### Docker 中使用(推荐)

推荐使用 Docker 安装方式,使用简单方便,只需运行如下命令:

```sh
docker pull ghcr.io/nashaofu/wol:latest
docker run -d \
--name wol \
-p 3000:3000 \
-v /path/to:/opt/wol \
ghcr.io/nashaofu/wol:latest
```

然后在浏览器中访问 `http://127.0.0.1:3000` 即可使用。

如果需要自定义配置,可将项目根目录下的 `wol.example.yaml` 文件拷贝到 `/opt/wol` 目录下并重命名为 `wol.yaml`,具体配置参考配置章节。

### 系统中使用

1. 前往[release](https://github.com/nashaofu/wol/releases)页面下载`wol-client.zip``wol-xxxx.zip``xxxx`表示系统架构,请根据自己的情况选择
2. 新建一个目录`wol`,解压`wol-client.zip``wol/www`,解压`wol-xxxx.zip``wol`目录下,最终目录结构如下

```bash
.
├── wol # wol-xxxx.zip
└── www # wol-client.zip
├── ... # other files
└── index.html
```

3. 在终端中运行`./wol`即可启动服务。同时也支持在启动时指定服务的端口号与配置文件。

```bash
Usage: wol [OPTIONS]

Options:
-p, --port <PORT> App listen port [default: 3000]
-c, --config <CONFIG> Config file path [default: ./wol.yaml]
-h, --help Print help
-V, --version Print version
```

## 配置

项目配置文件为`wol.yaml`,配置内容如下:

```yaml
# 账号密码
user: null
# 设备列表
devices:
- name: Windows # 设备名称
mac: 00:00:00:00:00:00 # 设备 mac 地址
ip: 192.168.1.1 # 设备 ipv4 地址
port: 9 # wake on lan 唤醒端口号,一般为9、7 或者 0
```
## 贡献指南
如果您想为 Wol 做出贡献,可以按照以下步骤进行:
1. 克隆项目到本地:
```sh
git clone https://github.com/nashaofu/wol.git
```

2. 创建新分支:

```sh
git checkout -b my-feature-branch
```

3. 启动项目:你需要安装 rust、nodejs 与 yarn

```sh
# 启动服务端项目
cargo run
# 启动前端项目
cd client && yarn && yarn dev
```

4. 修改并提交代码:

```sh
git add .
git commit -m "Add new feature"
```

5. 推送代码到远程仓库:

```sh
git push origin my-feature-branch
```

6. 创建 Pull Request:在 GitHub 上创建一个新的 Pull Request 并等待审核。

## 许可证

Wol 使用 MIT 许可证,详情请参阅 [LICENSE](LICENSE) 文件。
7 changes: 7 additions & 0 deletions src/api/device.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
errors::Result,
settings::{Device, SETTINGS},
wol,
};

use actix_web::{get, post, web, HttpResponse, Responder};
Expand All @@ -21,6 +22,12 @@ async fn save(data: web::Json<Vec<Device>>) -> Result<impl Responder> {
Ok(HttpResponse::Ok().json(&settings.devices))
}

#[post("/wake")]
async fn wake(data: web::Json<wol::WakeData>) -> Result<impl Responder> {
wol::wake(&data)?;
Ok(HttpResponse::Ok().json(&data))
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PingData {
ip: String,
Expand Down
16 changes: 7 additions & 9 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
mod device;
mod wol;

use actix_web::web;

pub fn init(cfg: &mut web::ServiceConfig) {
cfg
.service(
web::scope("/device")
.service(device::all)
.service(device::save)
.service(device::status)
)
.service(web::scope("/wol").service(wol::wake));
cfg.service(
web::scope("/device")
.service(device::all)
.service(device::save)
.service(device::wake)
.service(device::status),
);
}
9 changes: 0 additions & 9 deletions src/api/wol.rs

This file was deleted.

45 changes: 19 additions & 26 deletions web/src/components/Device/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ import {
PoweroffOutlined,
} from '@ant-design/icons';
import useSWR from 'swr';
import useSWRMutation from 'swr/mutation';
import { get } from 'lodash-es';
import { IDevice, IDeviceStatus } from '@/types/device';
import fetcher from '@/utils/fetcher';
import useMessage from '@/hooks/useMessage';
import useModal from '@/hooks/useModal';
import DeviceEdit from '../DeviceEdit';
import useBoolean from '@/hooks/useBoolean';
import { useDeleteDevice } from '@/hooks/useDevices';
import { useDeleteDevice, useWakeDevice } from '@/hooks/useDevices';
import styles from './index.module.less';
import fetcher from '@/utils/fetcher';

export interface IDeviceProps {
device: IDevice;
Expand All @@ -28,14 +27,6 @@ export default function Device({ device }: IDeviceProps) {
const message = useMessage();
const modal = useModal();
const [open, actions] = useBoolean(false);
const { trigger: deleteDevice } = useDeleteDevice({
onSuccess: () => {
message.success('删除成功');
},
onError: (err) => {
message.error(get(err, 'response.data.message', '删除失败'));
},
});

const {
data: status,
Expand All @@ -45,32 +36,34 @@ export default function Device({ device }: IDeviceProps) {
`/device/status/${device.ip}`,
(url) => fetcher.get<unknown, IDeviceStatus>(url),
{
refreshInterval: 5000,
refreshInterval: 7000,
},
);

const { isMutating: isWaking, trigger: wakeDevice } = useSWRMutation(
'/wol/wake',
async (url) => {
await fetcher.post(url, device);
await new Promise<void>((resolve) => {
setTimeout(() => resolve(), 10000);
});
const { isMutating: isWaking, trigger: wakeDevice } = useWakeDevice({
onSuccess: () => {
fetchDeviceStatus();
},
{
onError: (err) => {
message.error(get(err, 'response.data.message', '开机失败'));
},
onError: (err) => {
message.error(get(err, 'response.data.message', '开机失败'));
},
);
});

const { trigger: deleteDevice } = useDeleteDevice({
onSuccess: () => {
message.success('删除成功');
},
onError: (err) => {
message.error(get(err, 'response.data.message', '删除失败'));
},
});

const onWake = useCallback(() => {
if (isWaking) {
return;
}
wakeDevice();
}, [isWaking, wakeDevice]);
wakeDevice(device);
}, [isWaking, device, wakeDevice]);

const items: MenuProps['items'] = [
{
Expand Down
10 changes: 5 additions & 5 deletions web/src/components/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ export default function Header() {
[setThemeValue],
);

const onCreateOk = useCallback(() => {
actions.setFalse();
}, [actions]);

return (
<>
<Layout.Header>
Expand All @@ -56,7 +52,11 @@ export default function Header() {
</div>
</div>
</Layout.Header>
<DeviceEdit open={open} onOk={onCreateOk} onCancel={actions.setFalse} />
<DeviceEdit
open={open}
onOk={actions.setFalse}
onCancel={actions.setFalse}
/>
</>
);
}
49 changes: 34 additions & 15 deletions web/src/components/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
import { Col, Row, Spin } from 'antd';
import {
Button, Col, Empty, Row, Spin,
} from 'antd';
import { useDevices } from '@/hooks/useDevices';
import Device from '@/components/Device';
import DeviceEdit from '../DeviceEdit';
import useBoolean from '@/hooks/useBoolean';
import styles from './index.module.less';

export default function Home() {
const { data: devices = [], isLoading } = useDevices();
const [open, actions] = useBoolean(false);

return (
<Spin spinning={isLoading} size="large">
<div className={styles.home}>
<Row gutter={[24, 24]}>
{devices.map((item) => (
<Col key={item.uid} span={8} xs={24} sm={24} md={12} lg={8}>
<div className={styles.item}>
<Device device={item} />
</div>
</Col>
))}
</Row>
<div className={styles.container} />
</div>
</Spin>
<>
<Spin spinning={isLoading} size="large">
<div className={styles.home}>
{!devices.length && (
<Empty>
<Button type="primary" onClick={actions.setTrue}>
添加设备
</Button>
</Empty>
)}
<Row gutter={[24, 24]}>
{devices.map((item) => (
<Col key={item.uid} span={8} xs={24} sm={24} md={12} lg={8}>
<div className={styles.item}>
<Device device={item} />
</div>
</Col>
))}
</Row>
<div className={styles.container} />
</div>
</Spin>
<DeviceEdit
open={open}
onOk={actions.setFalse}
onCancel={actions.setFalse}
/>
</>
);
}
18 changes: 17 additions & 1 deletion web/src/hooks/useDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ IDevice[],
'/device/save'
>;

export function useDevices(config?: SWRConfiguration) {
export function useDevices(config?: SWRConfiguration<IDevice[]>) {
return useSWR<IDevice[]>(
'/device/all',
async (url) => {
Expand Down Expand Up @@ -99,3 +99,19 @@ export function useDeleteDevice(config?: UseSaveDevicesConfig) {
trigger: (device: IDevice) => saveDevices.trigger(devices.filter((item) => item.uid !== device.uid)),
};
}

export function useWakeDevice(
config?: SWRMutationConfiguration<void, Error, IDevice, '/device/wake'>,
) {
return useSWRMutation(
'/device/wake',
async (url, { arg }: { arg: IDevice }) => {
await fetcher.post(url, arg);
// 延迟 10s, 等待机器开机
await new Promise<void>((resolve) => {
setTimeout(() => resolve(), 10000);
});
},
config,
);
}

0 comments on commit b5d8e40

Please sign in to comment.