commit 8725f3e0221e6290aa51d791a0b71ac9e08ea30c Author: Juni Date: Wed Dec 11 13:13:07 2024 -0600 First commit diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..25b6cb9 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +TRACKER_BSKY_HANDLE= +TRACKER_BSKY_PASSWORD= +DEBUG_LOG_ACTIVE=true +DEBUG_LOG_LEVEL=info + +JETSTREAM_URL='ws://jetstream:6008/subscribe' + +SESSION_DATA_PATH='/sessionData' + +USER_DID= \ No newline at end of file diff --git a/.github/workflows/buildandpublishtoghcr.yml b/.github/workflows/buildandpublishtoghcr.yml new file mode 100644 index 0000000..b874538 --- /dev/null +++ b/.github/workflows/buildandpublishtoghcr.yml @@ -0,0 +1,68 @@ +# +name: Create and publish the bot container + +# Configures this workflow to run every time a change is pushed to the branch called `release`. +on: + push: + branches: ['main'] + +# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. +jobs: + build-and-push-image: + runs-on: ubuntu-latest + # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. + permissions: + contents: read + packages: write + # + steps: + - name: Checkout repository + uses: actions/checkout@v4 + # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. + - name: Log in to the Container registry + uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GHCR_PAT }} + # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v5 + with: + platforms: linux/amd64, linux/arm64 + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. + # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. + # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. +# - name: Build and push Docker image +# uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 +# with: +# context: . +# push: true +# tags: ${{ steps.meta.outputs.tags }} +# labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..345320f --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.env +.idea +node_modules +sessionData +data \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3f07e35 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM oven/bun:latest as base +WORKDIR /usr/src/app + +# install dependencies into temp directory +# this will cache them and speed up future builds +FROM base AS install +RUN mkdir -p /temp/dev +COPY package.json bun.lockb /temp/dev/ +RUN cd /temp/dev && bun install --frozen-lockfile + +# install with --production (exclude devDependencies) +RUN mkdir -p /temp/prod +COPY package.json bun.lockb /temp/prod/ +RUN cd /temp/prod && bun install --frozen-lockfile --production + +# copy node_modules from temp directory +# then copy all (non-ignored) project files into the image +FROM install AS prerelease +COPY --from=install /temp/dev/node_modules node_modules +COPY . . + +# [optional] tests & build +ENV NODE_ENV=production +RUN bun test +RUN bun run build + +# copy production dependencies and source code into final image +FROM base AS release +COPY --from=install /temp/prod/node_modules node_modules +COPY --from=prerelease /usr/src/app/build/index.ts . +COPY --from=prerelease /usr/src/app/package.json . + +# run the app +USER bun +ENTRYPOINT [ "bun", "run", "index.ts" ] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d145cba --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2024 Juni + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b871023 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# user-tracker + +Tracks and reports on a users actions diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..f755aa4 Binary files /dev/null and b/bun.lockb differ diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..dd1cb4e --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +version: "3.8" +services: + bskybot: + depends_on: + - jetstream + build: . + restart: unless-stopped + volumes: + - ./sessionData:/sessionData + env_file: + - .env + networks: + - bun + + + jetstream: + image: "ghcr.io/juni-b-queer/jetstream-new:personal-branch" + container_name: jetstream + restart: unless-stopped + environment: + - CURSOR_FILE=/data/cursor.json + ports: + - "6008:6008" + volumes: + - ./data:/data + networks: + - bun + +networks: + bun: + driver: bridge diff --git a/makefile b/makefile new file mode 100644 index 0000000..d9bcde1 --- /dev/null +++ b/makefile @@ -0,0 +1,23 @@ +.PHONY: * + +dev: + bun run src/index.ts + +build: + docker compose build + +up: + docker compose up -d + +down: + docker compose down + +logs: + docker compose logs -f + +install: + bun install + + +link: + bun link bsky-event-handlers \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..f760b04 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "user-tracker", + "description": "Tracks and reports on a users actions", + "version": "0.0.0", + "author": "Juni", + "module": "src/index.ts", + "type": "module", + "scripts": { + "build": "bun build --target=bun ./src/index.ts --outfile=./build/index.ts" + }, + "devDependencies": { + "bun-types": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "bsky-event-handlers": "2.1.0-beta.1", + "@atproto/api": "^0.13.19" + }, + "license": "MIT" +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..d8271f5 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,123 @@ +import { + BadBotHandler, + CreateSkeetHandler, + DebugLog, + GoodBotHandler, + HandlerAgent, + InputEqualsValidator, + JetstreamSubscription, + LogMessageAction, + ReplyingToBotValidator, + MessageHandler, + IntervalSubscription, + IntervalSubscriptionHandlers, + AbstractHandler, + IsSpecifiedTimeValidator, + CreateSkeetAction, + ActionTakenByUserValidator, + LogInputTextAction, + JetstreamEventCommit, + JetstreamSubject, + JetstreamRecord, TestValidator +} from 'bsky-event-handlers'; + +const testAgent = new HandlerAgent( + 'test-bot', + Bun.env.TRACKER_BSKY_HANDLE, + Bun.env.TRACKER_BSKY_PASSWORD +); + + +/** + * Jetstream Subscription setup + */ +let jetstreamSubscription: JetstreamSubscription; + + +let handlers = { + post: { + c: [ + new MessageHandler( + // @ts-ignore + [ActionTakenByUserValidator.make(Bun.env.USER_DID)], + [ + CreateSkeetAction.make("Aaron posted:", undefined, (handler: HandlerAgent, commit: JetstreamEventCommit): JetstreamSubject =>{ + return { + cid: MessageHandler.getCidFromMessage(handler, commit), + uri: MessageHandler.getUriFromMessage(handler, commit) + } + }), + LogInputTextAction.make("Post") + ], + testAgent + ), + GoodBotHandler.make(testAgent) + ] + }, + like: { + c: [ + new MessageHandler( + // @ts-ignore + [ActionTakenByUserValidator.make(Bun.env.USER_DID)], + [ + CreateSkeetAction.make("Aaron liked:", undefined, (handler: HandlerAgent, commit: JetstreamEventCommit): JetstreamSubject =>{ + return commit.commit.record.subject as JetstreamSubject; + }), + LogInputTextAction.make("Like") + ], + testAgent + ) + ] + }, + repost: { + c: [ + new MessageHandler( + // @ts-ignore + [ActionTakenByUserValidator.make(Bun.env.USER_DID)], + [ + CreateSkeetAction.make("Aaron reposted:", undefined, (handler: HandlerAgent, commit: JetstreamEventCommit): JetstreamSubject =>{ + return commit.commit.record.subject as JetstreamSubject; + }), + LogInputTextAction.make("Repost") + ], + testAgent + ) + ] + }, + block: { + c: [ + new MessageHandler( + // @ts-ignore + [ + ActionTakenByUserValidator.make(Bun.env.USER_DID) + ], + [ + CreateSkeetAction.make((handler: HandlerAgent, event: JetstreamEventCommit): string => { + const blockedDid = event.commit.record.subject + return "Aaron blocked a user: " + blockedDid; + }, undefined, undefined), + LogInputTextAction.make("Block"), + ], + testAgent + ) + ] + } +} + + + +async function initialize() { + await testAgent.authenticate() + jetstreamSubscription = new JetstreamSubscription( + handlers, + Bun.env.JETSTREAM_URL + ); + +} + +initialize().then(() =>{ + jetstreamSubscription.createSubscription() + DebugLog.info("INIT", 'Initialized!') +}); + +