Skip to content

Commit f39b987

Browse files
committed
Add code from prior work
1 parent d536626 commit f39b987

File tree

5 files changed

+287
-0
lines changed

5 files changed

+287
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,6 @@ dist
102102

103103
# TernJS port file
104104
.tern-port
105+
106+
# JetBrains IDEs
107+
.idea

README.md

+45
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,47 @@
11
# streamsource-client
22
Node API Client for Streamsource
3+
4+
## State of the project
5+
Highly volatile; breaking changes will be committed unapologetically
6+
7+
## Install
8+
```
9+
npm install streamsource-client
10+
```
11+
12+
## Prerequisite: Obtain a JWT from the Streamsource server
13+
Certain methods may require an authenticated and/or authorized JSON Web Token. To obtain this token, follow the steps documented in the [Streamsource README](https://github.com/streamwall/streamsource/#getting-started-with-authentication).
14+
15+
## Examples
16+
```javascript
17+
// Create an API client with your JWT
18+
const StreamsourceClient = require('streamsource-client')
19+
const streamsource = StreamsourceClient(YOUR_STREAMSOURCE_JWT)
20+
21+
// Search for streams
22+
const streamsData = await streamsource.getStreamsData({
23+
notPlatform: 'WSDOT',
24+
isExpired: false,
25+
isPinned: false,
26+
orderFields: ['createdAt'].join(','),
27+
orderDirections: ['DESC'].join(','),
28+
})
29+
30+
// Get info on a specific stream
31+
const streamData = await streamsource.getStreamData(12345)
32+
33+
// Add a new stream
34+
const streamOptions = {
35+
link: 'https://my-stream-url.com/',
36+
postedBy: 'My Bot Name',
37+
city: 'Seattle',
38+
region: 'WA',
39+
}
40+
await streamsource.createStream(streamOptions)
41+
42+
// Update a stream
43+
const updatedStream = await streamsource.updateStream({id: 12345, status: 'Live'})
44+
45+
// Expire a stream
46+
await streamsource.expireStream(12345)
47+
```

index.js

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
const fetch = require('node-fetch')
2+
3+
// Maps server keys to client keys; whitelists attributes
4+
const STREAM_DATA_MAP = {
5+
'id': 'id',
6+
'source': 'source',
7+
'platform': 'platform',
8+
'link': 'link',
9+
'status': 'status',
10+
'title': 'title',
11+
'isPinned': 'isPinned',
12+
'isExpired': 'isExpired',
13+
'checkedAt': 'checkedAt',
14+
'liveAt': 'liveAt',
15+
'embedLink': 'embedLink',
16+
'postedBy': 'postedBy',
17+
'city': 'city',
18+
'region': 'region',
19+
'createdAt': 'createdAt',
20+
'updatedAt': 'updatedAt',
21+
}
22+
23+
class Client {
24+
#DEFAULT_BASE_URI = "https://streams.streamwall.io"
25+
26+
constructor(jwt, base_uri) {
27+
if (!jwt) {
28+
throw new Error("You must pass an authentication token")
29+
}
30+
this.jwt = jwt
31+
this.base_uri = base_uri || this.#DEFAULT_BASE_URI
32+
}
33+
34+
async getStreamData(id) {
35+
if (!id) {
36+
throw new Error("getStreamData requires an id")
37+
}
38+
const endpoint = `${this.base_uri}/streams/${id}`
39+
return fetch(endpoint)
40+
.then(response => response.json())
41+
.then(response => {
42+
const data = response.data
43+
return data.map(streamData => {
44+
const mappedStream = {}
45+
for (let [sourceKey, destinationKey] of Object.entries(STREAM_DATA_MAP)) {
46+
stream[destinationKey] = streamData[sourceKey]
47+
}
48+
return mappedStream
49+
})
50+
})
51+
.catch(error => {
52+
console.error(`Could not fetch stream id ${id}: `, endpoint, error)
53+
return []
54+
})
55+
}
56+
57+
async getStreamsData(options) {
58+
const endpoint = `${this.base_uri}/streams`
59+
const url = new URL(endpoint)
60+
const params = new URLSearchParams(options)
61+
url.search = params
62+
63+
return fetch(url)
64+
.then(async response => {
65+
return response.json()
66+
})
67+
.then(async response => {
68+
const data = response.data
69+
const mappedStreams = []
70+
data.forEach(streamData => {
71+
const stream = {}
72+
for (let [sourceKey, destinationKey] of Object.entries(STREAM_DATA_MAP)) {
73+
stream[destinationKey] = streamData[sourceKey]
74+
}
75+
mappedStreams.push(stream)
76+
})
77+
return mappedStreams
78+
})
79+
.catch(error => {
80+
console.log("Could not fetch streams: ", endpoint, error)
81+
return []
82+
})
83+
}
84+
85+
async createStream({ link, city, region, source, postedBy, platform, status }) {
86+
if (!link) {
87+
throw new Error("createStream requires a link")
88+
}
89+
const endpoint = `${this.base_uri}/streams`
90+
const streamData = {
91+
link,
92+
city,
93+
region,
94+
source,
95+
postedBy,
96+
platform,
97+
status
98+
}
99+
const jsonStreamData = JSON.stringify(streamData)
100+
// console.log("Sending stream data: ", jsonStreamData)
101+
return fetch(
102+
endpoint, {
103+
method: 'POST',
104+
headers: {
105+
'Content-Type': 'application/json',
106+
'Authorization': `Bearer ${this.jwt}`
107+
},
108+
body: jsonStreamData
109+
})
110+
.then(response => {
111+
return {
112+
status: response.status,
113+
data: response.json()
114+
}
115+
})
116+
.then(({ status, data }) => {
117+
return {
118+
status,
119+
data
120+
}
121+
})
122+
.catch(error => {
123+
console.error("Error creating stream: ", endpoint, streamData, error)
124+
return
125+
})
126+
}
127+
128+
async updateStream({ id, source, platform, link, title, status, city, region, postedBy, checkedAt, liveAt, embedLink }) {
129+
if (!id) {
130+
throw new Error("updateStream requires an id")
131+
}
132+
const endpoint = `${this.base_uri}/streams/${id}`
133+
const streamData = {
134+
source,
135+
platform,
136+
link,
137+
title,
138+
status,
139+
city,
140+
region,
141+
postedBy,
142+
checkedAt,
143+
liveAt,
144+
embedLink
145+
}
146+
const jsonStreamData = JSON.stringify(streamData)
147+
// console.log(`Updating stream id ${id}`, jsonStreamData)
148+
return fetch(
149+
endpoint, {
150+
method: 'PATCH',
151+
headers: {
152+
'Content-Type': 'application/json',
153+
'Authorization': `Bearer ${this.jwt}`
154+
},
155+
body: jsonStreamData
156+
})
157+
.then(response => {
158+
return response.json()
159+
})
160+
.then(response => {
161+
const data = response.data
162+
// console.log(`Updated stream ${id}`, data)
163+
return data
164+
})
165+
.catch(error => {
166+
console.error(`Error updating stream ${id}`, endpoint, streamData, error)
167+
return false
168+
})
169+
}
170+
171+
async expireStream(streamId) {
172+
if (!streamId) {
173+
throw new Error("Must provide a stream id")
174+
}
175+
const endpoint = `${this.base_uri}/streams/${streamId}`
176+
return fetch(
177+
endpoint, {
178+
method: 'DELETE',
179+
headers: {
180+
'Content-Type': 'application/json',
181+
'Authorization': `Bearer ${this.jwt}`
182+
},
183+
})
184+
.then(response => {
185+
if (response.status != 204) {
186+
throw new Error("non-204 response", response)
187+
}
188+
return true
189+
})
190+
.catch(error => {
191+
console.error("Error expiring stream: ", endpoint, error)
192+
return false
193+
})
194+
}
195+
}
196+
197+
module.exports.StreamsourceClient = Client

package-lock.json

+13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "streamsource-client",
3+
"version": "1.0.0",
4+
"description": "Node.js client for the Streamsource API (https://github.com/streamwall/streamsource)",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/streamwall/streamsource-client.git"
12+
},
13+
"keywords": [
14+
"streamsource",
15+
"api",
16+
"client",
17+
"stream",
18+
"source"
19+
],
20+
"author": "Ben Menesini",
21+
"license": "MIT",
22+
"bugs": {
23+
"url": "https://github.com/streamwall/streamsource-client/issues"
24+
},
25+
"homepage": "https://github.com/streamwall/streamsource-client#readme",
26+
"dependencies": {
27+
"node-fetch": "^2.6.1"
28+
}
29+
}

0 commit comments

Comments
 (0)