We have a brand new, exciting guide page offering an introduction to matrix-js-sdk. This guide will live with the documentation at https://matrix.org/docs/guides/usage-of-the-matrix-js-sdk, but you can find the text below.
Matrix allows open real-time communications over the Internet using HTTP and JSON. This makes developing clients to connect to Matrix servers really easy! Because it's open, and uses simple syntax for messages, you can connect Matrix to anything that communicates over a standard HTTP interface - later projects in this series will explore ideas such as building bots, performing machine learning on message content, and connecting IoT devices such as Philips Hue lights.
This article will explore the Matrix Client-Server API, making use of the matrix-js-sdk. Later articles may discuss making the underlying calls. Specifically we will cover:
MatrixInMemoryStore
Before we start, make sure you have Node.js and NPM installed: follow instructions at nodejs.org for your platform. Then create a new directory to work in:
mkdir my-first-matrix-client cd my-first-matrix-client
npm install matrix-js-sdk
We include the SDK in our source exactly as expected:importsdkfrom'matrix-js-sdk';
access token
to login:constclient=sdk.createClient({<span class="na" style="color: #008080;">baseUrl</span>
:"https://matrix.org",<span class="na" style="color: #008080;">accessToken</span>
:"....MDAxM2lkZW50aWZpZXIga2V5CjAwMTBjaWQgZ2Vu....",<span class="na" style="color: #008080;">userId</span>
:"@USERID:matrix.org"});// note that we use the full MXID for the userId value
createClient
)If you are logged into Riot, you can find an access token
for the logged-in user on the Settings page.
If the homeserver you're logging in to supports logging in with a password, you can also retrieve an access token
programmatically using the API. To do this, create a new client
with no authentication parameters, then call client.login()
with "m.login.password"
:
constclient=sdk.createClient("https://matrix.org");client.login("m.login.password",{"user":"USERID","password":"hunter2"}).then((response)=>{<span class="nx">console</span>
.log(response.access_token);});
console.log(client.getAccessToken());
client.startClient();
client.once('sync',function(state,prevState,res){<span class="nx">console</span>
.log(state);// state will be 'PREPARED' when the client is ready to use});
client.on("event",function(event){<span class="nx">console</span>
.log(event.getType());<span class="nx">console</span>
.log(event);})
client.on("Room.timeline",function(event,room,toStartOfTimeline){<span class="nx">console</span>
.log(event.event);});
sdk.createClient()
, an instance of the default store, MatrixInMemoryStore
was created and enabled. When we sync, or instruct otherwise our client to fetch data, the data is automatically added to the store.To access the store, we use accessor methods. For example, to get a list of rooms in which our user is joined:
// client.client.getRooms() returns an array of room objectsvarrooms=client.getRooms();rooms.forEach(room=>{<span class="nx">console</span>
.log(room.roomId);});
client.getRooms
)More usefully, we could get a list of members for each of these rooms:
varrooms=client.getRooms();rooms.forEach(room=>{<span class="kd" style="font-weight: bold;">var</span>
members=room.getJoinedMembers();<span class="nx">members</span>
.forEach(member=>{ <span class="nx">console</span>
.log(member.name);<span class="p">{'}'});</span>
});
varrooms=client.getRooms();rooms.forEach(room=>{<span class="nx">room</span>
.timeline.forEach(t=>{ <span class="nx">console</span>
.log(JSON.stringify(t.event.content));<span class="p">{'}'});</span>
});
#test:matrix.org
, and used it as an example:vartestRoomId="!jhpZBTbckszblMYjMK:matrix.org";varcontent={<span class="s2" style="color: #d14;">"body"</span>
:"Hello World",<span class="s2" style="color: #d14;">"msgtype"</span>
:"m.text"};client.sendEvent(testRoomId,"m.room.message",content,"").then((res)=>{// message sent successfully}).catch((err)=>{<span class="nx">console</span>
.log(err);}
client.sendEvent
)Knowing this, we can put together message listening and message sending, to build a bot which just echos back any message starting with a "!":
vartestRoomId="!jhpZBTbckszblMYjMK:matrix.org";client.on("Room.timeline",function(event,room,toStartOfTimeline){<span class="c1" style="color: #998; font-style: italic;">// we know we only want to respond to messages</span>
<span class="k" style="font-weight: bold;">if</span>
(event.getType()!=="m.room.message"){ <span class="k" style="font-weight: bold;">return</span>
;<span class="p">{'}'}</span>
<span class="c1" style="color: #998; font-style: italic;">// we are only interested in messages from the test room, which start with "!"</span>
<span class="k" style="font-weight: bold;">if</span>
(event.getRoomId()===testRoomId&&event.getContent().body[0]==='!'){ <span class="nx">sendNotice</span>
(event.event.content.body);<span class="p">{'}'}</span>
});functionsendNotice(body){<span class="kd" style="font-weight: bold;">var</span>
content={ <span class="s2" style="color: #d14;">"body"</span>
:body.substring(1), <span class="s2" style="color: #d14;">"msgtype"</span>
:"m.notice"<span class="p">{'}'};</span>
<span class="nx">client</span>
.sendEvent(testRoomId,"m.room.message",content,"",(err,res)=>{ <span class="nx">console</span>
.log(err);<span class="p">{'}'});</span>
}
msgtype
in the object above. In the previous example, we used "m.text" for this field, but now we're using "m.notice". Bots will often use "m.notice" to differentiate their messages. This allows the client to render notices differently, for example Riot, the most popular client, renders notices with a more pale text colour.