Java Integration
Complete Java examples for Lunar Stream API integration using Spring Boot.
Dependencies (Maven)
xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>API Client
java
// LunarStreamClient.java
package com.example.lunarstream;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.hc.client5.http.classic.methods.*;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class LunarStreamClient {
private final String baseUrl;
private final String apiKey;
private final String projectId;
private final ObjectMapper objectMapper;
private final CloseableHttpClient httpClient;
public LunarStreamClient(String apiKey, String projectId) {
this.baseUrl = System.getenv().getOrDefault(
"LUNAR_STREAM_API_URL",
"https://api.lunarstream.kozow.com/api/v1"
);
this.apiKey = apiKey;
this.projectId = projectId;
this.objectMapper = new ObjectMapper();
this.httpClient = HttpClients.createDefault();
}
public JsonNode getMediaServers() throws IOException {
String url = baseUrl + "/media-servers/available?projectId=" + projectId;
HttpGet request = new HttpGet(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
return executeRequest(request);
}
public JsonNode createLivestream(String name, String mediaServerId) throws IOException {
String url = baseUrl + "/livestream";
HttpPost request = new HttpPost(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
Map<String, String> body = new HashMap<>();
body.put("name", name);
body.put("projectId", projectId);
body.put("mediaServerId", mediaServerId);
request.setEntity(new StringEntity(
objectMapper.writeValueAsString(body),
ContentType.APPLICATION_JSON
));
return executeRequest(request);
}
public JsonNode getLivestream(String id) throws IOException {
String url = baseUrl + "/livestream/" + id + "?projectId=" + projectId;
HttpGet request = new HttpGet(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
return executeRequest(request);
}
public JsonNode listLivestreams(int page, int limit) throws IOException {
String url = String.format("%s/livestream?projectId=%s&page=%d&limit=%d",
baseUrl, projectId, page, limit);
HttpGet request = new HttpGet(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
return executeRequest(request);
}
public JsonNode deleteLivestream(String id) throws IOException {
String url = baseUrl + "/livestream/" + id + "?projectId=" + projectId;
HttpDelete request = new HttpDelete(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
return executeRequest(request);
}
public JsonNode generatePushToken(String streamKey, int expiresIn) throws IOException {
String url = baseUrl + "/livestream/generate-push-token";
HttpPost request = new HttpPost(url);
request.setHeader("ls-api-key", apiKey);
request.setHeader("Content-Type", "application/json");
Map<String, Object> body = new HashMap<>();
body.put("projectId", projectId);
body.put("streamKey", streamKey);
body.put("expiresIn", expiresIn);
request.setEntity(new StringEntity(
objectMapper.writeValueAsString(body),
ContentType.APPLICATION_JSON
));
return executeRequest(request);
}
public JsonNode getStreamInfo(String streamKey) throws IOException {
String url = baseUrl + "/livestreams/stream-info/" + streamKey;
HttpGet request = new HttpGet(url);
request.setHeader("Content-Type", "application/json");
return executeRequest(request);
}
private JsonNode executeRequest(HttpUriRequestBase request) throws IOException {
return httpClient.execute(request, response -> {
String json = EntityUtils.toString(response.getEntity());
return objectMapper.readTree(json);
});
}
public void close() throws IOException {
httpClient.close();
}
}DTOs
java
// CreateStreamRequest.java
package com.example.lunarstream.dto;
import lombok.Data;
@Data
public class CreateStreamRequest {
private String name;
}
// StreamResponse.java
package com.example.lunarstream.dto;
import lombok.Builder;
import lombok.Data;
import java.util.List;
@Data
@Builder
public class StreamResponse {
private String id;
private String name;
private String status;
private String rtmpUrl;
private String hlsUrl;
private List<HlsSource> hlsSources;
@Data
@Builder
public static class HlsSource {
private String name;
private String url;
}
}Spring Boot Controller
java
// StreamController.java
package com.example.lunarstream.controller;
import com.example.lunarstream.LunarStreamClient;
import com.example.lunarstream.dto.CreateStreamRequest;
import com.example.lunarstream.dto.StreamResponse;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/streams")
public class StreamController {
@Value("${lunar.stream.api-key}")
private String apiKey;
@Value("${lunar.stream.project-id}")
private String projectId;
private LunarStreamClient client;
@PostConstruct
public void init() {
client = new LunarStreamClient(apiKey, projectId);
}
@PreDestroy
public void cleanup() throws IOException {
if (client != null) {
client.close();
}
}
@PostMapping
public ResponseEntity<?> createStream(@RequestBody CreateStreamRequest request) {
try {
JsonNode servers = client.getMediaServers();
JsonNode serverList = servers.get("data");
if (serverList == null || serverList.isEmpty()) {
return ResponseEntity.status(503)
.body(Map.of("error", "No media servers available"));
}
String mediaServerId = serverList.get(0).get("id").asText();
JsonNode result = client.createLivestream(request.getName(), mediaServerId);
JsonNode stream = result.get("data");
String rtmpUrl = stream.get("rmtpServer").asText() + "/" +
stream.get("streamKeyWithParams").asText();
String hlsUrl = null;
if (stream.has("hlsSources") && stream.get("hlsSources").size() > 0) {
hlsUrl = stream.get("hlsSources").get(0).get("url").asText();
}
return ResponseEntity.ok(StreamResponse.builder()
.id(stream.get("id").asText())
.name(stream.get("name").asText())
.status(stream.get("status").asText())
.rtmpUrl(rtmpUrl)
.hlsUrl(hlsUrl)
.build());
} catch (IOException e) {
return ResponseEntity.status(500)
.body(Map.of("error", "Failed to create stream: " + e.getMessage()));
}
}
@GetMapping("/{streamKey}")
public ResponseEntity<?> getStreamInfo(@PathVariable String streamKey) {
try {
JsonNode result = client.getStreamInfo(streamKey);
JsonNode stream = result.get("data");
List<StreamResponse.HlsSource> hlsSources = new ArrayList<>();
if (stream.has("hlsSources")) {
for (JsonNode source : stream.get("hlsSources")) {
hlsSources.add(StreamResponse.HlsSource.builder()
.name(source.get("name").asText())
.url(source.get("url").asText())
.build());
}
}
return ResponseEntity.ok(StreamResponse.builder()
.name(stream.get("name").asText())
.status(stream.get("status").asText())
.hlsSources(hlsSources)
.build());
} catch (IOException e) {
return ResponseEntity.status(404)
.body(Map.of("error", "Stream not found"));
}
}
@GetMapping
public ResponseEntity<?> listStreams(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int limit) {
try {
JsonNode result = client.listLivestreams(page, limit);
return ResponseEntity.ok(result);
} catch (IOException e) {
return ResponseEntity.status(500)
.body(Map.of("error", "Failed to list streams"));
}
}
@DeleteMapping("/{id}")
public ResponseEntity<?> deleteStream(@PathVariable String id) {
try {
client.deleteLivestream(id);
return ResponseEntity.ok(Map.of("success", true));
} catch (IOException e) {
return ResponseEntity.status(500)
.body(Map.of("error", "Failed to delete stream"));
}
}
@PostMapping("/{streamKey}/refresh-token")
public ResponseEntity<?> refreshToken(
@PathVariable String streamKey,
@RequestParam(defaultValue = "7200") int expiresIn) {
try {
JsonNode result = client.generatePushToken(streamKey, expiresIn);
JsonNode data = result.get("data");
return ResponseEntity.ok(Map.of(
"rtmpUrl", data.get("rtmpUrl").asText(),
"streamKeyWithToken", data.get("streamKeyWithToken").asText(),
"expiresAt", data.get("expiresAt").asText()
));
} catch (IOException e) {
return ResponseEntity.status(500)
.body(Map.of("error", "Failed to refresh token"));
}
}
}Application Properties
properties
# application.properties
lunar.stream.api-key=${LUNAR_STREAM_API_KEY}
lunar.stream.project-id=${LUNAR_STREAM_PROJECT_ID}
server.port=8080Usage
bash
# Run the application
mvn spring-boot:run
# Create a stream
curl -X POST http://localhost:8080/api/streams \
-H "Content-Type: application/json" \
-d '{"name": "My Stream"}'
# Get stream info
curl http://localhost:8080/api/streams/ee04affe2a669854052102fe762bd715
# List streams
curl "http://localhost:8080/api/streams?page=1&limit=10"
# Refresh token
curl -X POST "http://localhost:8080/api/streams/ee04affe2a669854052102fe762bd715/refresh-token?expiresIn=7200"