สร้าง App Chat แบบ Decentralize โดยใช้ Calimero and BOS : แบบจับมือทำ !

Eggoverse
5 min readDec 1, 2023

Guide นี้ จะพาสร้าง App Chat บน Blockchain แต่ก่อนที่จะเข้าเรื่อง เรามาทำความรู้จักกับ BOS กันก่อนดีกว่า

BOS นั้นคือ…?

ชื่อเต็มคือ Blockchain Operating System ระบบที่จะมาทำให้การเขียน/พัฒนา/deployโค้ด และการเข้าถึง Frontend กลายเป็นเรื่องง่าย โดย BOS เปรียบเสมือนประตูสู่โลก Web 3.0 ที่เน้นพัฒนาขับเคลื่อนด้วย Community

ทำไมถึง BOS …?

BOS เป็นทั้ง social network และมีพื้นที่และ tools ให้เลือกใช้ ซึ่งนอกจากที่จะเราสามารถหยิบใช้ได้แล้ว ยังมีอัพเดท App ใหม่ๆ ขึ้นมาด้วย นี่คือความพิเศษของ BOS ล่ะ

  1. การเข้าถึง : BOS ช่วยให้ User เรียกใช้ App บน blockchain จากที่ไหนก็ได้ รวมถึงระบบปลอดภัยรัดกุม และสะดวกรวดเร็ว
  2. ความปลอดภัย : components’ code ทั้งหมดอยู่บน Blockchain ซึ่งมั่นใจได้ว่าโปร่งใส ตรวจสอบได้ สามารถ run code ได้อย่างวางใจ
  3. การรวมพลัง : BOS ให้ Dev สามารถใช้ component ผสมผสาน และใช้ได้เรื่อยๆ ช่วยให้ทำงานได้ง่ายมากๆ Dev สามารถ deploy front-ends ใหม่ บน smart contract (Mainnet) ได้ภายใน 10 นาทีเท่านั้น
  4. ไม่ขึ้นอยู่กับ 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

ก่อนอื่น ขอแนะนำให้คุณปฏิบัติตามด้านล่างนี้

  1. ทำตามคำแนะนำที่นี่ here เพื่อให้ localhost:3000 ของคุณพร้อมสำหรับขั้นต่อไป
  2. สร้าง Account ที่ testnet.mynearwallet.com
  3. โหลดและติดตั้ง 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 ของคุณ

  1. เปิดไฟล์ 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 นี้

Code ฉบับเต็ม, ไปส่องได้ที่ Calimero GitHub repository

เราหวังเป็นอย่างยิ่งว่า guide นี้จะมีประโยชน์ให้ผู้อ่านทุกท่าน ในการสร้าง App Chat โดยใช้ BOS และ Calimero

หากมีข้อสงสัย โปรดอย่าลังเลที่จะติดต่อทีม Calimero !

Happy coding !!

ที่มา

https://www.calimero.network/blog/decentralized-chatapp-calimero-and-bos

--

--