สร้าง App Chat แบบ Decentralize โดยใช้ Calimero and BOS : แบบจับมือทำ !
Guide นี้ จะพาสร้าง App Chat บน Blockchain แต่ก่อนที่จะเข้าเรื่อง เรามาทำความรู้จักกับ BOS กันก่อนดีกว่า
BOS นั้นคือ…?
ชื่อเต็มคือ Blockchain Operating System ระบบที่จะมาทำให้การเขียน/พัฒนา/deployโค้ด และการเข้าถึง Frontend กลายเป็นเรื่องง่าย โดย BOS เปรียบเสมือนประตูสู่โลก Web 3.0 ที่เน้นพัฒนาขับเคลื่อนด้วย Community
ทำไมถึง BOS …?
BOS เป็นทั้ง social network และมีพื้นที่และ tools ให้เลือกใช้ ซึ่งนอกจากที่จะเราสามารถหยิบใช้ได้แล้ว ยังมีอัพเดท App ใหม่ๆ ขึ้นมาด้วย นี่คือความพิเศษของ BOS ล่ะ
- การเข้าถึง : BOS ช่วยให้ User เรียกใช้ App บน blockchain จากที่ไหนก็ได้ รวมถึงระบบปลอดภัยรัดกุม และสะดวกรวดเร็ว
- ความปลอดภัย : components’ code ทั้งหมดอยู่บน Blockchain ซึ่งมั่นใจได้ว่าโปร่งใส ตรวจสอบได้ สามารถ run code ได้อย่างวางใจ
- การรวมพลัง : BOS ให้ Dev สามารถใช้ component ผสมผสาน และใช้ได้เรื่อยๆ ช่วยให้ทำงานได้ง่ายมากๆ Dev สามารถ deploy front-ends ใหม่ บน smart contract (Mainnet) ได้ภายใน 10 นาทีเท่านั้น
- ไม่ขึ้นอยู่กับ Chain เดียว : BOS เข้าได้กับทุก Chain เป็นตัวเลือกในอุดมคติที่ช่วยให้ Dev ทำงานแบบ multi-chain ได้
เพิ่มเติมอีกนิด เสาหลักแห่ง BOS มีทั้งหมด 3 อย่าง ได้แก่
- Components : เครื่องมือ อุปกรณ์ต่างๆ ที่ให้ Dev เลือกหยิบใช้ ผสมนั้นนิด ผสมนี้หน่อย และบู้ม ! กลายเป็น App !
- Blockchains : ใช้ Components ได้ทุก Chain ตอนนี้รับรอง EVM chains, และ NEAR และเก็บไว้บน NEAR ในแบบ HTML/CSS/JS
- Gateways : ประตูสู่โลก Web 3 ที่รวมทุกอย่างจากทุก Chain มาให้ User ในที่เดียว
Calimero X BOS
การร่วมมือกันช่วยให้การพัฒนา front-end ของทั้ง 2 เสร็จเร็วขึ้น ซึ่ง Calimero ที่เป็น private blockchain ทำให้มั่นใจว่าข้อมูลจะถูกเก็บไว้อย่างปลอดภัย User สามารถเพลิดเพลินไปกับ function ขั้นสูง ที่จะพาไปสู่ Web3 ที่ดีขึ้น
เบื้องต้น ก่อนเริ่ม Development
ก่อนอื่น ขอแนะนำให้คุณปฏิบัติตามด้านล่างนี้
- ทำตามคำแนะนำที่นี่ here เพื่อให้ localhost:3000 ของคุณพร้อมสำหรับขั้นต่อไป
- สร้าง Account ที่ testnet.mynearwallet.com
- โหลดและติดตั้ง BOS Component Loader (bos-loader)
เมื่อเรียบร้อยแล้ว มาเริ่มกันเถอะ !
1. สร้าง folder หลักให้ชื่อ “tutorial”
mkdir tutorial
2. ใน “tutorial” folder, สร้างอีก folder ชื่อ “src.”
cd tutorial
mkdir src
3. ใน “src” folder, สร้างไฟล์ component , เช่น, Main.jsx.
cd src
touch Main.jsx
ตรวจสอบ Component ของคุณ
- เปิดไฟล์ Main.jsx และเพิ่ม “Hello” ใส่ใน Main.jsx component:
return Hello!
2. Run คำสั่ง BOS Loader
bos-loader --path src
เช่น
bos-loader KillSwitch.testnet --path src
4. เปิดหน้า http://localhost:3000/flags และตั้ง BOS loader URL เป็น http://127.0.0.1:3030
5. เปิดหน้า http://localhost:3000/<youraccount.near>/widget/<componentname> (case-sensitive) เพื่อเข้าถึง component ของคุณ
เช่น
http://localhost:3000/fakela.testnet/widget/Main
หรืออีกทาง คือตั้งค่า loader URL ใน https://test.near.org/flags และเปิดหน้า https://test.near.org/<youraccount.testnet>/widget/<component name> เพื่อเยี่ยมดู component ของคุณ
สร้าง Chat Application ดาวเด่นของเรา !
เมื่อทำตามขั้นตอน และ component ของคุณ พร้อมแล้ว ก็มาเริ่มกันเลย
ในหน้า code editor เริ่มด้วยการกำหนด contract ID กันก่อน
const contract = "chat-simple.ws-protocol-63";
จากนั้นเติม CSS styling ปรับแต่งหน้าตาของ Chat interface ซึ่งจะมีทั้ง message boxes, buttons, text, และอื่นๆ
const Separator = styled.div`
height: 1px;
padding: 1px;
width: 3rem;
background-color: #111;
`;
const Message = styled.div`
margin-bottom: 1rem;
background-color: #5c5470;
width: 100%;
padding: 2px;
`;
const MessageData = styled.div`
display: flex;
column-gap: 1rem;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
`;
const MainContainer = styled.div`
background-color: #352f44;
padding: 1rem;
width: 100%;
`;
const SenderText = styled.div`
color: #faf0e6;
font-size: 1rem;
line-height: 1.25rem;
font-weight: 700;
`;
const TimeAgo = styled.div`
color: #b9b4c7;
font-size: 0.75rem;
line-height: 1rem;
margin-top: 2px;
`;
const MessageText = styled.div`
color: #fff;
margin-top: 1rem;
margin-bottom: 1rem;
`;
const Title = styled.div`
color: #fff;
font-size: 1.25rem;
line-height: 1.5rem;
font-weight: 700;
`;
const IconSend = styled.i`
margin-top: 0.3rem;
margin-left: 1rem;
font-size: 1.25rem;
cursor: pointer;
color: #797978;
:hover {
color: #fff;
}
`;
const LoginText = styled.div`
color: #fff;
`;
const ButtonJoin = styled.div`
width: 100px;
padding: 4px;
background-color: #b9b4c7;
color: #111;
font-size: 1.25rem;
line-height: 1.5rem;
font-weight: 700;
border-radius: 8px;
`;
คราวนี้ มากำหนดตัวแปร สถานะ กันดีกว่า ซึ่งจะใช้เพื่อจัดการข้อมูล รวมถึงข้อมูลการใช้ต่างๆ
State.init({
bootstraping: true,
loggedIn: false,
channelList: [],
selectedChannel: 0,
usersList: [],
chatMessages: [],
message: "",
inputId: 0,
});
ต่อไป สร้าง functions เพื่อ fetch data จาก contract ซึ่ง function นี้จะดึงข้อมูลอย่าง รายชื่อสมาชิก, chat messages, และ channel lists ใน code ด้านล่าง
- updateMemberList ดึง members list
- updateChannelList ดึง channels/groups list
// DATA FETCHING FUNCTIONS - VIEW CALLS
const updateMemberList = () =>
Near.asyncCalimeroView(contract, "get_members").then((m) => {
State.update({ usersList: m });
return m;
});
const updateChannelList = () =>
Near.asyncCalimeroView(
contract,
"get_groups",
{ account: context.accountId },
undefined,
true
).then((c) => State.update({ channelList: c }));
state.channelList[0] &&
State.update({
chatMessages: Near.calimeroView(
contract,
"get_messages",
{
group: state.channelList[0],
},
undefined,
true
),
});
ถัดไป มาสร้าง helper functions ที่ช่วยจัดการ action อย่าง sending messages, joining the chat, และ verifying function access keys ใน code ด้านล่าง
- onChangeMessage จะ update สถานะของ App เมื่อ User ส่ง message เข้ามา
- sendMessage ใช้ส่งข้อความเข้าไปใน App.
// HELPER FUNCTIONS - CHANGE DATA OR CHANGE FUNCTIONS
const onChangeMessage = ({ target }) => {
State.update({ message: target.value });
};
const updateInputId = (id) => {
State.update({ inputId: id });
};
const sendMessage = () => {
if (!state.message) {
return;
}
let params = {};
params = { group: state.channelList[0] };
params.message = state.message;
params.timestamp = Date.now();
State.update({ message: "" });
updateInputId(Math.random().toString(36));
Near.fakCalimeroCall(contract, "send_message", params);
};
เรายังต้องกำหนด key function ในการเข้า join the chat, check membership status, และ verify function access keys ใน code ด้านล่าง
- joinCurb เรียกใช้เมื่อมี user ต้องการเข้าร่วม chat group.
- isMember ใช้เพื่อตรวจดูว่า user เป็นสมาชิกของ chat group, โดยดู account ID และ list of members ซึ่ง code ตรวจสอบเมื่อ application อยู่ในสถานะ “bootstrapping” เมื่อนั้นก็จะเรียกหา verifyKey function.
- verifyKey ตรวจสอบยืนยัน user’s authentication key.
หลังจากการยืนยันตัวตน functions ก็จะเรียกคำสั่ง updateMemberList และ updateChannelList เพื่อดึงข้อมูล member และ channel
// CALIMERO FUNCTION ACCESSKEYS FUNCTIONS
const joinCurb = () => {
Near.requestCalimeroFak(contract);
};
const isMember = (accountId, members) => {
return (members || state.usersList)
.map((user) => user.id)
.includes(accountId);
};
const verifyKey = () => {
Near.hasValidCalimeroFak(contract).then((result) => {
State.update({ bootstraping: false, loggedIn: result });
if (result) {
updateMemberList().then((members) => {
if (!isMember(context.accountId, members)) {
Near.fakCalimeroCall(contract, "join");
}
});
updateChannelList();
}
});
};
if (state.bootstraping) {
verifyKey();
}
updateMemberList();
updateChannelList();
สุดท้ายแล้ว ! เพิ่ม function เพื่อจัดรูปแบบ timestamp ของ chat messages ให้เข้าใจง่ายใน Code ด้านล่างเลย
const formatTimeAgo = (seconds) => {
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const weeks = Math.floor(days / 7);
const months = Math.floor(weeks / 4);
if (months > 0) {
return `${months} month${months > 1 ? "s" : ""} ago`;
} else if (weeks > 0) {
return `${weeks} week${weeks > 1 ? "s" : ""} ago`;
} else if (days > 0) {
return `${days} day${days > 1 ? "s" : ""} ago`;
} else if (hours > 0) {
return `${hours} hour${hours > 1 ? "s" : ""} ago`;
} else if (minutes > 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""} ago`;
} else {
return `just now`;
}
};
อีกนิดเดียว ! มา Rendering Front-End กัน!
สร้าง user interface สำหรับ app chat กัน โดย Code ด้านล่างจะ render chat interface, messages, input field, membership status, และอื่นๆ
return (
{context.accountId ? (
<>
{state.bootstraping ? (
Loading...
) : (
<>
{state.loggedIn && isMember(context.accountId) ? (
Calimero Chat - NEAR APAC
{!state.chatMessages ||
(state.chatMessages.length === 0 && (
No messages yet
))}
{(state.chatMessages || []).map((message, id) => (
{message.sender}
{formatTimeAgo(
(Date.now() - message.timestamp) / 1000
)}
{message.text}
))}
{
if (e.key == "Enter") {
sendMessage();
}
}}
placeholder={"send a message"}
key={state.inputId}
value={state.message}
autoFocus
/>
sendMessage()}
>
) : (
Join Chat
)}
)}
) : (
Please login to continue
)}
);
สำเร็จเรียบร้อย Chat App โดยใช้ BOS และ Calimero!!
อ๊ะ ! ขั้นตอนสำคัญ อย่าลืมทดสอบ Chat App ก่อนไป
กลับไปที่ http://localhost:3000/<youraccount.near>/widget/<componentname> เพื่อโหลดและทดสอบเจ้า app นี้
เราหวังเป็นอย่างยิ่งว่า guide นี้จะมีประโยชน์ให้ผู้อ่านทุกท่าน ในการสร้าง App Chat โดยใช้ BOS และ Calimero
หากมีข้อสงสัย โปรดอย่าลังเลที่จะติดต่อทีม Calimero !
Happy coding !!
ที่มา
https://www.calimero.network/blog/decentralized-chatapp-calimero-and-bos