add lib folder

This commit is contained in:
2026-01-10 09:45:35 +00:00
parent 051c032f1d
commit ebe8389cb3
5 changed files with 546 additions and 0 deletions

124
lib/python/channels.py Normal file
View File

@@ -0,0 +1,124 @@
"""
Channel messaging bindings for Python
Provides functions to list channels, read messages, and send messages by channel name
"""
import requests
from typing import Optional
from dataclasses import dataclass
@dataclass
class Channel:
id: str
name: str
data: dict = None
@classmethod
def from_dict(cls, d: dict) -> "Channel":
return cls(id=d["id"], name=d["name"], data=d)
@dataclass
class Message:
id: str
content: str
channel_id: str
timestamp: Optional[str] = None
author: Optional[str] = None
data: dict = None
@classmethod
def from_dict(cls, d: dict) -> "Message":
return cls(
id=d["id"],
content=d["content"],
channel_id=d.get("channelId", d.get("channel_id", "")),
timestamp=d.get("timestamp"),
author=d.get("author"),
data=d,
)
class ChannelClient:
def __init__(self, url: str, token: str):
self.url = url.rstrip("/")
self.token = token
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
})
def _request(self, method: str, endpoint: str, **kwargs) -> dict:
response = self.session.request(method, f"{self.url}{endpoint}", **kwargs)
response.raise_for_status()
return response.json()
def list_channels(self) -> list[Channel]:
"""List all available channels"""
data = self._request("GET", "/channels")
return [Channel.from_dict(c) for c in data]
def find_channel_id_by_name(self, name: str) -> Optional[str]:
"""Find a channel ID by its name"""
channels = self.list_channels()
for channel in channels:
if channel.name == name:
return channel.id
return None
def read_channel(self, name: str) -> Optional[Channel]:
"""Read channel details by name"""
channels = self.list_channels()
for channel in channels:
if channel.name == name:
return channel
return None
def read_messages(self, channel_name: str, limit: Optional[int] = None) -> list[Message]:
"""Read messages from a channel by name"""
channel_id = self.find_channel_id_by_name(channel_name)
if not channel_id:
raise ValueError(f"Channel not found: {channel_name}")
params = {}
if limit:
params["limit"] = limit
data = self._request("GET", f"/channels/{channel_id}/messages", params=params)
return [Message.from_dict(m) for m in data]
def send_message(self, channel_name: str, content: str) -> Message:
"""Send a message to a channel by name"""
channel_id = self.find_channel_id_by_name(channel_name)
if not channel_id:
raise ValueError(f"Channel not found: {channel_name}")
data = self._request("POST", f"/channels/{channel_id}/messages", json={"content": content})
return Message.from_dict(data)
def create_client(url: str, token: str) -> ChannelClient:
"""Create a new channel client"""
return ChannelClient(url, token)
def list_channels(url: str, token: str) -> list[Channel]:
"""List all available channels"""
return create_client(url, token).list_channels()
def read_channel(url: str, token: str, name: str) -> Optional[Channel]:
"""Read channel details by name"""
return create_client(url, token).read_channel(name)
def read_messages(url: str, token: str, channel_name: str, limit: Optional[int] = None) -> list[Message]:
"""Read messages from a channel by name"""
return create_client(url, token).read_messages(channel_name, limit)
def send_message(url: str, token: str, channel_name: str, content: str) -> Message:
"""Send a message to a channel by name"""
return create_client(url, token).send_message(channel_name, content)

10
lib/rust/Cargo.toml Normal file
View File

@@ -0,0 +1,10 @@
[package]
name = "channels"
version = "0.1.0"
edition = "2021"
[dependencies]
reqwest = { version = "0.11", features = ["json", "blocking"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "1.0"

164
lib/rust/src/lib.rs Normal file
View File

@@ -0,0 +1,164 @@
//! Channel messaging bindings for Rust
//! Provides functions to list channels, read messages, and send messages by channel name
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION, CONTENT_TYPE};
use serde::{Deserialize, Serialize};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ChannelError {
#[error("HTTP request failed: {0}")]
RequestError(#[from] reqwest::Error),
#[error("Channel not found: {0}")]
ChannelNotFound(String),
#[error("Invalid header value")]
InvalidHeader,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel {
pub id: String,
pub name: String,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub id: String,
pub content: String,
#[serde(alias = "channelId", alias = "channel_id")]
pub channel_id: String,
pub timestamp: Option<String>,
pub author: Option<String>,
#[serde(flatten)]
pub extra: serde_json::Value,
}
#[derive(Debug, Serialize)]
struct SendMessagePayload {
content: String,
}
pub struct ChannelClient {
url: String,
client: Client,
}
impl ChannelClient {
pub fn new(url: &str, token: &str) -> Result<Self, ChannelError> {
let mut headers = HeaderMap::new();
headers.insert(
AUTHORIZATION,
HeaderValue::from_str(&format!("Bearer {}", token))
.map_err(|_| ChannelError::InvalidHeader)?,
);
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
let client = Client::builder().default_headers(headers).build()?;
Ok(Self {
url: url.trim_end_matches('/').to_string(),
client,
})
}
/// List all available channels
pub fn list_channels(&self) -> Result<Vec<Channel>, ChannelError> {
let response = self
.client
.get(format!("{}/channels", self.url))
.send()?
.error_for_status()?;
Ok(response.json()?)
}
/// Find a channel ID by its name
pub fn find_channel_id_by_name(&self, name: &str) -> Result<Option<String>, ChannelError> {
let channels = self.list_channels()?;
Ok(channels.into_iter().find(|c| c.name == name).map(|c| c.id))
}
/// Read channel details by name
pub fn read_channel(&self, name: &str) -> Result<Option<Channel>, ChannelError> {
let channels = self.list_channels()?;
Ok(channels.into_iter().find(|c| c.name == name))
}
/// Read messages from a channel by name
pub fn read_messages(
&self,
channel_name: &str,
limit: Option<u32>,
) -> Result<Vec<Message>, ChannelError> {
let channel_id = self
.find_channel_id_by_name(channel_name)?
.ok_or_else(|| ChannelError::ChannelNotFound(channel_name.to_string()))?;
let mut url = format!("{}/channels/{}/messages", self.url, channel_id);
if let Some(limit) = limit {
url.push_str(&format!("?limit={}", limit));
}
let response = self.client.get(&url).send()?.error_for_status()?;
Ok(response.json()?)
}
/// Send a message to a channel by name
pub fn send_message(&self, channel_name: &str, content: &str) -> Result<Message, ChannelError> {
let channel_id = self
.find_channel_id_by_name(channel_name)?
.ok_or_else(|| ChannelError::ChannelNotFound(channel_name.to_string()))?;
let payload = SendMessagePayload {
content: content.to_string(),
};
let response = self
.client
.post(format!("{}/channels/{}/messages", self.url, channel_id))
.json(&payload)
.send()?
.error_for_status()?;
Ok(response.json()?)
}
}
/// Create a new channel client
pub fn create_client(url: &str, token: &str) -> Result<ChannelClient, ChannelError> {
ChannelClient::new(url, token)
}
/// List all available channels
pub fn list_channels(url: &str, token: &str) -> Result<Vec<Channel>, ChannelError> {
create_client(url, token)?.list_channels()
}
/// Read channel details by name
pub fn read_channel(url: &str, token: &str, name: &str) -> Result<Option<Channel>, ChannelError> {
create_client(url, token)?.read_channel(name)
}
/// Read messages from a channel by name
pub fn read_messages(
url: &str,
token: &str,
channel_name: &str,
limit: Option<u32>,
) -> Result<Vec<Message>, ChannelError> {
create_client(url, token)?.read_messages(channel_name, limit)
}
/// Send a message to a channel by name
pub fn send_message(
url: &str,
token: &str,
channel_name: &str,
content: &str,
) -> Result<Message, ChannelError> {
create_client(url, token)?.send_message(channel_name, content)
}

124
lib/sh/channels.sh Normal file
View File

@@ -0,0 +1,124 @@
#!/bin/bash
# Channel messaging bindings for Shell
# Provides functions to list channels, read messages, and send messages by channel name
#
# Usage: source this file to use functions, or run directly with commands
# source channels.sh
# list_channels "https://api.example.com" "your-token"
# read_channel "https://api.example.com" "your-token" "channel-name"
# read_messages "https://api.example.com" "your-token" "channel-name" [limit]
# send_message "https://api.example.com" "your-token" "channel-name" "message content"
set -e
# List all available channels
# Args: $1 = url, $2 = token
list_channels() {
local url="${1%/}"
local token="$2"
curl -s -X GET "${url}/channels" \
-H "Authorization: Bearer ${token}" \
-H "Content-Type: application/json"
}
# Find channel ID by name
# Args: $1 = url, $2 = token, $3 = channel_name
# Returns: channel ID or empty string
find_channel_id_by_name() {
local url="$1"
local token="$2"
local channel_name="$3"
list_channels "$url" "$token" | jq -r --arg name "$channel_name" '.[] | select(.name == $name) | .id'
}
# Read channel details by name
# Args: $1 = url, $2 = token, $3 = channel_name
read_channel() {
local url="$1"
local token="$2"
local channel_name="$3"
list_channels "$url" "$token" | jq --arg name "$channel_name" '.[] | select(.name == $name)'
}
# Read messages from a channel by name
# Args: $1 = url, $2 = token, $3 = channel_name, $4 = limit (optional)
read_messages() {
local url="${1%/}"
local token="$2"
local channel_name="$3"
local limit="$4"
local channel_id
channel_id=$(find_channel_id_by_name "$url" "$token" "$channel_name")
if [ -z "$channel_id" ]; then
echo "Error: Channel not found: $channel_name" >&2
return 1
fi
local endpoint="${url}/channels/${channel_id}/messages"
if [ -n "$limit" ]; then
endpoint="${endpoint}?limit=${limit}"
fi
curl -s -X GET "$endpoint" \
-H "Authorization: Bearer ${token}" \
-H "Content-Type: application/json"
}
# Send a message to a channel by name
# Args: $1 = url, $2 = token, $3 = channel_name, $4 = content
send_message() {
local url="${1%/}"
local token="$2"
local channel_name="$3"
local content="$4"
local channel_id
channel_id=$(find_channel_id_by_name "$url" "$token" "$channel_name")
if [ -z "$channel_id" ]; then
echo "Error: Channel not found: $channel_name" >&2
return 1
fi
curl -s -X POST "${url}/channels/${channel_id}/messages" \
-H "Authorization: Bearer ${token}" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg content "$content" '{content: $content}')"
}
# CLI mode - if script is run directly (not sourced)
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
case "$1" in
list_channels)
shift
list_channels "$@"
;;
read_channel)
shift
read_channel "$@"
;;
read_messages)
shift
read_messages "$@"
;;
send_message)
shift
send_message "$@"
;;
*)
echo "Usage: $0 {list_channels|read_channel|read_messages|send_message} <url> <token> [args...]"
echo ""
echo "Commands:"
echo " list_channels <url> <token>"
echo " read_channel <url> <token> <channel_name>"
echo " read_messages <url> <token> <channel_name> [limit]"
echo " send_message <url> <token> <channel_name> <content>"
exit 1
;;
esac
fi

124
lib/typescript/channels.ts Normal file
View File

@@ -0,0 +1,124 @@
/**
* Channel messaging bindings for TypeScript
* Provides functions to list channels, read messages, and send messages by channel name
*/
export interface Channel {
id: string;
name: string;
[key: string]: unknown;
}
export interface Message {
id: string;
content: string;
channelId: string;
timestamp?: string;
author?: string;
[key: string]: unknown;
}
export interface ChannelClientConfig {
url: string;
token: string;
}
export class ChannelClient {
private url: string;
private token: string;
constructor(config: ChannelClientConfig) {
this.url = config.url.replace(/\/$/, '');
this.token = config.token;
}
private async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const response = await fetch(`${this.url}${endpoint}`, {
...options,
headers: {
'Authorization': `Bearer ${this.token}`,
'Content-Type': 'application/json',
...options.headers,
},
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status} ${response.statusText}`);
}
return response.json();
}
/**
* List all available channels
*/
async listChannels(): Promise<Channel[]> {
return this.request<Channel[]>('/channels');
}
/**
* Find a channel ID by its name
*/
async findChannelIdByName(name: string): Promise<string | null> {
const channels = await this.listChannels();
const channel = channels.find(c => c.name === name);
return channel?.id ?? null;
}
/**
* Read channel details by name
*/
async readChannel(name: string): Promise<Channel | null> {
const channels = await this.listChannels();
return channels.find(c => c.name === name) ?? null;
}
/**
* Read messages from a channel by name
*/
async readMessages(channelName: string, limit?: number): Promise<Message[]> {
const channelId = await this.findChannelIdByName(channelName);
if (!channelId) {
throw new Error(`Channel not found: ${channelName}`);
}
const query = limit ? `?limit=${limit}` : '';
return this.request<Message[]>(`/channels/${channelId}/messages${query}`);
}
/**
* Send a message to a channel by name
*/
async sendMessage(channelName: string, content: string): Promise<Message> {
const channelId = await this.findChannelIdByName(channelName);
if (!channelId) {
throw new Error(`Channel not found: ${channelName}`);
}
return this.request<Message>(`/channels/${channelId}/messages`, {
method: 'POST',
body: JSON.stringify({ content }),
});
}
}
// Convenience functions for standalone usage
export function createClient(url: string, token: string): ChannelClient {
return new ChannelClient({ url, token });
}
export async function listChannels(url: string, token: string): Promise<Channel[]> {
return createClient(url, token).listChannels();
}
export async function readChannel(url: string, token: string, name: string): Promise<Channel | null> {
return createClient(url, token).readChannel(name);
}
export async function readMessages(url: string, token: string, channelName: string, limit?: number): Promise<Message[]> {
return createClient(url, token).readMessages(channelName, limit);
}
export async function sendMessage(url: string, token: string, channelName: string, content: string): Promise<Message> {
return createClient(url, token).sendMessage(channelName, content);
}