使用Rust+Rocket建立一個CRUD的RESTful歌曲請求API

banq發表於2022-10-28

如果您在 YouTube 和 Twitch 等平臺上觀看流媒體,您可能遇到過歌曲請求系統。歌曲請求系統允許觀眾將歌曲新增到 歌曲佇列中。當歌曲到達佇列的最前面時,歌曲會在直播流中播放。
在 Rocket crate 的幫助下,Rust 為這個系統建立一個 API 非常容易。
使用Rocket箱建立一個 RESTful API。

初始化:

cargo init <YOUR_PROJECT_NAME>


加入依賴:

[dependencies]

# NOTE: This is a pre-release version.
# Thus, It is suggested NOT to use this in production.
rocket = "0.5.0-rc.2"


在我們的Cargo專案準備就緒後,我們可以完全刪除預設的主函式。這將為我們的新rocket方法騰出空間,該方法歸屬於Rocket的發射程式宏。

這個函式實質上將取代我們的主函式,並在啟動時被呼叫。

//main.rs

#[macro_use]
extern crate rocket;

use rocket::{Build, Rocket};

#[launch]
fn rocket() -> Rocket<Build> {
    Rocket::build()
        // 設定`/`路由路徑作為我們路由的基礎。
        // 當我們建立我們的路由時,我們將把它們包括在`routes!`宏的引數中。
        .mount("/", routes![])
}


執行後輸出:

Configured for debug.
   >> address: 127.0.0.1
   >> port: 8000
   >> workers: 6
   >> ident: Rocket
   >> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
   >> temp dir: C:\Users\dev\AppData\Local\Temp\
   >> http/2: true
   >> keep-alive: 5s
   >> tls: disabled
   >> shutdown: ctrlc = true, force = true, grace = 2s, mercy = 3s
   >> log level: normal
   >> cli colors: true
Fairings:
   >> Shield (liftoff, response, singleton)
Shield:
   >> X-Content-Type-Options: nosniff
   >> Permissions-Policy: interest-cohort=()
   >> X-Frame-Options: SAMEORIGIN
Rocket has launched from http://127.0.0.1:8000



現在我們有了我們的rocket函式,我們可以開始為我們的API開發功能。

儲存歌曲佇列
為了儲存歌曲佇列,我們將使用一個靜態的LinkedList。
我們使用LinkedList是因為它包含在標準庫中,並且基本上是作為一個具有額外功能的佇列。

不過,為了允許靜態地修改列表,我們必須用Mutex來包裝這個列表。

use std::collections::LinkedList;
use std::sync::Mutex;

static SONG_QUEUE: Mutex<LinkedList<String>> = Mutex::new(LinkedList::new());


更多Mutex, click here.(中文:https://github.com/kumakichi/easy_rust_chs)

我們將多次重複以下程式碼:

let lock = SONG_QUEUE
    .lock()
    .expect("Unable to acquire lock on song queue because the Mutex was poisoned");


如果我們建立一個為我們執行此操作的函式會更好。

use std::sync::{Mutex, MutexGuard};

fn acquire_queue<'a>() -> MutexGuard<'a, LinkedList<String>> {
    SONG_QUEUE
        .lock()
        .expect("Unable to acquire lock on song queue because the Mutex was poisoned")
}


建立add路由
SONG_QUEUE定義好變數後,我們就可以開始建立路由了。
該add路由將收到一個包含歌曲名稱的POST請求,然後將其新增到歌曲佇列中。
或者,我們可以返回歌曲所在的位置。

#[post("/add/<song_name>")]
fn add_song(song_name: String) -> String {
    let mut lock = acquire_queue();

    lock.push_back(song_name);

    format!("Song added. This song is in position {}.", lock.len())
}


不要忘記在routes!宏中註冊這個新路由。
  1. - .mount("/", routes![])
  2. + .mount("/", routes![add_song])


測試:

C:\Users\dev>curl -X POST http://localhost:8000/add/Hello
Song added. This song is in position 1.
C:\Users\dev>curl -X POST http://localhost:8000/add/Hello%20number%202
Song added. This song is in position 2.


建立view路由
使用者現在可以新增歌曲,但無法檢視當前在佇列中的歌曲。
別擔心,我們將建立一個新的GET路由。

只有一行程式碼!

#[get("/view")]
fn view() -> String {
    format!("{:?}", acquire_queue())
}


不要忘記在routes!宏中註冊這個新路由。
  1. - .mount("/", routes![add_song])
  2. + .mount("/", routes![add_song, view])


執行:

C:\Users\dev>curl -X POST http://localhost:8000/add/Hello%20World
Song added. This song is in position 1.

C:\Users\dev>curl http://localhost:8000/view
<p class="indent">["Hello World"]



刪除歌曲
為了文章的簡單起見,一旦歌曲到達佇列的最前面,我們將不會真正播放它們。相反,我們只會在經過一定時間後刪除歌曲。
在這種情況下,我們會在歌曲排到佇列前 60 秒後移除歌曲

use std::thread;
use std::time::Duration;

fn remove_song_timer() {
    while !acquire_queue().is_empty() {
        thread::sleep(Duration::from_secs(60));
        acquire_queue().pop_front();
    }
}


我們需要修改我們的add_song路由以確保在remove_song_timer將歌曲新增到空佇列時生成執行緒。

#[post("/add/<song_name>")]
fn add_song(song_name: String) -> String {
    let mut lock = acquire_queue();

    if lock.is_empty() {
        thread::spawn(remove_song_timer);
    }
    lock.push_back(song_name);

    format!("Song added. This song is in position {}.", lock.len())
}


結果:

C:\Users\dev>curl -X POST http://localhost:8000/add/Hello%20World
Song added. This song is in position 1.
C:\Users\dev>curl http://localhost:8000/view
<p class="indent">["Hello World"]


60秒後……

C:\Users\dev>curl http://localhost:8000/view
<p class="indent">[]



 

相關文章