SharpMining/SharpMining/StratumConnection.cs

189 lines
4.4 KiB
C#

using System;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using sharp.jsonrpc.net;
using Newtonsoft.Json.Linq;
using sharp.cryptonote;
namespace SharpMining
{
public class StratumConnection : JSONClient
{
delegate void threadsyncdelegate();
StratumListener listener;
Thread thread;
bool shouldExit;
public Guid UID { get; } = Guid.NewGuid();
public CryptoNoteAddress Wallet { get; set; }
public string WorkerID { get; set; }
public int FixedDiff { get; set; }
public string Agent { get; set; }
public MiningPool Pool { get; private set; }
public MiningJob CurrentJob { get; private set; }
public MiningJob LastJob { get; private set; }
public StratumConnection(StratumListener listener,Socket socket)
:base(socket)
{
this.listener = listener;
this.thread = new Thread(()=>run());
this.thread.Start();
}
public new void Close(){
Monitor.Enter(this);
if (shouldExit){
return;
}
shouldExit = true;
Monitor.Wait(this);
base.Close();
Monitor.Exit(this);
}
private void run(){
while (!ShouldExit){
try
{
JToken token = readJSON();
if (token["method"] != null)
{
methodCalled(token["method"].ToObject<string>(), token["id"].ToObject<UInt64>(), token["params"]);
}
} catch (IOException ioe){
Close();
} catch (Exception e){
Console.WriteLine("StratumConnection: [{0}] Exception: {1}",UID.ToString(),e.ToString());
}
}
if (Pool != null){
Pool.WorkManager.OnNewBlockAvailable -= WorkManager_OnNewBlockAvailable;
}
Monitor.Enter(this);
Monitor.PulseAll(this);
Monitor.Exit(this);
}
private bool ShouldExit { get { Monitor.Enter(this); bool se = this.shouldExit; Monitor.Exit(this); return se; } }
private new void writeJSON(JToken token){
Monitor.Enter(this);
base.writeJSON(token);
Monitor.Exit(this);
}
private void methodCalled(string method,UInt64 id,JToken args){
switch (method){
case "login":
rpcLogin(id,args);
break;
case "submit":
rpcSubmit(id, args);
break;
default:
writeJSONRPC(id, null, new JValue(String.Format("Method not implemented: {0}", method)));
break;
}
}
private string splitSuffix(char deli, ref string line)
{
return splitSuffix(deli, ref line, "");
}
private string splitSuffix(char deli, ref string line, string def){
string result = def;
int i = line.IndexOf(deli);
if (i >= 0){
result = line.Substring(i + 1);
line = line.Substring(0, i);
};
return result;
}
private void rpcLogin(UInt64 id,JToken args){
string username, passwd;
Agent = args["agent"].ToObject<string>();
username = args["login"].ToObject<string>();
passwd = args["pass"].ToObject<string>();
try {
FixedDiff = int.Parse(splitSuffix('@', ref username,"0"));
WorkerID = splitSuffix('.', ref username);
Wallet = new CryptoNoteAddress(username);
Pool = this.listener.getAssociatedPool(Wallet.CryptoNoteCoin);
if (Pool == null){
throw new Exception("No Pool for that coin available!");
}
MiningJob job = Pool.WorkManager.createJob();
assignJob(job, false);
Pool.WorkManager.OnNewBlockAvailable += WorkManager_OnNewBlockAvailable;
} catch (Exception e){
writeJSONRPC(id,null,new JValue(String.Format("An Exception occured ({0}: {1})",e.ToString(),e.Message)));
Close();
}
Console.WriteLine("Miner connected: [{3}] Wallet: {0} WorkerID: {1} FixedDiff: {2}", Wallet, WorkerID, FixedDiff, UID.ToString());
writeJSONRPC(id, new JObject(
new JProperty("id", "555"),
new JProperty("job", CurrentJob.toJSON(100))
), null);
}
private void rpcSubmit(UInt64 id,JToken args)
{
}
private bool assignJob(MiningJob job,bool transmit){
LastJob = CurrentJob;
CurrentJob = job;
if (transmit){
transmitCurrentJob();
}
return true;
}
public void transmitCurrentJob(){
writeJSON(new JObject(
new JProperty("jsonrpc", "2.0"),
new JProperty("method","job"),
new JProperty("params", CurrentJob.toJSON())
));
}
void WorkManager_OnNewBlockAvailable(WorkManager workmanager)
{
assignJob( this.Pool.WorkManager.createJob(), true );
}
public override string ToString()
{
return string.Format("[StratumConnection: [{4}] MinerWallet={0}, WorkerID={1}, FixedDiff={2}, Agent={3}]", Wallet, WorkerID, FixedDiff, Agent, UID.ToString());
}
}
}